Prompt and context
An online API must move its resource path permanently from /v1/orders to /v2/orders. Callers include browser forms, mobile clients, third-party SDKs, and asynchronous workers; requests may be POSTs with large JSON bodies and an idempotency key. Design the status codes, client behavior, observability, and rollback path for the migration.
This question tests whether you can apply redirect semantics precisely and avoid duplicate side effects during an API move. RFC 9110 defines 308 Permanent Redirect; MDN explains that a client should not change the original method or request body when it resends the request at the new location. 301 is permanent, but historical clients have compatibility differences for non-GET requests and may change the method.
What the interviewer is testing
The interviewer wants you to separate permanent from temporary moves, then ask whether method and body preservation is required. A strong answer compares 301, 302, 307, and 308, explains why a side-effecting POST cannot rely on a client guessing how to retry, and includes idempotency keys, authentication, timeouts, and rollback.
They also expect you to consider the trust boundary of Location, cross-origin credentials, cache propagation, SDK redirect limits, and clients that do not support 308. Reciting “308 is 301 plus POST preservation” without a migration test plan is incomplete.
Clarifications to ask first
Permanence and scope
Confirm that the new URL is stable and whether the move covers one resource, an API prefix, or a different origin. If the target may still change, use 307 to express a temporary move instead of prematurely teaching clients and intermediaries permanent cache semantics.
Client capability and side effects
List browsers, mobile versions, SDKs, queue consumers, and partners. Ask whether POST creates an order, charges money, or emits a message, and whether callers send an idempotency key. Without evidence that replay is safe, a redirect is not an unconditional retry instruction.
Credentials, caches, and rollback
Confirm authentication scope, CORS, proxies, and CDN behavior for both hosts. Ask whether the old endpoint can keep serving and whether rollback means removing the redirect, switching routing, or restoring the old handler.
A 30-second answer
“I would first confirm whether the move is permanent and inventory every client. For a permanent move that must preserve a POST method and body, I would use 308; a temporary move uses 307. A 301 is not a strict contract for preserving non-GET semantics across historical clients. I would initially proxy the old endpoint to the new handler, reuse one idempotency key for every side effect, and restrict the Location host and credential forwarding. During a canary I would track 3xx follow rate, duplicate creations, 4xx/5xx, body size, and SDK version. If signals regress, I would stop sending 308 and keep the old endpoint capable of serving.”
Step-by-step deep dive
Step 1: Choose the status code precisely
308 means a permanent move and preserves the request method and body; 307 is temporary and also preserves them. 301 is permanent, but historical clients do not all preserve methods such as POST, so it is not a strict POST-migration contract. 302 should not carry that guarantee either.
Step 2: Treat replay as the primary constraint
Because 308 can cause a client to submit the full body again, both endpoints must recognize the same business command by the same idempotency key. Before executing a side effect, the server validates the key against a request digest; the same key with different parameters becomes a conflict instead of a second order. A client still follows its retry budget after a timeout and must not follow 308 forever.
Step 3: Release in phases and observe
Make the new address work directly before routing the old address through an observable proxy or 308 response. Canary by SDK version, source origin, and method. Record redirect-chain length, follow failures, duplicate side effects, target latency, authentication failures, and body size. For clients that do not support 308, keep a short-lived server-side proxy rather than silently switching to 301 and assuming equivalent behavior.
Step 4: Handle security, caching, and rollback
Location may point only to an allow-listed target. Re-evaluate cookies, Authorization, and CORS before a cross-origin hop so credentials do not reach an untrusted host. Make the CDN and client cache window explicit, starting short during validation and extending it gradually. On rollback, stop issuing new redirects and let the old endpoint accept the same idempotency keys; results already written at the new endpoint cannot be “undone” by simply switching routes back.
A high-quality sample answer
I would treat this as a protocol and migration question, not a number-picking exercise. For a permanent move where POST method and body must be preserved, I choose 308; for temporary traffic shifting, I choose 307. 301 is appropriate for many page URL moves, but it does not give the strict method-preservation guarantee I need for a non-GET API.
Before rollout, both URLs support the same authentication, request validation, and idempotency-key contract. The old endpoint first proxies to the new handler with complete logs, and the same key plus request digest can produce only one side effect. I then canary 308 by client version, restrict the target host, recheck cross-origin credentials, and verify CDN, SDK, and queue-consumer behavior.
I monitor redirect follow rate, chain length, duplicate creations, target errors, authentication failures, and body size. If an old client does not understand 308, I keep the old endpoint proxy rather than silently downgrading to 301. During an incident I stop 308, preserve the old endpoint and idempotency records, restore routing, and reconcile completed business results by request ID.
Common mistakes
- Return 301 for every move → Historical clients may change POST to another method or drop the body → Use 308 for a permanent API move that requires preservation, then verify clients.
- Execute the side effect again after seeing 308 → Redirects, timeouts, and client retries can multiply a create request → Use an idempotency key, request digest, and bounded retry budget.
- Treat 307 as permanent → A temporary state can become long-lived in caches or SDK configuration, making rollback harder → Use 307 for temporary shifting and decide on 308 only after stabilization.
- Ignore cross-origin Location risk → Cookies or Authorization may reach an untrusted target → Validate an allow-list, credential policy, and CORS together.
- Watch only the 3xx count → Old SDK follow failures and duplicate writes remain invisible → Join follow rate, errors, and side-effect outcomes by client version.
Follow-up questions
Follow-up 1: Why not return 200 from the old URL and mention the new URL in the body?
That does not let generic clients, caches, or SDKs migrate automatically, and it does not express that the resource moved permanently. A server-side proxy can remain during the transition, but the migration contract still needs an explicit status and Location while recording whether callers actually switched.
Follow-up 2: Can 308 forward Authorization unchanged to a new host?
Not by default. First establish that both hosts share a trusted boundary; otherwise have the client obtain or explicitly send credentials for the target host. The server must reject user-controlled Location values to avoid open redirects and credential leakage.
Follow-up 3: What if an old client does not support 308 at all?
Keep a server-side proxy for the old endpoint or return a compatibility response based on known client capability until the old version exits. The proxy must reuse the request idempotency key and have a retirement date; you cannot claim every client will treat 308 like 301 without evidence.
Follow-up 4: Is rollback just changing 308 back to 200?
Also reconcile orders, events, and audit records already written by the new endpoint. Stop new redirects and restore the old entry point, then make both paths read the same source of truth so writes do not fork or duplicate. Verify completed side effects by request ID and idempotency key after routing is restored.