Representative interview topic

Backend Interview: How Do You Migrate an API from 200 JSON to 204?

BackendMedium
Offer.cc Editorial TeamPublished Updated

Question

A write endpoint has long returned 200 with a JSON success object. The team wants to replace that response with 204 No Content. Design a migration that keeps existing clients working.

1. Prompt and Use Case

PATCH /profiles/42 has been in production for years. On success, it returns 200 OK with a fixed body: { "success": true }. A web app, mobile apps, third-party software development kits (SDKs), and automation jobs all call it. The body carries no business data, so the team wants to return 204 No Content instead.

Changing the status line is the easy part. An older client may call response.json() for every 2xx response, a gateway may extract a field from the body, and a dashboard may count only 200 as success. The migration must let old and new clients coexist and provide a fast server-side rollback before a compatibility problem spreads.

2. What the Interviewer Is Testing

  • Whether you treat a status change as a response-contract migration rather than a one-line server edit.
  • Whether you inventory browsers, mobile apps, SDKs, proxies, monitors, and retry middleware as real consumers.
  • Whether you can run 200 and 204 together through versioning or Prefer negotiation.
  • Whether you define rollout metrics, stop conditions, and a server-side rollback that does not require client downgrades.
  • Whether you know that a 204 response ends after its header section and cannot carry content or trailers.

3. Questions to Answer Before Migration

  1. Which clients always parse JSON, and which only inspect response.ok or the 2xx class?
  2. Is the success object truly unread, including log collectors, gateway scripts, and generated SDK return types?
  3. Can clients retry automatically, turning a successful write followed by a parse error into a duplicate request?
  4. Can every client be upgraded, or must both contracts remain available for a long period?
  5. Which headers, such as ETag, rate-limit fields, and trace identifiers, must remain?

4. A 30-Second Answer Framework

I would first build a consumer inventory and use contract tests to find every dependency on the 200 JSON body. During migration, 200 remains the default. Compatible clients opt into the minimal response through a new API version or Prefer: return=minimal; when the server honors it, it returns 204 and reports Preference-Applied. I would roll out from internal traffic to known low-risk client versions, monitoring parse failures, duplicate writes, retries, and per-client success. Rollback is a server switch back to 200 because the JSON serialization path remains intact until the migration is closed.

5. A Staged Migration Plan

Step 1: Build a Client Capability Inventory

For each caller, record its owner, version, HTTP library, success check, response parser, and retry policy. Search for unconditional response.json(), exact status === 200 comparisons, generated SDK return types, and gateway reads of body.success. Unknown or unversioned callers remain on 200. No evidence of compatibility means no 204 rollout.

Step 2: Make Clients Accept Both Success Contracts

Ship client support first. A compatible client accepts the agreed 2xx responses, checks for 204 or an empty body before parsing, and separates request success from JSON decoding. Contract tests feed it both 200 + JSON and 204 + empty body. Reversing this order risks turning a successful write into a client-visible parse failure and then a duplicate retry.

Step 3: Choose How the Two Contracts Coexist

For a deliberate breaking change, a new API version can always return 204 while the old version keeps 200. If the route and operation remain the same, RFC 7240 preference negotiation is another option: compatible clients send Prefer: return=minimal; the server may honor it with 204 and Preference-Applied: return=minimal. Callers that need the representation send Prefer: return=representation or keep the default 200 behavior. If the response is cacheable, declare Vary: Prefer correctly.

Step 4: Roll Out by Client, Not Random Request

Enable the behavior in test environments and internal callers first, then expand only to client versions known to be compatible. Keep each client or account in a stable cohort so it does not alternate between 200 and 204. Observe a complete business cycle at each stage before expanding; a short period of clean HTTP metrics is not enough.

Step 5: Observe the Failures the Protocol Change Can Cause

On the server, break down 200, 204, 5xx, and retry counts by client version. On clients, record empty-body parse failures, error UI shown after a successful request, and duplicate submissions. Compare completed writes with request retries, especially for non-idempotent operations. Alerts must identify the client version and rollout cohort; aggregate 2xx rates hide compatibility failures.

Step 6: Preserve Instant Rollback and Close the Migration

Keep the original JSON serialization path behind the server switch throughout the migration. If a stop condition fires, restore 200 globally; dual-compatible clients keep working without a downgrade. Remove the old path only after every supported client is above the minimum compatible version, old traffic is absent for an agreed observation window, and SDK, proxy, and contract suites still pass.

6. High-Quality Sample Answer

I would treat this as a response-contract migration. First I would inventory every consumer and find code that always parses JSON, checks exactly for 200, or reads body.success. I would ship clients that accept both 200 JSON and 204 with no body before changing server behavior. The server keeps 200 as the default; compatible clients select 204 through an API version or Prefer: return=minimal, confirmed by Preference-Applied. Rollout proceeds by client version, with parse failures, retries, and duplicate writes as primary signals. The 200 serialization path stays available until all supported clients have migrated, so rollback is a server-side switch rather than a client release.

7. Common Mistakes

  • Change 200 directly to 204 → old clients fail while parsing an empty body → ship dual-compatible clients before enabling 204.
  • Watch only HTTP error rates → 204 is still a successful response, so parse failures do not appear as server 5xx → add client parsing, retry, and duplicate-write metrics.
  • Randomize rollout per request → one client receives an unstable contract → cohort by client version or another stable identity.
  • Accept Prefer without reporting the result → the client cannot tell whether the preference was honored → return Preference-Applied and define the default behavior.
  • Delete JSON serialization immediately → rollback requires a code release → retain the old path until the migration window closes.
  • Ignore automatic retry behavior → a parse error disguises a successful write as failure → verify idempotency keys, retry middleware, and duplicate-submission metrics.

8. Follow-up Questions and Responses

Follow-up 1: Why not switch every client at once?

The server can prove that the write succeeded, but it cannot prove that every deployed client handles a 204 body correctly. One old version that always parses JSON turns protocol success into a user-visible failure. Client compatibility first, followed by version-scoped rollout, keeps the failure boundary observable.

Follow-up 2: When should you choose versioning versus Prefer?

A new version fits a durable contract break and is easy to reason about, but it adds version-lifecycle work. Prefer fits an operation where both a returned representation and a minimal response are valid. Because a server may ignore a preference, the client needs a documented default and should inspect Preference-Applied. Both are more reliable than guessing from User-Agent strings.

Follow-up 3: What information can a 204 response retain?

It can retain headers such as ETag, trace identifiers, and rate-limit fields. It cannot carry message content or trailers. A client should therefore treat “no JSON” and “no metadata” as separate questions.

Follow-up 4: When is it safe to delete the 200 compatibility path?

All supported clients must have shipped dual-response handling, telemetry must show no old-version traffic, and SDK, proxy, automation, and rollback tests must pass. An app-store release alone is not enough because users can remain on older versions for a long time.

Public sources

Related questions