Back to interview questions

100+ REST API Interview Questions and Answers

100+ REST API Interview Questions and Answers

Explore 120 REST API interview questions and answers on HTTP methods, status codes, caching, authentication, API design, testing, security, and reliability.

Explore 120 REST API interview questions and answers on HTTP methods, status codes, caching, authentication, API design, testing, security, and reliability.

By

Team Sherlock.sh

Add Sherlock as a preferred source on Google

REST API interviews test more than familiarity with HTTP verbs and status codes. Strong candidates can turn a business operation into a clear resource contract, explain what happens when a request fails or repeats, protect data across authorization boundaries, and use evidence to investigate performance. Recruiters should distinguish a candidate who can recite endpoint conventions from one who can design and maintain an API that clients can depend on.

This guide to 100+ REST API Interview Questions and Answers contains 120 questions across beginner, intermediate, and experienced levels. It covers REST constraints, HTTP semantics, representations, caching, conditional requests, authentication, API security, testing, evolution, and distributed-system reliability. It distinguishes REST as an architectural style from the broader category of HTTP APIs, and separates protocol requirements from application-specific design choices.

How can recruiters detect AI-assisted cheating, deepfakes, and impersonation during REST API interviews?

An API interview might ask a candidate to prevent duplicate order creation, explain a failed conditional update, or investigate a response that leaked across tenants. A polished answer is less useful if the candidate cannot independently reason about request semantics, authorization, concurrency, and failure recovery. Unauthorized real-time assistance can hide those gaps.

Sherlock AI helps recruiters detect potential AI-assisted cheating, deepfakes, candidate impersonation, and unauthorized real-time assistance during REST API interviews.

Pair interview-integrity checks with a small design or debugging scenario. Change a requirement, introduce an ambiguous timeout, or ask how the candidate would verify an authorization decision. Review suspicious signals in context rather than treating a signal alone as proof of misconduct.

REST API Interview Questions

Choose questions that reflect the role and the API consumers. A frontend developer, backend engineer, and platform architect need different depth. State the client type, business operation, data sensitivity, traffic pattern, consistency needs, and operational constraints before evaluating a design.

REST API Interview Questions for Beginners

Start with REST constraints, resources, HTTP methods and responses, representation formats, basic security, pagination, caching, and testing. These questions establish a precise vocabulary without treating every common API convention as a REST requirement.

  1. What is a REST API, and how is REST different from a protocol?

  2. What are the architectural constraints of REST?

  3. What is a resource, and how is it different from its representation?

  4. What does a uniform interface mean in REST?

  5. What does stateless communication mean for a REST API?

  6. How are client-server separation and layered systems useful?

  7. What is HATEOAS, and why is it more than returning arbitrary links?

  8. How does a REST-style API differ from SOAP, RPC, and GraphQL?

  9. What are the main parts of an HTTP request and response?

  10. How should resource URIs and collection paths be designed?

  11. When should an API use path parameters versus query parameters?

  12. What are GET and HEAD used for?

  13. What is POST used for, and must it always create a resource?

  14. What is PUT used for, and how does it differ from POST?

  15. What is PATCH, and how does it differ from PUT?

  16. What does DELETE mean, and does it guarantee physical erasure?

  17. What is the difference between safe and idempotent HTTP methods?

  18. What are OPTIONS and the Allow header used for?

  19. What do the five HTTP status-code classes mean?

  20. When would you return 200, 201, 202, or 204?

  21. How do 400, 404, 409, and 422 differ?

  22. What is the difference between 401 and 403?

  23. How do Content-Type and Accept differ?

  24. Does a REST API have to use JSON?

  25. How should an API represent missing values, null values, and empty collections?

  26. How do authentication and authorization differ?

  27. What does HTTPS protect, and what does it not protect?

  28. How do API keys and bearer access tokens differ?

  29. What is CORS, and is it an authentication mechanism?

  30. Why does a browser send a CORS preflight request?

  31. Why should an API validate inputs on the server?

  32. What should a useful API error response contain?

  33. What is pagination, and why should collection responses be bounded?

  34. How can filtering and sorting be exposed consistently?

  35. What is HTTP caching, and why does it matter for APIs?

  36. What is the difference between no-cache and no-store?

  37. What are ETags and conditional requests?

  38. What is API versioning, and why is compatibility more important than a version label?

  39. What are OpenAPI and Swagger, and how are they related?

  40. How would you test a simple REST API endpoint?

REST API Interview Questions for Intermediate

Explore implementation choices across concurrency, pagination, caching, retries, validation, access control, versioning, tests, and observability. Ask candidates to describe both the intended behavior and the failures their design must handle.

  1. How would you design a resource-creation response with 201 Created?

  2. How would you model a long-running operation with 202 Accepted?

  3. How do you choose between offset and cursor pagination?

  4. How can keyset pagination avoid skipped or repeated records?

  5. How should pagination links and opaque cursors be secured?

  6. How would you implement filtering without exposing arbitrary database queries?

  7. How should an API support content negotiation and Vary?

  8. How do Cache-Control, freshness, and validation work together?

  9. How do you prevent user-specific responses from leaking through shared caches?

  10. How does If-None-Match support efficient GET requests?

  11. How does If-Match prevent lost updates?

  12. When would you use 412 Precondition Failed versus 428 Precondition Required?

  13. How do JSON Patch and JSON Merge Patch differ?

  14. How would you make a multi-field PATCH operation atomic?

  15. How can an API make repeated POST requests safe with an idempotency key?

  16. How do you handle an idempotency key reused with a different request body?

  17. How should clients choose timeouts, retries, exponential backoff, and jitter?

  18. How do 429 and 503 differ, and how should Retry-After be handled?

  19. How would you format errors using Problem Details for HTTP APIs?

  20. How should validation errors identify fields without exposing internals?

  21. How do bearer-token validation and OAuth scopes work together?

  22. When should a browser application use the authorization-code flow with PKCE?

  23. Why does validating a JWT signature alone not authorize an API request?

  24. How do you prevent broken object-level authorization?

  25. How do you prevent mass assignment and broken property-level authorization?

  26. How do cookie authentication, CSRF protection, and CORS interact?

  27. How should file uploads be validated and constrained?

  28. How would you design a bulk operation with explicit failure semantics?

  29. How should a client handle 301, 302, 303, 307, and 308 redirects?

  30. What request and response information should an API log?

  31. How do correlation IDs and distributed tracing help API troubleshooting?

  32. How would you test an API contract against an OpenAPI description?

  33. How do unit, integration, contract, and end-to-end API tests differ?

  34. How should an API handle dates, time zones, money, and large identifiers?

  35. How can an API evolve without breaking older clients?

  36. How would you deprecate and retire an API version?

  37. When should you return an empty collection instead of 404?

  38. How can hypermedia guide a multi-step business workflow?

  39. How should webhook deliveries be authenticated and retried?

  40. How do you diagnose a slow API request across gateway, service, and database?

REST API Interview Questions for Experienced

Use these scenarios to assess architectural judgment and operational ownership. Strong responses connect requirements to trade-offs, failure boundaries, rollout plans, and verifiable outcomes rather than claiming a gateway or protocol alone solves the problem.

  1. How would you design an order API that survives duplicate requests and ambiguous timeouts?

  2. How would you coordinate API writes with event publication reliably?

  3. How do you preserve correctness when an API spans multiple services?

  4. How should an API expose eventual consistency and read-your-writes behavior?

  5. How would you design optimistic concurrency for a high-contention resource?

  6. How would you build a multi-tenant API without cross-tenant data leakage?

  7. How would you design rate limits and quotas that are fair across tenants?

  8. How do admission control, load shedding, and backpressure protect an API?

  9. How should retry budgets and circuit breakers work together?

  10. How would you design an asynchronous job API with cancellation and expiry?

  11. How would you design bulk exports without exhausting application memory?

  12. How would you select between polling, webhooks, server-sent events, and WebSockets?

  13. How would you design a secure webhook system for untrusted destinations?

  14. How can cache invalidation and conditional requests remain correct during updates?

  15. How would you investigate an authorization-related cache leak?

  16. How would you migrate a public API schema without synchronized client upgrades?

  17. How would you version a representation without multiplying incompatible endpoints?

  18. How would you assess whether hypermedia adds value to a public API?

  19. How would you design an API gateway without turning it into a business-logic bottleneck?

  20. When should a backend-for-frontend differ from a general-purpose API?

  21. How would you secure service-to-service API access?

  22. How would you manage access-token revocation and key rotation?

  23. How would you threat-model an API that accepts URLs and imports remote content?

  24. How would you prevent sensitive data exposure through errors, telemetry, and exports?

  25. How would you design an auditable deletion workflow with retention constraints?

  26. How would you evaluate HTTP/2 or HTTP/3 without changing API semantics?

  27. How can inconsistent HTTP parsing across intermediaries become a security problem?

  28. How would you define and measure API availability and latency objectives?

  29. How do you design API load tests that reveal realistic failure modes?

  30. How would you roll out a risky API change with canaries and rollback?

  31. How would you diagnose rising p99 latency while average latency stays stable?

  32. How do you design disaster recovery and failover for stateful API dependencies?

  33. How should an API handle cross-region consistency and duplicate suppression?

  34. How would you design signed requests and replay protection when bearer tokens are insufficient?

  35. How would you govern a large API portfolio without slowing every team?

  36. How would you compare REST, gRPC, and GraphQL for a specific product?

  37. How would you design API contracts for clients that are intermittently offline?

  38. How would you handle a breaking security fix that cannot wait for normal deprecation?

  39. How do you distinguish an HTTP API that works from one that satisfies REST constraints?

  40. How would you review an unfamiliar API design in a senior engineering interview?

REST API Interview Questions and Answers

These answers follow the question bank in the same order and begin with direct responses candidates can adapt in an interview. HTTP messages, JSON documents, commands, and code are illustrative. Examples omit irrelevant transport details where stated; adapt authentication, schemas, request framing, and operational controls to the actual service before use.

REST API Interview Questions and Answers for Beginners

The beginner answers connect core concepts to practical request and response behavior. They explain the distinctions that prevent common errors, such as confusing idempotency with identical responses or CORS with authorization.

1. What is a REST API, and how is REST different from a protocol?

A REST API exposes interactions with resources using the constraints of Representational State Transfer. REST is an architectural style: it describes how components should interact, rather than defining a particular message format or network transport. HTTP is a protocol with concrete methods, status codes, headers and message semantics. Most APIs described as REST APIs use HTTP, but the terms are not interchangeable.

For example, an order can be identified by /orders/42, with a representation retrieved using GET. The representation might be JSON, but JSON does not make the interface RESTful. A service that sends every operation to /execute using POST can be a useful HTTP API without satisfying REST's uniform-interface and hypermedia constraints. In an interview, I would distinguish strict REST from the common, looser meaning of a resource-oriented HTTP API.

2. What are the architectural constraints of REST?

REST has six architectural constraints: client-server separation, stateless communication, cacheability, a uniform interface, a layered system and optional code-on-demand. The first five define the core style; code-on-demand allows a server to extend client behavior by supplying executable code, but is not required.

Each constraint addresses a design concern. Separating clients from servers supports independent evolution. Stateless requests avoid dependence on remembered conversational context. Cache metadata enables controlled reuse. A uniform interface makes interactions understandable across resources. Layering permits intermediaries without requiring clients to understand the entire deployment.

These constraints are architectural, not a checklist of URL conventions. Plural nouns, JSON responses and CRUD endpoints can improve an API's usability, but none substitutes for the constraints. The trade-offs also matter: statelessness can increase repeated request metadata, while caching requires deliberate freshness and privacy decisions.

3. What is a resource, and how is it different from its representation?

A resource is the concept identified by a URI; a representation is the data describing that resource at a particular time and in a particular format. An order remains the same resource even when its status changes or when clients request different representations.

For example, /orders/42 might return this JSON representation:

JSON example

{"id":"42","status":"pending","total":{"amount":"29.00","currency":"USD"}}
{"id":"42","status":"pending","total":{"amount":"29.00","currency":"USD"}}
{"id":"42","status":"pending","total":{"amount":"29.00","currency":"USD"}}

Another representation could be an HTML page intended for a person. Neither format has to mirror the database row. The server can combine data, omit internal fields and calculate values while preserving the resource's public meaning. I would define identifiers and representation schemas separately, especially when exposing sensitive data. Updating a representation is governed by the method and API contract; receiving JSON does not grant permission to modify every property it contains.

4. What does a uniform interface mean in REST?

A uniform interface means clients interact through shared rules instead of learning unrelated operation semantics for every resource. In REST it includes resource identification, manipulation through representations, self-descriptive messages and hypermedia-driven application state.

In an HTTP API, this means respecting HTTP method and status semantics and using representation metadata consistently. A client should not need to discover that GET deletes an account on one endpoint but reads it on another. Content-Type tells it how to interpret a body, while meaningful link relations can identify available next steps.

Uniformity does not require identical schemas or identical business rules. Orders and invoices can differ substantially while sharing interaction conventions. It also does not mean that noun-based paths alone establish REST compliance. A collection of custom commands behind HTTP can still lack the uniform semantics and discoverable transitions required by the architectural style.

5. What does stateless communication mean for a REST API?

Stateless communication means each request contains the information needed to understand it without relying on server-held conversational context from earlier requests. The server can retain resource data, databases, authorization policies and caches; statelessness does not mean that nothing is stored.

For example, a request for an order can include a credential and the order identifier. Any suitable application instance can process it without first receiving a separate request that selects the current order for that client. This simplifies distribution and recovery when instances fail.

A server-side session that supplies hidden application context creates a different dependency. Merely using a JWT does not prove an API is stateless, and consulting stored user or token records does not automatically make it stateful. The important question is whether processing depends on remembered conversation state rather than the current request and resource state.

6. How are client-server separation and layered systems useful?

Client-server separation keeps presentation and client interaction concerns apart from server-side resource management. A layered system allows a component to interact with its immediate neighbor without needing to know every component behind it. Together, these constraints support independent deployment and intermediary services.

For example, a mobile application can call an API through a load balancer and gateway while the implementation moves between service instances. The client should not need to know which database stores the orders or which instance handles its request. A cache can also answer eligible requests without contacting the origin.

Layers are not free: each can add latency, configuration and failure modes. I would keep the external contract stable, propagate suitable diagnostic identifiers and ensure intermediaries preserve HTTP semantics. Authentication or caching at a gateway does not remove the origin's responsibility to enforce resource-level access controls.

7. What is HATEOAS, and why is it more than returning arbitrary links?

HATEOAS means Hypermedia as the Engine of Application State. The server's representations expose meaningful controls that let the client discover supported next interactions, rather than requiring every workflow transition to be hard-coded from external documentation.

For an unpaid order, a representation might offer a payment action; after payment, it might instead offer shipment tracking. A useful control communicates its relation and, through the representation's defined semantics, how to invoke it. A URL placed in an arbitrary links array is insufficient if the client cannot understand its purpose or interaction rules.

Hypermedia can reduce coupling to URI layouts and changing workflows, but clients still need knowledge of media types, link relations and business concepts. It does not eliminate documentation or authorization. The server must reject an unauthorized transition even if a client fabricates a request for a control it never received.

8. How does a REST-style API differ from SOAP, RPC, and GraphQL?

REST organizes interactions around resources and a uniform interface. RPC organizes them around calling named procedures. SOAP defines an XML-based messaging framework, while GraphQL provides a typed query language and execution model in which clients select fields. These are different design dimensions, not four competing wire formats.

For example, a REST-style design might retrieve /orders/42; an RPC interface might expose GetOrder; a GraphQL query could request an order and selected related fields. SOAP messages can carry structured operations using its envelope and processing rules.

I would compare requirements rather than claim one is always faster or simpler. REST-style HTTP APIs fit standard web intermediaries well when designed for them. GraphQL offers flexible selection but needs query-cost controls. RPC can provide explicit operation contracts. SOAP can suit established messaging ecosystems. Using HTTP or JSON alone does not resolve the architectural choice.

9. What are the main parts of an HTTP request and response?

An HTTP request identifies the method and target and carries headers plus optional content. A response carries a status code, headers and optional content. Headers describe matters such as authentication, representation format and cache behavior. HTTP versions differ in wire encoding, but these core semantics remain relevant.

This is an illustrative HTTP/1.1 request with no body:

HTTP request example

GET /orders/42 HTTP/1.1
Host: example.com
Accept: application/json

GET /orders/42 HTTP/1.1
Host: example.com
Accept: application/json

GET /orders/42 HTTP/1.1
Host: example.com
Accept: application/json

The method requests a representation; the target identifies the order; Host identifies the authority; Accept states a preferred response format. A successful response could use status 200 and Content-Type application/json. In HTTP/2 and HTTP/3, messages are not transmitted as these textual start lines. Bodies are also not universal: HEAD responses and status 204 responses have no content, so clients must not blindly parse every successful response as JSON.

10. How should resource URIs and collection paths be designed?

Resource URIs should be stable, understandable identifiers whose structure follows a consistent public contract. A common convention uses collection paths such as /orders and member paths such as /orders/42. HTTP methods then express the interaction, rather than adding verbs such as /getOrder for every operation.

I would use nesting when it communicates a real relationship, for example /orders/42/items, but avoid exposing every internal database relationship through deeply nested paths. Identifiers should remain opaque to clients unless their structure is explicitly part of the contract. Renaming a database table should not force clients to change URLs.

Plural nouns and lowercase paths are conventions, not REST requirements. Sensitive credentials should not appear in URIs, and knowing an identifier must never imply authorization. For complex workflows, modeling an operation as a resource can be clearer than forcing everything into simplistic CRUD semantics.

11. When should an API use path parameters versus query parameters?

Path parameters usually identify a particular resource or scoped collection, while query parameters commonly refine a retrieval through filtering, sorting, pagination or representation options. For example, /customers/17/orders?status=open&limit=20 identifies a customer's order collection and requests a bounded subset.

This is an API design convention, not an HTTP rule that query parameters cannot identify resources. The complete URI, including its query, participates in identifying the target. I would keep parameter names, supported values, encoding rules and defaults explicit, and reject unsupported values consistently.

Do not put passwords or bearer tokens into either location: URLs can appear in logs, histories and diagnostic systems. Query parameters also do not automatically make a request uncacheable. Cache behavior depends on HTTP rules and metadata, and caches must distinguish the relevant request targets and negotiated variants correctly.

12. What are GET and HEAD used for?

GET retrieves a representation of a target resource. HEAD requests the corresponding response metadata without response content. Both are safe and idempotent methods, so their intended semantics should not perform business mutations such as approving a payment or deleting a record.

HEAD can help a client inspect metadata such as content type, validators or size without transferring the representation. Servers generally send the headers they would send for GET, but may omit fields whose values are determined only while generating content. A Content-Length on HEAD, when supplied, describes the size that a corresponding GET would have sent, not a HEAD body.

I would not assume HEAD is computationally free or universally implemented efficiently. GET can also cause incidental effects such as logging. Those effects do not justify exposing a destructive action through a supposedly safe retrieval endpoint.

13. What is POST used for, and must it always create a resource?

POST asks the target resource to process the supplied representation according to that resource's semantics. Creating a subordinate resource is common, but not its only purpose. POST can also submit a form, initiate a job or perform a documented calculation.

For example, posting an order to /orders might create /orders/42 and return 201 with a Location header. Posting an export request to /exports might return 202 when processing has only been accepted, with a documented way to observe progress.

POST is not idempotent by definition: repeating the same request can create another order or another job. A particular API can offer duplicate suppression through a documented idempotency-key contract, but that is additional behavior. Clients should not blindly retry an ambiguous timeout. The response status and representation must explain whether the operation finished, created something or remains pending.

14. What is PUT used for, and how does it differ from POST?

PUT requests creation or replacement of the target resource's state with the state defined by the supplied representation. The client already knows the target URI. POST instead delegates processing to the target according to its own semantics, commonly including selection of a new resource's URI.

For example, PUT to /preferences/17 can replace a user's editable preference representation, while POST to /orders can ask the collection to create an order. A successful PUT that creates a resource uses 201; replacing an existing representation can use 200 or 204.

PUT is idempotent in its intended effect, but repeated responses need not have identical statuses or timestamps. The contract must explain writable fields, server-managed fields and omitted properties. Treating PUT as an undocumented partial update confuses clients; use a clearly defined PATCH format when partial modification is intended.

15. What is PATCH, and how does it differ from PUT?

PATCH applies a set of changes to a resource, whereas PUT requests replacement of its state as defined by the supplied representation. A PATCH body is a patch document, and its media type determines how the server interprets the changes.

For example, this JSON Patch document replaces one property without specifying the rest of the order:

JSON example

[{"op":"replace","path":"/deliveryNote","value":"Use side entrance"}]
[{"op":"replace","path":"/deliveryNote","value":"Use side entrance"}]
[{"op":"replace","path":"/deliveryNote","value":"Use side entrance"}]

It would be sent with Content-Type application/json-patch+json. Other formats, such as JSON Merge Patch, have different rules, particularly for nulls and arrays. PATCH is not inherently idempotent: setting a value can be repeatable, while appending an array item can duplicate it. The server must apply the requested patch atomically rather than expose a partly applied result. For concurrent edits, a conditional request with an appropriate validator can prevent overwriting intervening changes.

16. What does DELETE mean, and does it guarantee physical erasure?

DELETE requests removal of the association between a target resource and its current functionality. It does not guarantee that every underlying byte, backup or audit record is physically erased. An application might remove public access while retaining records under a documented retention policy.

For example, DELETE /orders/42 could make that order unavailable through the API after a successful operation. A 202 response means deletion was accepted but may not have happened yet; 204 can indicate completion without response content. The contract should describe asynchronous deletion and any remaining visibility.

DELETE is idempotent in its intended effect. A second request may return 404 even if the first returned 204; different statuses do not violate idempotency. I would distinguish ordinary API deletion from a verified data-erasure workflow, especially where replicas, exports or legal retention obligations are involved.

17. What is the difference between safe and idempotent HTTP methods?

Safe methods have read-only intended semantics; idempotent methods have the same intended server effect when an identical request is repeated as when it is made once. Safety concerns what the client asks to change. Idempotency concerns repeated effects, not identical responses.

Method

Safe

Idempotent by method semantics

GET, HEAD, OPTIONS

Yes

Yes

PUT, DELETE

No

Yes

POST, PATCH

No

No

A repeated DELETE can return 404 after an earlier success while still being idempotent. A GET may produce access logs without becoming a mutation operation. Conversely, putting a payment action behind GET violates safety even if it happens to return JSON. Method semantics inform retries, but clients must also consider authentication, request replayability and the application's actual contract before retrying failures.

18. What are OPTIONS and the Allow header used for?

OPTIONS asks about communication options available for the target resource or server. The Allow response header lists supported methods for a target. For example, Allow: GET, HEAD, PUT, DELETE, OPTIONS describes methods the server currently supports there; it is not a promise that every caller is authorized to use them.

A 405 Method Not Allowed response must include Allow, helping distinguish a recognized method that is unsupported for this target from other failures. OPTIONS responses can describe capabilities without executing a resource-changing operation.

Browser CORS preflights also use OPTIONS, but their access-control headers have a separate purpose. Access-Control-Allow-Methods is not interchangeable with Allow. I would implement both according to their respective semantics rather than assume that returning a generic OPTIONS success grants browser access or replaces authentication and authorization checks.

19. What do the five HTTP status-code classes mean?

HTTP status-code classes group responses by broad outcome. The exact code then provides the meaning a client needs for its next step.

Class

General meaning

Example

1xx

Interim information

100 Continue

2xx

Successful handling

201 Created

3xx

Redirection or related further action

304 Not Modified

4xx

Request cannot be fulfilled for a client-side reason

404 Not Found

5xx

Server failed to fulfill an apparently valid request

503 Service Unavailable

These classes are not a complete retry policy or a blame assignment. A 429 may be retryable later, while repeating a malformed 400 request is usually pointless. A 304 is used for cache validation rather than redirecting the browser to another page. I would combine the specific status, response metadata and documented operation semantics before deciding what to do.

20. When would you return 200, 201, 202, or 204?

Use 200 when the request succeeded and the response carries the appropriate result representation. Use 201 when processing created one or more resources, normally identifying the primary created resource with Location. Use 202 when processing has been accepted but is not complete. Use 204 when the request succeeded and there is no response content.

For example, retrieving an order can return 200, creating it can return 201, starting a background export can return 202, and updating a preference without returning a representation can return 204. These are choices based on what actually happened, not interchangeable success labels.

A 202 is not a guarantee of eventual success; provide a documented status resource or another observation mechanism. A 204 must not include a JSON body, including {}. Clients should inspect the status and content metadata before attempting to parse a result.

21. How do 400, 404, 409, and 422 differ?

400 Bad Request covers requests the server cannot or will not process because of a perceived client error, such as malformed JSON. 404 means the target resource is not found, or the server is unwilling to disclose its existence. 409 signals a conflict with the current resource state. 422 Unprocessable Content applies when the content type and syntax are understood but the contained instructions cannot be processed.

For example, an invalid JSON document fits 400; an unknown order fits 404; a transition conflicting with an already closed order can fit 409; a well-formed request with an invalid field combination can fit 422.

The boundary between 400 and 422 depends on the documented contract. Consistency and actionable error details matter more than inventing a unique code for every validation rule. Do not expose hidden resource existence through overly detailed error differences.

22. What is the difference between 401 and 403?

401 Unauthorized means the request lacks valid authentication credentials for the target resource. Despite its name, it is principally an authentication challenge, and the response must include an applicable WWW-Authenticate header. 403 Forbidden means the server understands the request but refuses to fulfill it.

A missing or expired access token commonly leads to 401. A valid user trying to access an administrative function commonly receives 403. However, 403 does not prove that authentication succeeded: refusal can have other policy reasons. Servers may also use 404 to avoid revealing the existence of a forbidden resource.

I would ensure clients do not endlessly refresh tokens after every 403. Authentication renewal helps only when the credential problem is actually repairable. Error messages should explain safe remediation while avoiding account, tenant or resource details that an unauthorized caller should not learn.

23. How do Content-Type and Accept differ?

Content-Type identifies the media type of the content actually sent in a message. Accept expresses which response media types a client is willing to receive. They describe different directions and can appear together on a request with a body.

For example, a client can submit JSON using Content-Type application/json while asking for a problem or success representation according to the endpoint's documented negotiation rules. A bodyless GET may use Accept without needing Content-Type. The server's response Content-Type identifies the representation it selected; it should not merely echo the request headers.

An unsupported request media type can produce 415 Unsupported Media Type. A server unwilling to supply an acceptable representation can return 406 Not Acceptable. I would document supported formats and validate actual payloads instead of trusting a media-type label as proof that content is well formed or safe.

24. Does a REST API have to use JSON?

No. REST does not prescribe JSON or any single representation format. An API can transfer JSON, XML, HTML, images or another suitable media type while following the same architectural constraints. JSON is popular because many clients can consume it easily, not because it defines REST.

For example, a report resource might provide JSON metadata and a separate PDF representation or download resource. A client can state preferences through Accept, and the server identifies the selected content with Content-Type. If request headers select different cacheable variants, the caching metadata must account for that selection.

I would choose formats based on consumers, interoperability, payload size and tooling. A response containing JSON is still only a representation: it says nothing by itself about statelessness, method correctness or hypermedia. Likewise, returning XML does not automatically make an API SOAP.

25. How should an API represent missing values, null values, and empty collections?

Missing properties, explicit nulls and empty collections should have distinct, documented meanings. An absent property may mean it was not requested, is unsupported or was omitted. Null is an explicit value whose business meaning must be defined. An empty array usually means the collection is known and currently contains no elements.

For example:

JSON example

{"middleName":null,"orders":[]}
{"middleName":null,"orders":[]}
{"middleName":null,"orders":[]}

This can mean the middle name is unknown and the represented order collection is empty. It does not necessarily mean the person has no middle name, unless that is the contract. For updates, omitted and null fields can behave differently; JSON Merge Patch uses null to request removal of a member. I would specify required properties and nullable values separately in the schema, keep collection shapes stable and avoid using empty strings as undocumented substitutes for missing data.

26. How do authentication and authorization differ?

Authentication establishes who or what is making a request. Authorization decides whether that identity may perform the requested action on the particular resource. A valid credential is evidence for authentication, not blanket permission to access every object.

For example, a token can identify a customer successfully while the server still rejects that customer's request for another customer's invoice. Authorization may depend on tenant membership, ownership, role, scope and the resource's current state. These checks belong on the server for each relevant operation, including list, export and nested-resource endpoints.

I would avoid relying on hidden UI buttons, unpredictable identifiers or a gateway's token check as the only access control. Property-level permissions matter too: someone allowed to edit a profile may not be allowed to set isAdmin. Tests should include valid identities attempting actions outside their allowed boundaries.

27. What does HTTPS protect, and what does it not protect?

HTTPS uses TLS to protect HTTP traffic in transit, providing confidentiality, integrity and server authentication when certificate validation is performed correctly. It helps prevent an observer on the network path from reading or altering credentials and payloads exchanged across that protected connection.

It does not fix broken authorization, malicious application logic, compromised clients or secrets written into application logs. It also does not automatically encrypt stored data. If TLS terminates at a gateway, protection for the connection from that gateway to the application must be considered separately.

For an API, I would require HTTPS, keep certificate verification enabled and avoid sending credentials in URLs. I would also assess what endpoints and intermediaries can see after decryption. Transport security is essential, but it is one layer alongside input validation, access controls, safe logging and protection of stored credentials.

28. How do API keys and bearer access tokens differ?

An API key commonly identifies a calling application, project or integration, while a bearer access token commonly represents a time-bounded authorization grant with associated permissions. The exact distinction depends on the provider: the label API key alone does not specify its security properties.

A bearer token can be used by anyone who possesses it, so theft can enable impersonation within its permitted scope. Tokens may be opaque or structured; JWT is a format, not a requirement for bearer authentication. API keys can also function as bearer secrets.

I would compare scope, expiry, rotation, revocation and whether the credential represents a user or an application. Send credentials using the documented header mechanism over HTTPS, never expose privileged keys in public browser code, and avoid logging secrets. Neither credential type removes the need for object-level authorization or abuse limits.

29. What is CORS, and is it an authentication mechanism?

CORS is a browser-enforced mechanism controlling whether cross-origin JavaScript can access certain HTTP responses. It is not authentication and does not determine whether a caller owns a resource. The server still needs normal credential validation and authorization.

For example, an API can allow a web application at a particular origin to read responses by returning appropriate CORS headers. A command-line client is not constrained by the browser's same-origin policy, so denying an origin is not a reliable way to block arbitrary API callers.

Some cross-origin requests can be sent without a preflight even if the browser later refuses to expose the response. Consequently, CORS is not a complete CSRF defense. I would configure an explicit trusted-origin policy where appropriate and treat credentials carefully: credentialed browser access cannot be enabled using a wildcard allowed origin.

30. Why does a browser send a CORS preflight request?

A browser sends a CORS preflight when a cross-origin request's method or headers require permission checking before the actual request. It uses OPTIONS to ask whether the origin, method and requested headers are permitted. A suitable cached preflight result can avoid repeating that check for a period.

For example, a cross-origin PATCH request commonly needs a preflight, as does a request using an Authorization header. A JSON Content-Type is not one of the CORS-safelisted content types. The server answers with the relevant access-control headers; an ordinary Allow header is not a substitute.

Not every cross-origin request is preflighted. If permission checking fails, the browser blocks the actual preflight-dependent request, but this browser behavior is not a security boundary for non-browser clients. The API must authenticate and authorize the real request independently and avoid treating an OPTIONS success as business-operation success.

31. Why should an API validate inputs on the server?

Server-side input validation is necessary because clients are untrusted and client-side checks are easy to bypass. The server must enforce the contract and business rules before data changes or expensive work occur, regardless of which application sent the request.

I would validate media type, syntax, schema, allowed fields, lengths, ranges and cross-field constraints. For an order, a positive quantity is a structural rule, while whether an item may be purchased by that customer is a business and authorization rule. Limits on body size, array length and requested page size also help prevent resource exhaustion.

Validation is not a replacement for parameterized database queries, safe output handling or authorization. Nor should the server bind every supplied property directly onto internal models. Reject or safely handle unexpected writable fields and return useful, non-sensitive errors without leaking stack traces or database implementation details.

32. What should a useful API error response contain?

A useful error response combines the correct HTTP status with a stable, machine-readable error identity and a safe explanation that helps the client recover. Where useful, it can identify invalid fields and provide a request or occurrence identifier for support. Clients should not have to parse an English sentence to classify the error.

Problem Details offers a standard representation. An illustrative JSON body is:

JSON example

{"type":"about:blank","title":"Bad Request","status":400,"detail":"The limit parameter must be an integer from 1 to 100."}
{"type":"about:blank","title":"Bad Request","status":400,"detail":"The limit parameter must be an integer from 1 to 100."}
{"type":"about:blank","title":"Bad Request","status":400,"detail":"The limit parameter must be an integer from 1 to 100."}

This would use Content-Type application/problem+json, with an actual HTTP status of 400. Domain-specific problem types can add stable semantics. I would exclude stack traces, SQL, tokens and private resource details. Error documentation should also say which failures are retryable; returning 200 with an embedded error undermines standard client and monitoring behavior.

33. What is pagination, and why should collection responses be bounded?

Pagination divides a collection into bounded responses so a client does not have to download every matching resource at once. Bounding results protects memory, database work, response latency and network usage, and makes large collections practical to consume.

A simple API might accept limit=20 and return an opaque next cursor or a next-page link. The server should enforce a maximum even if the client asks for more. An empty result can still return the normal collection shape rather than inventing a special response format.

Pagination needs a defined ordering and documented behavior as data changes. Offset pagination can shift when records are inserted or removed; cursor-based approaches can avoid some, but not all, consistency problems. I would not promise a snapshot unless the implementation provides one. Total counts can be expensive and should not be mandatory merely to display a next-page control.

34. How can filtering and sorting be exposed consistently?

Filtering and sorting should use a small, documented query vocabulary with consistent names, operators and defaults. For example, /orders?status=open&sort=-createdAt,id can request open orders ordered by newest creation time, then identifier, if that syntax is explicitly supported.

The server should allowlist filterable and sortable fields, validate values and reject unsupported expressions predictably. Define whether repeated parameters mean AND or OR, how nulls are handled and whether string comparisons are case-sensitive. A stable secondary sort key is important when the primary field contains duplicates, especially with pagination.

I would not expose raw SQL or internal column names as a public query language. Expensive filters and sorts need cost limits or suitable indexes, and authorization must apply before returning matches. A flexible query interface is not permission to scan or reveal another tenant's records.

35. What is HTTP caching, and why does it matter for APIs?

HTTP caching allows an eligible stored response to satisfy a later request, reducing latency, bandwidth and origin load. A response's cache directives and other metadata determine whether it can be stored and reused, for how long, and whether validation is required.

For example, a public product catalog can tolerate a short freshness lifetime, while a customer's account balance may need stricter privacy and freshness rules. When a stored response becomes stale, a validator such as an ETag can let the client check whether it changed without downloading the same representation again.

GET responses are not automatically safe to share simply because GET is safe. Authorization, response directives, cache keys and representation variants all matter. I would define caching deliberately and test it through actual intermediaries. Application caching inside a service is related but does not replace the HTTP caching contract visible to clients and proxies.

36. What is the difference between no-cache and no-store?

no-cache allows storage but requires successful validation before a stored response is reused to satisfy a request. no-store instructs caches not to store the request or response as applicable. The names are easy to misread: no-cache does not mean that nothing can be cached.

For example, a frequently changing representation can use no-cache with an ETag so clients validate and potentially avoid downloading unchanged content. A response containing highly sensitive information may instead need no-store. private addresses a different issue: it prevents storage by shared caches but can permit a private client cache.

These directives are not data-erasure or access-control mechanisms. No-store does not reliably remove every previously stored copy, and it cannot prevent a malicious recipient from saving information. I would combine cache policy with correct authorization, HTTPS and careful handling of sensitive data in clients, logs and intermediaries.

37. What are ETags and conditional requests?

An ETag is an opaque validator for a selected representation. Clients should compare and return it as supplied rather than infer meaning from its contents. Conditional requests use validators to make retrieval or modification depend on the current resource state.

For example, after receiving ETag "order-7", a client can issue:

HTTP request example

GET /orders/42 HTTP/1.1
Host: example.com
If-None-Match: "order-7"

GET /orders/42 HTTP/1.1
Host: example.com
If-None-Match: "order-7"

GET /orders/42 HTTP/1.1
Host: example.com
If-None-Match: "order-7"

If the representation still matches, the server can respond 304 without the representation content, allowing reuse of the stored copy. For updates, If-Match can require a current strong validator and prevent a stale client from overwriting newer data; a failed condition normally produces 412. Weak ETags, marked with W/, can support cache validation but do not satisfy strong If-Match comparison. ETags are not credentials and do not replace authorization.

38. What is API versioning, and why is compatibility more important than a version label?

API versioning identifies intentionally different contracts so clients can continue using a supported behavior while the API evolves. Versions may be expressed in paths, headers or media types, but the label alone does not make a change safe.

Compatibility depends on what existing clients observe: field meanings, validation rules, status codes, pagination, authentication requirements and timing can matter alongside schema shape. Removing a field is an obvious risk; adding an enum value can also break a client with exhaustive handling. Even an additive change needs evaluation against real consumer assumptions.

I would prefer compatible evolution where practical, document breaking changes and provide a migration and retirement policy when a new contract is necessary. Tests against representative older clients are more useful than assuming /v2 solves compatibility. Keep the API's business version distinct from the OpenAPI specification version used to describe it.

39. What are OpenAPI and Swagger, and how are they related?

OpenAPI is a standard for describing HTTP APIs in a machine-readable form. A description can specify paths, operations, parameters, request and response schemas, security schemes and examples. Swagger originally named the specification that became OpenAPI; today the name also refers to tools such as Swagger UI and Swagger Editor.

An OpenAPI description can drive interactive documentation, client generation and contract validation. For example, it can state that GET /orders/{id} accepts a path identifier and returns either an order representation or a documented error. This makes assumptions explicit for developers and tooling.

It does not implement the server, prove authorization is correct or establish that the API satisfies REST constraints. Generated documentation can also drift if it is not checked against behavior. I would keep the description under review and use tests to detect mismatches rather than treating a rendered Swagger page as proof of correctness.

40. How would you test a simple REST API endpoint?

I would test the endpoint against its documented contract, including the request, response and observable side effects. For GET /orders/42, that includes status, media type, schema and expected data, plus confirmation that the operation does not modify the order.

Useful negative cases include an unknown identifier, missing or expired credentials, access to another user's order, invalid parameters and unsupported methods. For mutation endpoints, I would also check validation, persistence, repeated-request behavior and concurrency where relevant. Cache headers and conditional responses deserve explicit cases when the endpoint supports them.

A manual request is only a starting point. Automated unit tests can exercise business rules, integration tests can verify storage and middleware, and contract tests can compare responses with OpenAPI. I would use isolated test data and avoid production side effects. A 200 status alone does not establish correctness, security or acceptable performance.

REST API Interview Questions and Answers for Intermediate

The intermediate answers show how to build predictable contracts and robust client behavior. Examples emphasize explicit assumptions, conditional writes, bounded work, authorization checks, and meaningful diagnostics.

41. How would you design a resource-creation response with 201 Created?

I would return 201 only after creation has succeeded, identify the primary new resource with Location, and normally include its representation. This lets the caller use server-assigned identifiers, normalized values, and defaults without immediately fetching the resource again.

Illustrative HTTP excerpt; message framing is omitted:

HTTP response example

HTTP/1.1 201 Created
Location: /orders/ord_71
Content-Type: application/json
ETag: "order-71-v1"

{"id":"ord_71","status":"pending","currency":"USD"}
HTTP/1.1 201 Created
Location: /orders/ord_71
Content-Type: application/json
ETag: "order-71-v1"

{"id":"ord_71","status":"pending","currency":"USD"}
HTTP/1.1 201 Created
Location: /orders/ord_71
Content-Type: application/json
ETag: "order-71-v1"

{"id":"ord_71","status":"pending","currency":"USD"}

For POST /orders, the location identifies the order rather than merely repeating the collection URL. I would document whether the body is the resource itself or an envelope and ensure generated URLs reflect the public API address, not an internal proxy hostname. Creation still requires authorization and transaction safety. If work has only been queued and creation is not complete, I would use an asynchronous-operation contract instead of claiming success with 201.

42. How would you model a long-running operation with 202 Accepted?

I would return 202 when the server has accepted work but has not completed it, and provide an operation resource the client can inspect. Acceptance is not a promise that the business operation will eventually succeed.

JSON example

{"operationId":"job_19","status":"queued","statusUrl":"/operations/job_19"}
{"operationId":"job_19","status":"queued","statusUrl":"/operations/job_19"}
{"operationId":"job_19","status":"queued","statusUrl":"/operations/job_19"}

The status resource would expose documented states such as queued, running, succeeded, failed, and canceled. A successful operation can link to its result; a failed one should expose a safe, structured error. I would document polling intervals, retention, cancellation behavior, and what happens when the operation record expires. Authorization must apply to status and result endpoints as well as submission. The server should durably record accepted work before acknowledging it. Repeated submissions need a separate deduplication strategy; 202 alone does not prevent duplicate jobs after a timeout.

43. How do you choose between offset and cursor pagination?

I would choose offset pagination for small or relatively stable datasets where jumping to a numbered page matters. I would prefer cursor pagination for large, frequently changing feeds where predictable traversal and efficient indexed access matter more than arbitrary page numbers.

Offset requests such as ?offset=100&limit=25 are easy to understand, but inserts or deletions before the offset can shift the next page. Deep offsets may also require the database to process many discarded rows. A cursor can encode the last ordering key and let the next request continue from that boundary.

Both designs need a maximum page size and a deterministic order with a unique tie-breaker. A cursor is not automatically a database snapshot: updates to ordering fields can still move records. I would separately document consistency guarantees and whether exact totals are available or expensive.

44. How can keyset pagination avoid skipped or repeated records?

Keyset pagination continues after the last seen sort key instead of counting how many rows to skip. I would use an indexed, deterministic ordering and include a unique tie-breaker so rows sharing a timestamp are not lost.

SQL example

SELECT id, created_at
FROM orders
WHERE tenant_id = :tenant_id
  AND (created_at, id) > (:last_time, :last_id)
ORDER BY created_at ASC, id ASC
LIMIT :

SELECT id, created_at
FROM orders
WHERE tenant_id = :tenant_id
  AND (created_at, id) > (:last_time, :last_id)
ORDER BY created_at ASC, id ASC
LIMIT :

SELECT id, created_at
FROM orders
WHERE tenant_id = :tenant_id
  AND (created_at, id) > (:last_time, :last_id)
ORDER BY created_at ASC, id ASC
LIMIT :

The cursor stores both boundary values. Deleting an earlier row does not shift that boundary, unlike offset pagination. New rows before the boundary will not suddenly displace already traversed rows. However, keyset pagination cannot guarantee a stable export if existing sort keys change or late-arriving records fall behind the cursor. For that requirement, I would add a snapshot or an explicit consistency mechanism. Nullable keys, descending order, and mixed sort directions require carefully matched predicates.

45. How should pagination links and opaque cursors be secured?

I would treat a cursor as untrusted client input, even when it is opaque. Base64 encoding hides neither its contents nor its meaning. A self-contained cursor should be integrity-protected, or it can reference server-side state using an unpredictable identifier.

The cursor should bind relevant pagination context, such as ordering, filters, and snapshot version, so clients cannot accidentally continue a different query. Sensitive context may require encryption rather than a signature alone. I would validate token size, format, expiry, and supported version and return a documented client error for invalid cursors.

Most importantly, every page request must independently enforce the caller's current permissions and tenant boundary. Possessing a cursor must not grant access. Pagination links should use trusted API origins and avoid embedding credentials. Clients following server-provided links should not forward authorization headers to arbitrary destinations.

46. How would you implement filtering without exposing arbitrary database queries?

I would expose a small, documented filtering language and translate it into parameterized queries. Clients should select approved business fields and operators, not supply SQL fragments, table names, or unrestricted database expressions.

For example, GET /orders?status=paid&createdAfter=2026-10-01T00:00:00Z can map to validated status and timestamp values. Sort fields also need an allowlist because parameter binding generally cannot safely substitute arbitrary SQL identifiers. Tenant and ownership predicates come from authenticated server context, not from an optional client filter.

I would bound result size, expression depth, list lengths, and execution cost. Invalid or unsupported filters should produce actionable errors rather than silently broadening the query. Tests should cover injection strings, invalid dates, combinations of filters, and attempts to cross tenant boundaries. Index design and query-plan checks then establish which supported combinations remain practical at production scale.

47. How should an API support content negotiation and Vary?

I would use request headers such as Accept to choose a supported response representation and return the actual media type in Content-Type. If the selection depends on a request header, caches need the corresponding Vary field to distinguish variants.

For example, a resource supporting JSON and CSV might return Vary: Accept. A cache must not serve a stored CSV representation to a caller requesting JSON simply because the URI matches. Unsupported preferences can result in 406 when the server declines to provide a fallback; the API should document that policy. Unsupported request-body media types are a separate issue, commonly reported with 415.

I would avoid varying on unnecessary headers because each variation fragments cache reuse. Representation-specific validators must also remain correct: a strong ETag for one byte representation cannot casually identify a different representation.

48. How do Cache-Control, freshness, and validation work together?

Freshness determines whether a stored response can be reused without contacting the origin; validation checks whether an existing response is still current. Cache-Control defines relevant policy, while validators such as ETags enable efficient revalidation.

For a product catalog, I might choose Cache-Control: public, max-age=60 and return an ETag. A cache can reuse a fresh response within the allowed lifetime. Once validation is required, it can send If-None-Match; a 304 allows reuse of the stored body with updated metadata.

The policy should follow product requirements, not a universal TTL. A rapidly changing stock count and a product description may need different treatment. no-cache permits storage but requires validation before reuse; no-store prohibits storage. Freshness is also affected by response age, so receiving a response does not necessarily start a brand-new full lifetime.

49. How do you prevent user-specific responses from leaking through shared caches?

I would make personalized caching an explicit design decision rather than assume the URL identifies the entire response. Two users requesting /me must never share a response merely because the method and path match.

For sensitive account data, Cache-Control: no-store is a straightforward policy. Where browser caching is acceptable but shared caching is not, private restricts storage to private caches. I would verify gateway and CDN behavior, including any configuration that overrides origin headers. Authorization-bearing requests have special shared-cache rules, but application teams should not rely on undocumented defaults or assume a session cookie automatically disables caching.

Tests should alternate identities against the same edge endpoint and check both bodies and metadata. Logout, permission changes, cache invalidation, and error responses also matter. Adding Vary: Cookie is not a substitute for a deliberate security policy and correct cache configuration.

50. How does If-None-Match support efficient GET requests?

A client stores a GET representation together with its ETag and later sends that tag in If-None-Match. If the selected representation still matches, the server can return 304 without retransmitting the body. Otherwise it returns the current representation, normally with 200 and a new validator.

HTTP request example

GET /products/p_9 HTTP/1.1
Host: api.example.com
If-None-Match: "product-p9-v4"
GET /products/p_9 HTTP/1.1
Host: api.example.com
If-None-Match: "product-p9-v4"
GET /products/p_9 HTTP/1.1
Host: api.example.com
If-None-Match: "product-p9-v4"

The client must retain a usable stored representation: a 304 is not an empty replacement document. Cache metadata from the response must be handled correctly, and variants must match the original request context. If-None-Match uses weak comparison, so it can support semantic equivalence for cache validation even when tags are weak. That differs from write preconditions requiring strong comparison. Authentication and authorization still apply; an unchanged resource does not justify skipping access checks.

51. How does If-Match prevent lost updates?

If-Match prevents a client from overwriting changes made after it read a resource. I would return a strong ETag on the read and require the client to send that value with an update.

Illustrative HTTP excerpt; message framing is omitted:

HTTP request example

PATCH /profiles/u_8 HTTP/1.1
Host: api.example.com
If-Match: "profile-u8-v12"
Content-Type: application/merge-patch+json

{"displayName":"Maya"}
PATCH /profiles/u_8 HTTP/1.1
Host: api.example.com
If-Match: "profile-u8-v12"
Content-Type: application/merge-patch+json

{"displayName":"Maya"}
PATCH /profiles/u_8 HTTP/1.1
Host: api.example.com
If-Match: "profile-u8-v12"
Content-Type: application/merge-patch+json

{"displayName":"Maya"}

The server must compare the current version and commit the update atomically. If another writer has already changed the resource, the stale precondition fails with 412 instead of silently losing that writer's update. The client can fetch the latest state and deliberately reconcile its change.

A separate read followed by an unconditional database write is insufficient because another update can occur between them. I would implement a conditional update or transaction and issue a new validator after success. Weak ETags cannot satisfy the strong comparison used by If-Match.

52. When would you use 412 Precondition Failed versus 428 Precondition Required?

I would return 428 when an operation requires a precondition but the client did not supply one. I would return 412 when the client supplied a precondition that evaluates to false.

For example, an API may require If-Match for editing an address. A PATCH without that header gets 428 with guidance to retrieve the current representation and validator. A PATCH containing an outdated ETag gets 412 because the resource changed after the client read it.

The distinction helps clients recover correctly: missing concurrency information is not the same as stale concurrency information. I would document the required conditional headers in the operation contract and ensure the error does not expose data the caller cannot access. A 428 response must not be cached. Clients should not automatically replace a stale validator and replay an edit without deciding whether the newer changes are compatible.

53. How do JSON Patch and JSON Merge Patch differ?

JSON Patch describes an ordered sequence of operations; JSON Merge Patch describes a desired partial object shape. Their media types and handling of arrays and null values differ.

JSON example

[{"op":"replace","path":"/name","value":"Maya"}]
[{"op":"replace","path":"/name","value":"Maya"}]
[{"op":"replace","path":"/name","value":"Maya"}]

That JSON Patch document uses application/json-patch+json. Operations include add, remove, replace, move, copy, and test, with JSON Pointer paths. It can target individual array elements, although positional indexes can become stale under concurrent edits.

A merge patch such as {"name":"Maya","nickname":null} uses application/merge-patch+json: it updates the name and removes the nickname member. Arrays are replaced as a whole rather than merged element by element. Null therefore cannot simply mean โ€œstore a literal null memberโ€ in that object patch. I would choose the format that matches client needs, explicitly document it, validate writable paths, and use conditional requests where concurrent updates are possible.

54. How would you make a multi-field PATCH operation atomic?

I would validate and apply the complete patch within one atomic state change. If any operation fails, none of the patch's changes should become visible. HTTP PATCH requires this all-or-nothing application of the patch document.

For a transfer between two account fields, I would first authenticate the caller, authorize every affected field, validate the patch structure, and check any version precondition. Then I would compute the proposed state, enforce cross-field invariants, and commit in a database transaction or equivalent atomic storage operation. A failure rolls the transaction back.

I would test a patch where the first operation is valid but a later operation fails, then verify the original state remains unchanged. External effects such as emails should not run midway through the patch. I would persist an outbox record in the same transaction as the state change, then dispatch after commit. This avoids a crash gap and does not pretend irreversible effects can be rolled back.

55. How can an API make repeated POST requests safe with an idempotency key?

I would define an application-level idempotency contract in which the client generates one key per logical operation and reuses that key only when retrying that operation. A header commonly named Idempotency-Key is not, by itself, a universal guarantee of deduplication.

The server atomically claims a key scoped to the relevant caller and operation, records a request fingerprint, and stores the outcome. A matching retry returns the recorded result rather than creating a second order or charge. Concurrent requests using the same key need coordinated handling, not independent โ€œcheck then insertโ€ logic.

I would document retention, in-progress behavior, which failures are retained, and what happens after expiry. The side effect and deduplication record must remain consistent across crashes. A key recorded only in process memory is inadequate across replicas or restarts. Clients must preserve the key when a timeout leaves the outcome unknown.

56. How do you handle an idempotency key reused with a different request body?

I would reject reuse of an idempotency key for a different logical request rather than execute the new payload or replay an unrelated result. The precise status code and error type belong in the API contract; a documented conflict response is one reasonable choice.

The server stores a fingerprint covering the operation, relevant parameters, and authenticated scope alongside the key. Fingerprinting needs a deliberate normalization policy: insignificant JSON object ordering should not accidentally change request identity if the contract treats it as equivalent. Conversely, meaningful changes such as amount, currency, or destination must not be ignored.

I would never reveal another tenant's prior response when a key collides. An in-progress matching request also needs defined handling, such as a retryable conflict. Tests should cover concurrent retries, changed bodies, changed query parameters, and expiry. This is application behavior, not something POST semantics automatically provide.

57. How should clients choose timeouts, retries, exponential backoff, and jitter?

I would set timeouts from the caller's overall latency budget, then retry only failures that are plausibly transient and safe to repeat. Separate connection and response timeouts help identify where time is being spent; the total deadline must include all attempts and delays.

A common backoff policy draws a random delay between zero and min(cap, base * 2**attempt). Jitter spreads retries so many clients do not hit a recovering service simultaneously. I would cap attempts and use a retry budget to avoid turning a small outage into overload.

A timeout does not prove the server did nothing. Retrying a non-idempotent write requires an explicit safety mechanism, such as an idempotency key or outcome lookup. I would honor valid server retry guidance within the deadline, avoid retrying ordinary validation failures, and prevent multiple dependency layers from independently multiplying attempts.

58. How do 429 and 503 differ, and how should Retry-After be handled?

429 indicates that the caller has exceeded a rate limit; 503 indicates that the service is temporarily unable to handle the request, for example because of overload or maintenance. The distinction supports different operational responses: adjust client demand for 429 and investigate service capacity or availability for 503.

Either response can provide Retry-After, expressed as delay seconds or an HTTP date. A client should parse both forms, account for its remaining deadline, and avoid immediately retrying before the advised time. If the value is absent or invalid, a bounded backoff policy with jitter can apply.

Neither status makes every request safe to repeat. A write may still require deduplication or an outcome check. I would expose a useful error type and limit scope where appropriate, but not leak other tenants' usage. Rate limiting and transient service failure should have distinct metrics and alerts.

59. How would you format errors using Problem Details for HTTP APIs?

I would use application/problem+json and stable problem types so clients can handle failures without parsing human-readable messages. The HTTP status remains meaningful; the response body adds context rather than replacing protocol semantics.

JSON example

{
  "type":"https://api.example.com/problems/insufficient-stock",
  "title":"Insufficient stock",
  "status":409,
  "detail":"Only two units are currently available.",
  "instance":"/problems/occurrences/req_84"
}
{
  "type":"https://api.example.com/problems/insufficient-stock",
  "title":"Insufficient stock",
  "status":409,
  "detail":"Only two units are currently available.",
  "instance":"/problems/occurrences/req_84"
}
{
  "type":"https://api.example.com/problems/insufficient-stock",
  "title":"Insufficient stock",
  "status":409,
  "detail":"Only two units are currently available.",
  "instance":"/problems/occurrences/req_84"
}

The type identifies the problem category, while the instance can identify this occurrence. If included, status should agree with the actual response status. I would add documented extension members for information clients genuinely need, such as a safe field-error list or support identifier. Error details must not include stack traces, credentials, SQL text, or internal hostnames. Different occurrences of the same type should remain structurally consistent even when their human-readable details differ.

60. How should validation errors identify fields without exposing internals?

I would identify invalid input using stable public field locations and machine-readable codes, with concise messages explaining the corrective action. Error paths should refer to the documented request structure, not database columns or implementation class names.

JSON example

{"errors":[{"pointer":"/items/0/quantity","code":"minimum","message":"Must be at least 1."}]}
{"errors":[{"pointer":"/items/0/quantity","code":"minimum","message":"Must be at least 1."}]}
{"errors":[{"pointer":"/items/0/quantity","code":"minimum","message":"Must be at least 1."}]}

Here, errors, pointer, and code are an application-defined extension that must be documented; they are not automatically mandated by Problem Details. JSON Pointer is useful for nested JSON bodies, while query and header errors need clearly identified locations of their own.

I would limit the number and size of reported errors, avoid echoing secrets, and distinguish malformed input from authorization failures. Validation should include types, ranges, formats, permitted properties, and cross-field rules. Tests should ensure a helpful public message never exposes a parser stack trace or confidential account existence.

61. How do bearer-token validation and OAuth scopes work together?

Bearer-token validation establishes whether the presented credential is acceptable for this API; scopes describe delegated permissions the token may exercise. Neither step eliminates the need for resource-specific authorization.

For a JWT access token, I would verify its signature using trusted keys, constrain accepted algorithms, and validate issuer, audience, expiry, and other required claims. For an opaque token, I would use the issuer's supported validation mechanism, such as authenticated introspection. The API should not assume every access token is a JWT.

An orders:read scope might permit invoking an order-read operation, but the API must still check whether this caller can read the particular order in the requested tenant. Missing or invalid credentials and insufficient permission should produce appropriate, documented authentication or authorization failures. Tokens belong in protected transport and should not appear in URLs, analytics events, or application logs.

62. When should a browser application use the authorization-code flow with PKCE?

A browser application using OAuth delegated authorization should use the authorization-code flow with PKCE rather than relying on a client secret embedded in JavaScript. Browser-delivered code cannot keep such a shared secret confidential.

The client creates a fresh verifier and sends its derived S256 challenge in the authorization request. When exchanging the returned authorization code, it sends the verifier. The authorization server checks the binding, reducing the usefulness of an intercepted code. Redirect URI validation and protection against authorization-response attacks remain essential; PKCE is not a replacement for the entire secure OAuth flow.

A backend-for-frontend can instead keep access tokens server-side and expose a hardened browser session, with its own cookie and CSRF controls. I would choose the architecture deliberately and follow the provider's supported flow. PKCE does not prevent malicious JavaScript from acting within an already compromised application.

63. Why does validating a JWT signature alone not authorize an API request?

A valid JWT signature proves integrity under a particular signing key; it does not prove that the token is intended for this API or that its holder may perform the requested action. Authorization requires additional context and policy checks.

I would constrain the accepted issuer and algorithms, verify audience and time-related claims, and ensure the token has the expected purpose. An ID token intended for a client application's sign-in session should not be accepted merely because its signature validates against a familiar identity provider.

After token validation, I would check operation permissions, tenant membership, ownership or sharing rules, and relevant resource state. A valid employee token should not authorize reading every employee's payroll. Revocation and privilege-change requirements also influence token lifetime and validation architecture. Tests must include correctly signed tokens with the wrong audience, issuer, scope, tenant, and token type.

64. How do you prevent broken object-level authorization?

I would authorize access to each requested object using the authenticated principal and the object's actual ownership, tenant, and sharing rules. Guess-resistant identifiers help reduce enumeration but do not replace authorization.

For GET /invoices/inv_42, a query constrained by both invoice ID and the caller's permitted tenant is safer than fetching by ID and assuming the URL implies access. The same checks must cover writes, nested resources, bulk endpoints, exports, and indirect references supplied in request bodies.

I would centralize reusable policy enforcement while keeping business-specific rules explicit. Negative tests should swap object identifiers between users with the same role and between tenants, not merely test an administrator against an anonymous client. Responses should avoid unnecessary existence disclosure. Audit logs can record denied access safely, but logging a denial does not compensate for returning the protected object.

65. How do you prevent mass assignment and broken property-level authorization?

I would use explicit request and response schemas instead of binding arbitrary JSON directly onto persistence models. Writable fields and readable fields must be separately authorized for the caller and operation.

For example, a profile update may accept displayName and timezone but never isAdmin, tenantId, or an internal approval flag. Simply hiding those fields in the UI is ineffective because clients can construct their own requests. Nested objects and patch paths require the same scrutiny as top-level members.

On output, I would construct a deliberate representation so fields such as password hashes, internal notes, or fraud scores cannot leak through automatic serialization. Schema validation is useful, but business authorization still determines which permitted fields a specific user may change. Tests should inject forbidden properties, attempt nested privilege changes, and inspect responses under multiple roles.

66. How do cookie authentication, CSRF protection, and CORS interact?

Cookie authentication can expose an API to CSRF because browsers may attach cookies automatically to attacker-triggered requests. CORS governs whether browser scripts can access cross-origin responses; it is not general API authorization and does not reliably prevent all cross-origin requests from being sent.

I would use appropriate Secure, HttpOnly, and SameSite cookie settings, CSRF protection suited to the application, and Origin validation where appropriate. State-changing actions should not use GET. SameSite is a useful layer, not an excuse to skip analysis of the application's actual cross-site flows.

For credentialed cross-origin requests, I would allow only trusted origins and configure credentials deliberately rather than use a wildcard origin. Preflight behavior must also be understood. Non-browser clients are not constrained by browser CORS enforcement, so authentication and authorization remain mandatory. XSS is another distinct threat: malicious same-origin code can bypass many assumptions behind browser-side protections.

67. How should file uploads be validated and constrained?

I would enforce upload limits before expensive processing and treat the uploaded filename, declared media type, and file contents as untrusted. Validation should combine an allowlist of permitted formats with content inspection and controls appropriate to how the file will be used.

For an image upload, I would bound compressed bytes, decoded dimensions, and processing time rather than checking only the filename extension. Generated storage names prevent traversal and collisions. Uploads should be isolated from executable application content, with authorization on both upload and retrieval. Antivirus scanning or content disarm can provide additional protection where the risk warrants it.

I would also limit per-user storage and concurrent uploads, handle partial transfers, and quarantine files until required checks complete. Archive extraction needs safeguards against path traversal and decompression bombs. A successful upload response should not imply the file is safe or publicly available before those stages finish.

68. How would you design a bulk operation with explicit failure semantics?

I would first decide whether the batch is atomic or allows partial success, then make that choice explicit in the request and response contract. Clients must not infer per-item outcomes from an ambiguous overall 200 response.

For an atomic update, every item succeeds or the entire batch leaves state unchanged. For independent items, the response can contain a stable client item identifier, outcome, resource link, and structured error for each entry. The top-level status describes processing of the batch envelope, while documented item results describe individual actions. There is no requirement to use WebDAV's 207 for every JSON bulk API.

I would cap item count and payload size, enforce authorization per item, and document ordering and dependencies. Retrying a partially successful batch requires item-level deduplication or carefully defined batch replay behavior. Large batches may fit an asynchronous operation resource better than a long synchronous request.

69. How should a client handle 301, 302, 303, 307, and 308 redirects?

A client should follow redirects according to both the status code and the safety of forwarding the original request. Redirect handling is especially important for requests with bodies or credentials.

Status

Main handling distinction

301 / 302

User agents may change POST to GET; do not rely on body preservation.

303

Retrieve the indicated resource, usually with GET.

307 / 308

Preserve the method when automatically following.

301 and 308 indicate permanent redirection; 302 and 307 are temporary. I would bound redirect chains, reject insecure downgrades where required, and verify how the chosen HTTP library handles headers and replayable bodies. Authorization should not be blindly forwarded to another origin. A streaming upload may not be replayable even when the status preserves its method. For APIs, explicit redirect policies are safer than assuming every client behaves like a browser.

70. What request and response information should an API log?

I would log enough structured metadata to reconstruct failures and measure service behavior without collecting unnecessary sensitive data. Useful fields include timestamp, request or trace identifier, route template, method, status, duration, response size, service version, and a suitably protected caller or tenant reference.

Route templates such as /orders/{id} keep aggregation manageable and avoid recording arbitrary path values as metric labels. Security events should identify the action and outcome, while detailed audit records may need separate integrity and retention controls.

I would not routinely log authorization headers, cookies, passwords, access tokens, full request bodies, or personal data. Redaction should happen before data reaches the logging system. Untrusted values need length limits and safe encoding to prevent log injection. Access controls, retention, sampling, and failure behavior matter too: observability should not become a new data leak or take down the request path when the logging backend fails.

71. How do correlation IDs and distributed tracing help API troubleshooting?

A correlation ID joins records for a logical request; distributed tracing adds parent-child spans and timing across services. Together they help identify whether a slow response came from gateway waiting, application work, a downstream call, or a database operation.

I would propagate supported trace context across trusted boundaries and attach trace and span identifiers to structured logs. A service should create a new child span rather than reuse one span identifier for every downstream operation. Asynchronous work may require explicit propagation or links because it can outlive the original request.

Incoming identifiers are untrusted metadata, not credentials. I would validate their format and avoid placing personal data in tracing baggage. Sampling means a log may not have a retained full trace, so essential diagnostics cannot depend on traces alone. Finally, parallel span durations must not simply be added together when explaining the end-to-end latency.

72. How would you test an API contract against an OpenAPI description?

I would validate the OpenAPI document itself, then test whether real requests and responses conform to the declared operations, schemas, status codes, headers, and media types. The description must match the implementation version being tested.

A test suite should exercise valid examples and boundary cases, including missing required fields, null versus absent values, unsupported media types, and undocumented response shapes. Generated tests are useful, but curated examples are needed for business invariants and authorization scenarios. I would also compare contract changes in CI to flag removed operations, newly required inputs, or changed field types.

Schema conformity does not prove semantic correctness. A response can satisfy its schema while exposing another tenant's order or calculating the wrong total. Consumer expectations and integration behavior need additional tests. Tooling must support the OpenAPI version and schema dialect in use rather than silently ignoring keywords it does not understand.

73. How do unit, integration, contract, and end-to-end API tests differ?

The test levels differ mainly in scope, dependencies, and the failures they are designed to isolate. I would combine them rather than expect one layer to establish all API correctness.

Unit tests exercise focused logic, such as validation or authorization policy, with controlled dependencies. Integration tests verify interactions with real components such as the database, serializer, or message broker. Contract tests check that a provider and its consumers agree on request and response behavior. End-to-end tests execute complete workflows through the deployed stack.

For an order API, a unit test can reject a negative quantity, an integration test can verify transactional rollback, a contract test can validate the error representation, and an end-to-end test can complete checkout. Most cases should run at the narrowest useful level for fast feedback. A smaller set of realistic end-to-end tests covers critical paths without making every diagnosis depend on a slow, fragile full environment.

74. How should an API handle dates, time zones, money, and large identifiers?

I would choose explicit, interoperable representations and document their semantics rather than rely on each language's defaults. Dates, instants, monetary values, and identifiers have different requirements.

JSON example

{"createdAt":"2026-10-26T11:00:00Z","billingDate":"2026-10-31","amountMinor":1299,"currency":"USD","id":"9007199254740993"}
{"createdAt":"2026-10-26T11:00:00Z","billingDate":"2026-10-31","amountMinor":1299,"currency":"USD","id":"9007199254740993"}
{"createdAt":"2026-10-26T11:00:00Z","billingDate":"2026-10-31","amountMinor":1299,"currency":"USD","id":"9007199254740993"}

An instant includes an offset or UTC marker; a calendar date does not imply midnight in an unspecified time zone. Recurring local schedules may need an IANA time-zone identifier as well as local time because daylight-saving rules matter.

For money, I would use a documented decimal representation or integer minor units together with currency, never assume every currency has two decimal places, and define rounding. Large identifiers are often safest as strings because JavaScript numbers cannot exactly represent every large integer. These choices must be consistent across schemas, SDKs, persistence, and examples to prevent silent coercion.

75. How can an API evolve without breaking older clients?

I would preserve existing client assumptions about accepted inputs, response meaning, and failure behavior, not merely keep the endpoint path unchanged. Compatibility includes semantics as well as JSON shape.

Adding an optional response field is often safe when clients tolerate unknown fields. Making an input required, changing units, narrowing accepted values, or turning a nullable field into a different structure can break clients. Even adding an enum value may break consumers with exhaustive switches, so enum evolution needs an explicit policy.

I would use contract tests, consumer feedback, and traffic evidence to assess changes before rollout. New behavior can be introduced through optional capabilities or a separate version when necessary, with a migration period. Old and new clients should be tested together. I would avoid changing undocumented defaults casually: if clients rely on pagination ordering or retry behavior, those defaults are effectively part of the contract.

76. How would you deprecate and retire an API version?

I would deprecate a version through a migration process with a replacement, clear dates, usage visibility, and direct communication to affected consumers. A warning in documentation alone is unlikely to reach every production client.

The standardized Deprecation response header can signal deprecation, and a deprecation link can point to guidance. Its date syntax is a Structured Field Date using @ followed by epoch seconds. Sunset serves a different purpose: it signals an expected retirement time and uses HTTP-date syntax. Deprecation does not itself change endpoint behavior or mean it is already unavailable.

I would publish migration examples, maintain overlap, identify remaining clients from privacy-conscious telemetry, and test the replacement against representative workflows. Before shutdown, owners need an agreed retirement decision and recovery plan. After retirement, responses should remain intentional and documented rather than deteriorating into unexplained gateway errors.

77. When should you return an empty collection instead of 404?

I would return an empty collection when the collection resource exists and the query succeeds but no members match. For example, GET /orders?status=refunded can return 200 with {"items":[]} even when the user has no refunded orders.

A 404 is appropriate when the addressed resource does not exist or when the API intentionally does not disclose its existence. That distinction matters for nested paths: an existing customer's empty order collection differs from a request under a nonexistent customer. The API should document that behavior and apply authorization before revealing parent existence.

Returning a consistent collection envelope avoids forcing clients to treat ordinary absence of results as an exception. It also preserves pagination metadata and links. I would not switch between an array, null, and a missing field based on result count. A successful empty result must still reflect validated filters rather than silently ignoring invalid query parameters.

78. How can hypermedia guide a multi-step business workflow?

Hypermedia can expose the transitions currently available in a business workflow so clients follow server-provided controls instead of constructing every next URL themselves. The links or actions need documented relation semantics and representation rules; arbitrary URL fields are not enough.

For an order awaiting payment, the representation might offer a payment action and a cancellation action. After shipment, those actions disappear and a tracking relation becomes available. A client understands the meaning of these relations and uses the supplied targets rather than embedding the entire order state machine.

Action descriptions may need method, accepted media type, and input requirements through an established media type or documented profile. Missing controls can improve the user interface, but they are not authorization enforcement: the server must recheck permissions and state when an action arrives. Clients must also handle stale representations because another actor may change the workflow before execution.

79. How should webhook deliveries be authenticated and retried?

I would authenticate webhook deliveries using HTTPS plus a documented signature scheme, then make processing safe under retries. For an HMAC-based scheme, the receiver verifies a signature over the exact required message bytes and timestamp using the correct endpoint secret, with constant-time comparison where appropriate.

The receiver should enforce a freshness window and deduplicate event identifiers. Signature verification generally needs the original raw body, not JSON that has been parsed and reserialized. Secret rotation should support a controlled overlap without accepting obsolete secrets indefinitely.

After validation, I would durably enqueue the event and acknowledge promptly; a successful response should mean it is safely accepted, not merely read into memory. Delivery retries need bounded backoff, observability, and a dead-letter or manual recovery path. Consumers should tolerate duplicate and out-of-order events and fetch current resource state when ordering cannot be trusted.

80. How do you diagnose a slow API request across gateway, service, and database?

I would trace one slow request across layers and compare it with a similar fast request before guessing at the bottleneck. End-to-end duration includes more than application execution: DNS, connection setup, gateway queues, service queues, downstream calls, database waits, serialization, and response transfer can all contribute.

I would correlate gateway access logs, application spans, and database evidence using a trace or request identifier. At the database, connection-pool wait and lock wait must be distinguished from query execution; a fast query after a long pool wait does not exonerate the database path. Query plans, row counts, and N+1 patterns can then explain execution cost.

I would segment results by route, payload size, tenant, cache state, and deployment version, and inspect tail latency rather than averages alone. After a targeted change, I would repeat a representative workload and verify both latency and error rates without exposing sensitive payloads in diagnostics.

REST API Interview Questions and Answers for Experienced

The experienced answers focus on distributed correctness, security, multi-tenancy, resilience, evolution, and API governance. The right design depends on business guarantees and client needs, not merely on whether an endpoint uses JSON and resource-shaped URLs.

81. How would you design an order API that survives duplicate requests and ambiguous timeouts?

I would make order creation a durable business operation with a client-supplied idempotency key, rather than treating a timeout as evidence that nothing happened. The key would be scoped to the authenticated tenant and operation, bound to a canonical request fingerprint, and retained for a documented retry window.

A unique database constraint would arbitrate concurrent attempts. In one transaction, I would persist the order and the operation's recoverable result or state. Matching retries would return the existing outcome; a different payload using the same key would be rejected. Pending operations would expose a stable status resource instead of starting another order.

Payment and fulfillment need their own deduplication and reconciliation boundaries; a local transaction cannot make remote effects exactly once. I would test simultaneous duplicates, crashes after commit but before response, and retries after retention expires. Clients should reconcile ambiguous outcomes before creating a new key.

82. How would you coordinate API writes with event publication reliably?

I would commit the business write and an outbox record in the same database transaction, then let a separate publisher deliver the event. That removes the gap where an order commits but the process crashes before notifying downstream services.

Each event would carry a stable identifier, aggregate identifier, and relevant sequence or version. The publisher would retry until delivery is acknowledged, but a crash after publishing and before recording success can cause duplicate delivery. Consumers therefore need durable deduplication or idempotent state transitions, ideally committed with their own business effects.

I would preserve ordering only where the business requires it, such as within one order, rather than promise global ordering. Operationally, I would monitor oldest unpublished-event age, backlog, poison events, and consumer lag. Failure tests would interrupt both sides of every commit boundary and verify that reconciliation finds neither missing transitions nor duplicate financial effects.

83. How do you preserve correctness when an API spans multiple services?

I would identify the business invariants first, then keep each invariant within one transactional owner wherever possible. Splitting a workflow across services does not create a distributed transaction merely because the API presents one endpoint.

For an order spanning inventory and payment, I might use a durable saga: reserve inventory, authorize payment, then confirm the order. Each step needs an operation identifier, retry behavior, timeout policy, and compensating action. Compensation is a new business action, such as releasing a reservation; it is not necessarily an exact reversal of everything already observed.

The public representation should distinguish pending, confirmed, failed, and intervention-required states. I would make ownership of stuck workflows explicit and provide reconciliation tooling. Tests would cover duplicate messages, reordered responses, expired reservations, and failed compensation. If the requirement truly demands an indivisible cross-service invariant, I would reconsider the boundary or accept the coordination and availability costs explicitly.

84. How should an API expose eventual consistency and read-your-writes behavior?

I would state which reads are authoritative, which may lag, and what evidence a client can use to observe its own write. A successful write response should not silently imply that every search index, replica, and analytics view has already caught up.

For example, order creation could return the committed order and its version immediately, while the collection search remains eventually consistent. A subsequent detail read could route to the authoritative store, or accept a documented consistency token and wait up to a bounded deadline for a replica to reach that version. Such a token must be scoped and validated rather than trusted as an arbitrary storage instruction.

I would document timeout behavior and a fallback status lookup when the requested consistency cannot be met. Tests would deliberately delay replication and check monotonic client behavior, failover handling, and misleading empty search results. Stronger guarantees should be paid for only on workflows that need them.

85. How would you design optimistic concurrency for a high-contention resource?

I would use a strong representation validator with If-Match and enforce the comparison atomically with the update. Reading a version, checking it in application code, and later writing unconditionally still permits a lost update.

For a shared inventory resource, the database operation might update only where both the identifier and expected version match, incrementing the version on success. A stale precondition produces 412; a missing mandatory precondition can produce 428. The client must reload and reconsider its intended change, not blindly overwrite the latest representation.

Under sustained contention, optimistic concurrency may create excessive retries. I would examine narrower resources, atomic domain operations, reservations, or serialized processing instead of merely increasing retry counts. An invariant such as nonnegative stock belongs in the authoritative transaction as well. Concurrent tests should verify both conflict rates and business outcomes, including two writers racing from the same version and unrelated changes sharing one coarse validator.

86. How would you build a multi-tenant API without cross-tenant data leakage?

I would make tenant isolation an end-to-end authorization invariant, not a convention in URL naming. The effective tenant must come from authenticated, authorized context; a caller-supplied tenant identifier is only a requested target that requires validation.

Every object lookup, mutation, list query, cache entry, background job, export, and event subscription must preserve that scope. I would use tenant-aware repository interfaces and, where practical, database policies as defense in depth. Administrative cross-tenant access needs a separate, narrowly authorized path with auditable purpose.

A dangerous example is correctly filtering the database but caching the result under an object identifier alone. Another is a worker loading an export without its originating tenant context. I would maintain negative tests that substitute another tenant's identifiers across all operations, including nested objects and bulk requests. Isolation reviews should also inspect logs, support tooling, object-storage paths, and error behavior, because successful endpoint authorization does not cover those secondary channels.

87. How would you design rate limits and quotas that are fair across tenants?

I would separate short-term rate limits, concurrency limits, and longer-term consumption quotas. They protect different resources: requests per second does not constrain an export that occupies a worker for twenty minutes.

A practical design uses per-tenant budgets with operation-specific costs, bounded bursts, and a global capacity guardrail. Expensive searches might consume more units than a small metadata read. Weighted scheduling can preserve minimum service for smaller tenants while allowing unused capacity to be borrowed. Limits should be keyed to verified identity, not just IP addresses shared by many users.

For distributed enforcement, I would explicitly choose between approximate local counters and stronger shared coordination, including behavior when the limiter is unavailable. Responses should explain the relevant limit without revealing other tenants' usage. I would test noisy-neighbor workloads, synchronized bursts, and key rotation attempts. Fairness is demonstrated by latency and useful throughput across tenants, not merely by a counter remaining below its threshold.

88. How do admission control, load shedding, and backpressure protect an API?

Admission control decides whether work can begin, load shedding rejects work the service cannot safely absorb, and backpressure signals producers to slow down. Together they keep overload from turning into unbounded queues, timeouts, and cascading retries.

I would set limits around the scarce resource: database connections, worker slots, downstream concurrency, or queue age. A request that cannot finish within its remaining deadline should usually be rejected before consuming more capacity. Priority classes can protect critical operations, but low-priority work still needs explicit starvation and retention policies.

For example, an export queue could stop accepting jobs once its estimated waiting time exceeds the product's promise, while ordinary order reads continue. Clients need bounded, jittered retry behavior, not immediate retries against every rejection. I would verify that the service recovers after a traffic spike, queue age falls, and useful completions remain stable. CPU utilization alone is insufficient evidence that overload protection works.

89. How should retry budgets and circuit breakers work together?

Retry budgets limit how much extra traffic recovery attempts may generate; circuit breakers temporarily stop calls to a dependency that is persistently failing. I would use both, with one clearly designated retry layer, so a single request does not multiply retries at every service hop.

Each attempt must fit within the original deadline and be safe to repeat. A budget could cap retries relative to normal traffic, while exponential backoff and jitter spread remaining attempts. An open circuit should fail quickly or use a semantically valid fallback; a half-open circuit should admit only limited probes before normal traffic resumes.

I would distinguish dependency failures from caller mistakes so invalid requests do not trip the breaker. Isolation should match the failure boundary, avoiding one tenant's bad workload disabling everyone else. Tests would measure attempt amplification, recovery behavior, and fallback correctness during partial outages. Neither mechanism resolves an ambiguous write outcome without application-level idempotency or reconciliation.

90. How would you design an asynchronous job API with cancellation and expiry?

I would expose a durable job resource with explicit states, ownership, progress semantics, and retention. Submission can return 202 with a status location, but acceptance must mean the system has durably recorded enough information to execute or recover the job.

The state machine might include queued, running, succeeded, failed, cancellation-requested, canceled, and expired. Cancellation is a request, not a guarantee that already committed effects can be undone. A compare-and-set transition should arbitrate a worker completing at the same time that a client requests cancellation.

The contract should distinguish execution deadlines from result expiry and specify how long status records remain accessible. Result downloads require authorization even when the job identifier is hard to guess. I would make submission retries deduplicated and workers restartable from checkpoints. Verification would cover worker crashes, duplicate deliveries, cancellation races, expired results, and cleanup failures, with operators able to identify jobs that are no longer making progress.

91. How would you design bulk exports without exhausting application memory?

I would run large exports asynchronously and process bounded chunks into durable object storage instead of building the entire file in application memory. The job response would provide progress and, after completion, an authorized download path with a defined expiry.

The consistency model matters as much as streaming: exporting a changing collection may require a database snapshot, a point-in-time boundary, or an explicitly best-effort view. I would choose stable ordering and checkpoints that let a worker resume without silently skipping or duplicating rows. Long database snapshots also have storage and maintenance costs, so they need limits.

Per-tenant concurrency, byte caps, cancellation, and destination cleanup protect capacity. Exported fields must follow the same authorization policy as interactive reads, including property-level restrictions. I would test with a dataset larger than available worker memory, inject failures between chunks, and compare row counts and checksums against the chosen consistency contract. Partial artifacts should never appear as completed downloads.

92. How would you select between polling, webhooks, server-sent events, and WebSockets?

I would choose the simplest delivery mechanism that meets the latency, directionality, and operational requirements. Polling suits infrequent status checks; webhooks suit server-to-server notifications; server-sent events suit a mostly server-to-browser event stream; WebSockets suit sustained bidirectional interaction.

For a report-generation API, bounded polling may be entirely adequate. For integration events, webhooks avoid requiring partners to hold connections open but introduce delivery retries and destination security. A live dashboard may benefit from server-sent events, while collaborative interaction may justify WebSocket session infrastructure.

Whichever transport I choose, I would define reconnect behavior, event identifiers, ordering scope, replay retention, authentication refresh, and backpressure. A live connection is not durable delivery, and reconnection can produce gaps or duplicates. The authoritative resource API should allow clients to reconcile current state. I would test proxy idle timeouts, slow consumers, reconnect storms, and token expiry. These communication choices do not by themselves determine whether the surrounding API satisfies REST constraints.

93. How would you design a secure webhook system for untrusted destinations?

I would treat every webhook destination as an untrusted outbound network request and every delivery as a potentially duplicated event. Destination registration should require authorization and appropriate ownership verification, but verification alone does not make future requests safe.

Delivery workers should restrict schemes and ports, reject prohibited network ranges after resolution, validate every redirect or disable redirects, and use controlled egress so DNS rebinding cannot reach internal services or metadata endpoints. Time, response-size, and concurrency limits prevent a recipient from exhausting workers.

I would sign the exact delivered payload with a timestamp and stable delivery identifier, document verification and key rotation, and provide a bounded retry schedule with jitter. Receivers need replay checks and durable deduplication. Failed deliveries should be inspectable without exposing secrets or complete sensitive payloads. Tests would include destinations that change addresses, redirect internally, respond slowly, and repeatedly fail, ensuring one tenant's endpoint cannot monopolize delivery capacity.

94. How can cache invalidation and conditional requests remain correct during updates?

I would define the acceptable staleness first, then align validators, cache keys, and invalidation with that contract. Conditional requests reduce transfer costs, but they do not automatically make independently cached representations instantly consistent after a write.

A validator must correspond to the selected representation and change when that representation changes. Successful writes can invalidate the directly targeted cached resource under HTTP rules, but related collections, derived summaries, and application caches need their own strategy. I might use versioned keys, bounded freshness, or event-driven invalidation backed by reconciliation.

The critical race is an old read populating the cache after an invalidation. Version-aware population or a generation check can stop stale data from becoming newly fresh. I would test concurrent reads and writes, delayed invalidation events, and representation variants. For authorization-sensitive data, correctness also includes partitioning or disabling shared caching; a perfectly fresh response is still unsafe if served to the wrong principal.

95. How would you investigate an authorization-related cache leak?

I would first stop further exposure by disabling or bypassing the affected shared cache and invalidating implicated entries, while preserving restricted evidence for investigation. I would not assume that adding one response header immediately removes copies already stored elsewhere.

Using controlled test identities, I would reconstruct the full cache key and request path across CDN, gateway, application, and browser layers. I would inspect tenant scope, authorization handling, query normalization, negotiated variants, and any rule that overrides origin cache directives. The objective is to identify exactly which responses can be reused across principals.

Impact assessment should use access records carefully, without copying exposed content into incident tickets. Remediation needs regression tests where one identity primes the cache and another requests the same apparent URL. I would also test role changes and revoked access. Cache configuration and authorization changes should be rolled out together, followed by verification at every layer rather than only at the origin server.

96. How would you migrate a public API schema without synchronized client upgrades?

I would use an expand-and-contract migration so old and new clients remain valid during a measured transition. First I would identify the actual compatibility risks: renamed fields, changed meanings, new required inputs, narrower validation, and enum additions can break clients differently.

For example, replacing a single name field with structured components may require accepting both formats temporarily, defining precedence when both appear, and continuing to emit the old representation for existing consumers. Internally, I would migrate storage independently from the public contract and avoid dual writes without reconciliation.

Consumer contract tests and production usage telemetry would identify remaining dependencies. A version or capability boundary is appropriate when the new semantics cannot coexist safely; it should not substitute for a migration plan. I would publish examples and a retirement policy, then remove compatibility code only after the agreed conditions are met. Rollback must account for data written by the new implementation, not just restoring an older binary.

97. How would you version a representation without multiplying incompatible endpoints?

I would version only the incompatible representation contract and keep resource identity stable where practical. A media-type or negotiated representation version can let the same resource URI serve compatible variants without creating a separate endpoint for every field change.

That approach requires explicit negotiation rules, sensible defaults, discoverable supported formats, and correct cache variation. URI versioning may still be the clearer operational choice for a particular client ecosystem; neither convention guarantees backward compatibility. I would compare tooling, gateway routing, generated clients, debugging, and cache behavior before selecting one.

Additive evolution should remain the default when clients can safely tolerate it. I would avoid combining many independent version switches that create an untestable compatibility matrix. Contract tests should exercise every supported representation against the same underlying resource, including write semantics and error shapes. The migration is successful when clients can upgrade independently and old versions can eventually retire, not merely when version numbers have been moved out of URLs.

98. How would you assess whether hypermedia adds value to a public API?

I would assess hypermedia by whether clients benefit from discovering valid transitions at runtime rather than hard-coding resource paths and workflow rules. Its value is strongest when business state changes which actions are available, or when independently evolving clients need navigational guidance.

For an order, the representation could expose a cancellation relation only while cancellation remains meaningful, with a defined media type describing how to invoke it. Link relation semantics and processing rules matter; an arbitrary array of URLs is not sufficient. The server must still authorize and validate the action because state may change before the client follows the link.

I would prototype one real client and compare branching logic, upgrade requirements, payload size, and tooling complexity with a documented non-hypermedia alternative. Tests should cover missing and unfamiliar relations and races between discovery and execution. If consumers simply ignore the controls and construct every URL themselves, I would not claim the design achieves the intended decoupling.

99. How would you design an API gateway without turning it into a business-logic bottleneck?

I would keep the gateway focused on cross-cutting edge responsibilities: routing, transport security, coarse authentication, request limits, and consistent telemetry. Business invariants and object-level authorization should remain with the services that own the relevant state.

A useful boundary is whether a rule requires domain data or a transaction. Rejecting an oversized body belongs at the edge; deciding whether an order is cancelable belongs in the order service. Some aggregation can be useful, but complex workflows and service-specific transformations can turn gateway configuration into a shared release bottleneck.

I would provide version-controlled policies, automated validation, independent service ownership, and a controlled exception process. Gateway failure modes require capacity testing, timeout alignment, and safe deployment practices because its blast radius is large. Tests should confirm that bypassing an edge check does not grant unauthorized backend access. I would also measure added latency and operational coupling rather than assuming a central gateway is automatically simpler.

100. When should a backend-for-frontend differ from a general-purpose API?

A backend-for-frontend should differ when a specific client experience has materially different data shape, latency, or interaction needs. I would use it to compose and adapt domain APIs, not to create a competing source of business truth.

For example, a mobile home screen may need one compact response assembled from several services, while an administrative web application needs detailed workflows and different pagination. The BFF can optimize payloads and absorb client-specific compatibility concerns, with ownership aligned to that frontend team.

Domain authorization must still be enforced downstream, and the BFF must not forward arbitrary client-supplied identity headers as trusted context. I would give fan-out calls deadlines and explicitly define partial-response behavior so one optional widget does not block the whole screen. Before introducing the layer, I would compare its benefit against extra deployments, duplicated adapters, and failure modes. Verification should use real client journeys and network conditions, not only isolated backend benchmarks.

101. How would you secure service-to-service API access?

I would give each workload a verifiable identity, use encrypted transport, and authorize the smallest necessary operations at the receiving service. Being inside a private network is not sufficient authentication, and a valid service identity does not grant access to every tenant's data.

Depending on the platform, I might combine mutual TLS with short-lived, audience-restricted access tokens. Certificate-bound tokens can reduce the usefulness of stolen tokens when that binding is enforced correctly. User-delegated calls must preserve the distinction between the calling service and the user on whose behalf it acts, without trusting unsigned forwarded headers.

Credentials should be issued and rotated automatically, with secrets excluded from logs and images. I would define behavior for identity-provider outages and certificate expiry rather than quietly falling back to anonymous access. Tests would include wrong audiences, expired identities, unauthorized service pairs, and cross-tenant requests. Audit records should identify both workload and delegated principal where applicable.

102. How would you manage access-token revocation and key rotation?

I would distinguish revoking a credential from rotating the signing key that verifies it. Rotating keys is routine hygiene; it is not a precise substitute for invalidating one compromised user's token.

For revocation-sensitive operations, I might use token introspection or a centrally enforced revocation mechanism, accepting its latency and availability costs. Short-lived self-contained access tokens reduce the exposure window but do not provide immediate revocation by themselves. Revoking refresh tokens prevents future issuance without necessarily invalidating already issued access tokens everywhere.

Normal key rotation should overlap old verification keys with new issuance long enough for valid tokens to expire, while emergency compromise may require rejecting the old key sooner. Validators need bounded key caches, trusted issuer configuration, and protection against attacker-driven key-fetch storms. I would test overlap, stale caches, authorization-server outages, and compromised-key removal. The documented revocation delay should reflect actual cache and propagation behavior rather than an idealized control-plane response.

103. How would you threat-model an API that accepts URLs and imports remote content?

I would threat-model the importer as an attacker-controlled request originating from a more trusted network. The main risks include server-side request forgery, credential forwarding, malicious content, oversized responses, decompression bombs, and expensive parsing.

I would prefer an allowlist of required destinations when the product permits it. Otherwise, a dedicated fetch service should constrain schemes, ports, resolved addresses, redirects, and egress routes, blocking internal and metadata networks for both IPv4 and IPv6. Validation must match the address actually connected to; checking a hostname once does not prevent later resolution changes.

Fetched content remains untrusted even when the destination is allowed. I would impose byte and time limits, avoid forwarding ambient credentials, and parse in a constrained worker with safe libraries. Tests should cover alternate address forms, redirects, DNS changes, and archives with extreme expansion. Authorization and quotas also belong on the import operation so legitimate destinations cannot become a resource-exhaustion channel.

104. How would you prevent sensitive data exposure through errors, telemetry, and exports?

I would minimize sensitive data at collection and serialization boundaries rather than relying entirely on cleanup after it reaches logs or exports. Each output channel should have an explicit allowlist of fields and a purpose-based access policy.

Errors should expose stable problem categories and safe identifiers, not stack traces, credentials, or database content. Telemetry should use route templates rather than raw URLs containing secrets, and avoid request bodies by default. Collector-side redaction is useful defense in depth, but data already sent to an exporter may have crossed the intended boundary.

Exports need property-level authorization, bounded retention, controlled downloads, and audit trails. I would seed test records with recognizable synthetic secrets and inspect errors, traces, logs, and generated files for leakage. Access reviews and deletion procedures must include telemetry stores and support tools. Any retention or privacy obligation should be determined for the actual organization and data, not assumed to be identical across jurisdictions.

105. How would you design an auditable deletion workflow with retention constraints?

I would model deletion as an auditable workflow whose status distinguishes loss of normal access from completion of the applicable erasure process. Removing a resource from the API does not prove that every replica, backup, export, or downstream system has physically removed it.

The workflow would verify authority, identify affected data locations, evaluate documented retention or hold requirements, and record a minimal decision trail. Eligible data would be deleted or irreversibly transformed according to the agreed policy; restricted retained data should not remain available through ordinary product access.

Workers need idempotent steps, retries, reconciliation, and clear ownership of failures. Backup restoration procedures must reapply deletion records so restored data does not silently reappear. I would expose useful progress without leaking sensitive inventory details, and test partial failure, duplicate requests, and restored backups. Retention periods and exceptions require organization-specific policy review; I would not present one universal deadline or claim that a successful DELETE response settles those obligations.

106. How would you evaluate HTTP/2 or HTTP/3 without changing API semantics?

I would evaluate HTTP/2 and HTTP/3 as transport changes while keeping resource meanings, methods, status codes, and authorization contracts unchanged. A protocol upgrade does not fix poor API boundaries or establish REST compliance.

HTTP/2 multiplexes streams over a connection, while HTTP/3 maps HTTP onto QUIC and can reduce cross-stream blocking caused by packet loss. Whether either improves this product depends on connection reuse, network loss, payload sizes, geography, proxies, and client support. I would measure realistic journeys rather than compare one warm request on a developer laptop.

The rollout needs observability by negotiated protocol, connection setup costs, CPU use, tail latency, and failure rates. I would test fallback when UDP is unavailable, intermediary translation, flow-control behavior, and connection draining. Security review should include protocol-specific resource exhaustion and replay-sensitive early-data behavior. A successful rollout improves user-visible performance without changing retry safety or exposing different application behavior through different transport paths.

107. How can inconsistent HTTP parsing across intermediaries become a security problem?

Inconsistent parsing can let an attacker make a frontend and backend disagree about request boundaries or authority, enabling request smuggling, cache poisoning, or authorization bypass. The vulnerability often exists between individually plausible components rather than inside one handler.

I would inspect the complete path, including HTTP/2-to-HTTP/1.1 translation, content framing, duplicate headers, connection reuse, and path normalization. Ambiguous framing should be rejected, and intermediaries must implement the relevant protocol rules consistently rather than guessing which interpretation the backend will choose.

The defensive priority is supported, patched proxies and servers with strict parsing, plus consistent routing and authorization normalization. I would use approved test environments to check malformed-request rejection and verify that one client's request cannot affect another request on a reused connection. Production investigation should preserve wire-level evidence securely where permitted. Application validation alone cannot repair a boundary disagreement that occurs before the request reaches application code, and a web application firewall is not proof of consistent parsing.

108. How would you define and measure API availability and latency objectives?

I would define availability and latency objectives around useful user outcomes, with an explicit population of requests and a measurement window. A process being alive is not an availability objective, and a fast error response is not a successful user interaction.

For example, order submission might require a valid accepted operation within a chosen threshold, while asynchronous completion has a separate objective. I would specify how client errors, rate limits, cancellations, dependency failures, and maintenance are counted so exclusions cannot hide genuine service problems. Latency objectives should use threshold-based good-event ratios or relevant percentiles, not just averages.

Metrics should be segmented by critical operation and measured near the user boundary where possible. Internal traces help explain misses but do not replace the service-level indicator. I would derive alerting and release decisions from error-budget consumption, validate instrumentation against synthetic transactions, and revisit targets with product owners when cost, user expectations, or traffic patterns change.

109. How do you design API load tests that reveal realistic failure modes?

I would build a workload model from real operation mixes, arrival patterns, data sizes, and tenant skew, then test both steady capacity and recovery after overload. A uniform stream of tiny cached reads rarely reveals the failures that matter in production.

The environment should represent connection pools, database indexes, cache misses, authentication costs, and downstream limits. An open arrival model can reveal queue growth that a closed loop hides when clients slow down with the service. I would include large payloads, expensive valid queries, bursty tenants, retrying clients, and slow dependencies.

Success criteria should cover correctness, useful throughput, tail latency, queue age, rejection behavior, and time to recover, not only maximum requests per second. Test traffic must be isolated and authorized, with stop conditions that protect shared dependencies. After identifying a bottleneck, I would change one constraint and repeat the same workload. I would also verify that generator capacity and measurement artifacts are not mistaken for server behavior.

110. How would you roll out a risky API change with canaries and rollback?

I would separate deployment from exposure, introduce the change to a controlled cohort, and compare user-relevant outcomes against a comparable baseline before expanding. A canary is useful only when its traffic can expose the risk and the monitoring can detect harm.

For a schema or write-path change, I would first ensure old and new binaries can coexist and that the data migration is backward compatible. Feature flags or routing rules can limit exposure, but tenant-sticky routing may be necessary when mixed behavior would confuse a workflow. Shadow reads can help compare results; shadow writes must not accidentally duplicate real effects.

Rollback criteria should include correctness, authorization failures, and error-budget burn as well as latency. I would rehearse the reversal and identify irreversible changes requiring a forward fix or compensation. Low-traffic canaries need enough representative observations before promotion. The rollout ends when the new path is stable and obsolete compatibility mechanisms can be removed safely, not when deployment tooling reports success.

111. How would you diagnose rising p99 latency while average latency stays stable?

I would treat rising p99 latency as evidence that a small but important request population has worsened, then locate that population before optimizing the average path. Changes in tenant mix, payload size, region, cache state, or dependency behavior can affect the tail without moving the mean much.

First I would verify the histogram boundaries, aggregation window, and sample volume. Averaging per-instance percentiles does not produce the fleet percentile. I would compare request cohorts and use trace exemplars or targeted sampling to inspect slow requests, including queue time before application spans begin.

Likely causes include pool exhaustion, lock contention, garbage collection, cold connections, slow shards, and retry amplification. I would correlate each hypothesis with saturation metrics and a timeline of changes. A controlled reproduction or reversible mitigation should confirm causality. Increasing timeouts may merely keep requests waiting longer; the desired outcome is reduced tail latency without sacrificing correctness or hiding failures through cancellations.

112. How do you design disaster recovery and failover for stateful API dependencies?

I would start with recovery time and recovery point objectives for each user-critical workflow, then design the dependency recovery sequence to meet them. Stateless API servers are easy to replace; databases, queues, keys, configuration, and deduplication records usually determine whether recovery is correct.

The strategy might use replication for rapid failover and independent backups for corruption or destructive changes. Promotion requires fencing the previous writer to avoid split brain, validating replication lag, and understanding which acknowledged writes may be missing. DNS changes alone do not establish safe ownership of writes.

Recovery exercises should restore actual data into an isolated environment, verify credentials and encryption keys, replay necessary events, and test business invariants. I would include failback and reconciliation, not just failover. The public API needs a plan for ambiguous operations and unavailable historical status during recovery. Measured restore time and recoverable data age are stronger evidence than backup-success dashboards or an untested runbook.

113. How should an API handle cross-region consistency and duplicate suppression?

I would choose the consistency boundary before choosing multi-region routing. If duplicate suppression must be global, independently writable regional idempotency tables with asynchronous replication are insufficient: two regions can accept the same operation before either sees the other.

For a payment-like operation, I might route each tenant or operation key to one authoritative writer, or use a store with the coordination guarantees the invariant requires. During a partition, preserving that guarantee may require rejecting or delaying some writes. Active-active designs can work for mergeable state, but financial side effects need stronger ownership and reconciliation.

The idempotency record must preserve tenant scope, request fingerprint, outcome, and a documented retention window through failover. I would test duplicate requests arriving simultaneously in different regions, stale routing, and promotion with replication lag. Read consistency should also be explicit: a nearby replica may not reflect a just-accepted write. Geographic availability claims should never conceal weaker duplicate or durability guarantees.

114. How would you design signed requests and replay protection when bearer tokens are insufficient?

I would use a well-defined request-signature scheme that binds the request to a trusted key and covers the components whose integrity matters. A signature authenticates selected message content; it does not automatically authorize the operation or prevent replay.

The signing contract should include the method, target, relevant headers, and a verified content digest when the body matters. Both parties need identical canonicalization and an agreed set of mandatory covered components. Creation and expiry times bound the acceptance window, while a nonce or unique request identifier needs atomic replay tracking scoped to the signing identity.

I would document clock-skew tolerance, key discovery, rotation, and behavior when replay storage is unavailable. TLS remains necessary to protect confidentiality and transport context. Tests would alter each protected component, replay the same valid request concurrently, and exercise intermediary normalization. Finally, I would distinguish intentional application retries from malicious replays, using a separate idempotency contract where clients must safely recover an ambiguous outcome.

115. How would you govern a large API portfolio without slowing every team?

I would standardize the decisions that repeatedly create integration or security risk, while leaving teams freedom over domain modeling and implementation. Governance should make the safe path easy rather than require a central committee to approve every endpoint.

A practical baseline covers authentication, authorization expectations, errors, pagination, compatibility, observability, ownership, and retirement. Templates, reference implementations, schema linting, and contract checks can enforce routine rules in the delivery pipeline. An API catalog should identify owners, consumers, lifecycle state, and supported versions so abandoned endpoints do not disappear from security review.

Exceptions need a named owner, rationale, risk assessment, and review date rather than a permanent informal waiver. I would reserve human design reviews for high-risk boundaries, sensitive data, and genuinely novel patterns. Measures of success include integration lead time, recurring incidents, adoption, and compatibility failures. A hundred-page standard that teams bypass is less useful than a small, tested set of defaults with a clear escalation path.

116. How would you compare REST, gRPC, and GraphQL for a specific product?

I would compare the options against the product's clients, interaction patterns, and operating constraints rather than declare one universally superior. REST is an architectural style, gRPC is an RPC framework, and GraphQL defines a query-oriented API model; they are not interchangeable labels for serialization formats.

For a public resource API serving varied clients, conventional HTTP resource semantics can simplify inspection and caching. For internal typed service calls with streaming needs and controlled clients, gRPC may fit well. For a frontend assembling varied related data, GraphQL can give clients selection flexibility, but query cost, authorization, and resolver behavior need deliberate controls.

I would prototype the critical journey with realistic payloads and failure handling, evaluating tooling, browser support, observability, compatibility, and team expertise. Hybrid use can be sensible if translation boundaries remain clear. Whichever option wins, idempotency, access control, resource limits, and operational ownership still require explicit design; selecting a protocol does not solve them.

117. How would you design API contracts for clients that are intermittently offline?

I would design offline synchronization around durable operation identities, explicit conflicts, and a recoverable change feed rather than assume clients can replay old requests indefinitely. The contract must state how long idempotency records, change cursors, and deletion tombstones remain valid.

A client could queue an operation with a stable identifier and the version it edited, then submit it when connectivity returns. The server checks current authorization and concurrency constraints at execution time. It should not trust an old offline permission decision or silently overwrite newer changes. Some domains allow deterministic merging; others need the user to resolve a conflict.

A sync cursor should be opaque, scoped, and accompanied by a full-resynchronization path when history expires. Deletions need representation in the change stream so offline clients do not resurrect removed records. I would test reordered uploads, repeated reconnects, long absences, expired credentials, and interrupted downloads. Local storage protection also matters because server-side revocation cannot erase every disconnected device immediately.

118. How would you handle a breaking security fix that cannot wait for normal deprecation?

I would prioritize containment of the security exposure, while making the unavoidable compatibility impact explicit and as narrow as possible. Normal deprecation timelines are not a reason to keep a known exploitable behavior available.

The response should identify the vulnerable behavior, affected clients, immediate mitigation, and safer replacement. Depending on the issue, I might disable one operation, reject a dangerous input shape, restrict a permission, or require credential rotation. Feature flags and targeted routing can reduce blast radius, but must not leave an undocumented insecure bypass for important customers.

I would coordinate incident communication with security and support, provide a migration example, and avoid disclosing exploitable details prematurely. Tests should prove the exploit path is closed and check critical legitimate workflows. Rollback must not simply restore the vulnerability; a safe fallback or forward fix may be necessary. After containment, I would track impacted consumers, remove temporary controls deliberately, and update compatibility policy to describe emergency security exceptions.

119. How do you distinguish an HTTP API that works from one that satisfies REST constraints?

An HTTP API can be useful, reliable, and secure without satisfying all REST constraints. I would assess the architecture rather than infer compliance from JSON payloads, plural nouns, or correct-looking status codes.

REST combines client-server separation, stateless interactions, cache constraints, a uniform interface, layered systems, and optional code-on-demand. Its uniform interface includes resource identification, manipulation through representations, self-descriptive messages, and hypermedia-driven application state. Statelessness concerns the information needed to understand each request; it does not prohibit persistent resource data on servers.

In a review, I would follow a real client workflow and ask whether the client interprets representation semantics and available controls, or relies on an out-of-band script of endpoint calls. I would also inspect cache metadata and assumptions about intermediary layers. The result should be an honest description of the design and its trade-offs. Calling a pragmatic HTTP API non-RESTful is not, by itself, evidence that the product needs a rewrite.

120. How would you review an unfamiliar API design in a senior engineering interview?

I would begin with the product workflow and the invariants the API must protect, then review the contract through a few concrete success and failure scenarios. Listing endpoint naming preferences before understanding the domain misses the most consequential risks.

For an order API, I would trace creation, duplicate submission, concurrent updates, authorization failure, and a timeout after commitment. I would inspect resource boundaries, method semantics, response states, pagination, errors, compatibility, and consistency promises. Then I would examine tenant isolation, sensitive data, quotas, dependency failure, observability, and operational ownership.

I would distinguish facts from assumptions and ask which client and traffic constraints drove each choice. Recommendations should be prioritized: a cross-tenant authorization flaw outranks inconsistent naming, and an unbounded export outranks a cosmetic response-field preference. I would finish with a small set of proposed changes and the tests or measurements needed to validate them, rather than redesign everything or claim that one architectural style resolves every trade-off.

REST API Documentation and Further Reading

HTTP semantics and REST constraints are distinguished from implementation conventions and evolving specifications. Verify the chosen OpenAPI version, browser behavior, OAuth profile, framework, and gateway capabilities before adapting examples. An Internet-Draft is not an RFC or a universal interoperability guarantee.

Use these primary architecture, protocol, security, and API-description resources to verify the concepts in this guide. The references are curated, not an exhaustive research log. Source review and local static or synthetic checks do not establish that a particular API deployment is secure, interoperable, or production-ready.

Team Sherlock.sh

Building fraud intelligence for live high-stake video interactions (financial discussions, hiring interviews, board meeting etc).

Catch candidate fraud before it costs you.

Sherlock AI helps you detect AI-assisted, proxy, and deepfake candidates, so every hiring decision is backed by evidence.

Ask AI about Sherlock.sh

Similar Posts