beginner 2 min answer Multiple choice

A batch endpoint accepts up to 500 items. Two items fail validation and the rest are processed. Which response shape should it return?

batchpartial successerror designidempotencybeginner
Pick one
Show the full answer Hide the answer

What is being tested

Whether you design for the case that actually dominates batch endpoints: neither total success nor total failure. A single status code cannot describe 498 successes and 2 failures, and every shortcut that pretends otherwise moves work onto the client - usually work the client gets wrong.

The shape that works

207 (or 200, documented) with:
  results: [ { id: "client-ref-1", status: "ok", resource: {...} },
             { id: "client-ref-2", status: "failed", error: { type, detail } } ]
  summary: { succeeded: 498, failed: 2 }

Three properties make it usable, and all three are commonly missing:

  1. A stable per-item identifier, supplied by the client, so a failed item can be matched back to the caller's own record without relying on array position. Position-based matching breaks the moment the server reorders or filters.
  2. Machine-readable error types per item, not prose. RFC 9457 (2023) - the Problem Details format, which replaced RFC 7807 - gives a conventional structure for this.
  3. Retry-safety for the subset. The client must be able to resubmit only the failures, which means the endpoint has to be idempotent per item, keyed on the client's identifier. Without that, partial retry risks duplicating the 498.

Why the other options fail

  • "200 with a success body." The client's happy path treats 200 as done, so the two failures are discovered weeks later by reconciliation - or never. A partial success reported as a success is a data-loss mechanism, and it is the most common error-design mistake in batch APIs.
  • "400 for the whole batch." Honest and wasteful: the client resubmits 500 items to retry 2, and if the endpoint is not idempotent, 498 duplicates follow. It is also a poor fit for the common case where failures are per-item validation rather than a malformed request.
  • "500 so existing retry logic handles it." This asks a client to retry work that succeeded, and it lies about whose fault it is - a validation failure is the caller's input, not a server defect, and misreporting it corrupts every error-rate dashboard on both sides.

The decision rule

Choose atomicity deliberately and say which you chose. Either the batch is all-or-nothing - in which case one failed item means a 4xx and no side effects, and the contract must say so - or it is per-item, in which case per-item outcomes are mandatory. The failure mode to avoid is accidental partial atomicity, where some items are applied and the response does not say which.

When this is the wrong answer

For a batch of 2 or 3 items, per-item machinery is more contract than the problem needs - make it atomic and return a 4xx. And where items are genuinely interdependent, such as a double-entry accounting posting, partial success is not a shape to report but a state to prevent: that batch must be one transaction, and the right answer is to reject the whole thing.