REST API Design Interview Questions and Answers
Resource modelling, HTTP semantics, versioning and API evolution.
Whether you are preparing for entry-level REST API Design interview questions for freshers or senior software engineer interview questions addressing concurrency, scalability, and system architecture, this track provides peer-reviewed model answers with syntax walkthroughs, edge cases, and practical interview tips.
1 What is idempotency and which HTTP methods are idempotent? Easy
An operation is idempotent when performing it multiple times produces the same server state as performing it once.
- GET, HEAD, PUT and DELETE are idempotent by HTTP semantics.
- POST is not idempotent; repeated calls may create multiple resources.
- PATCH is not guaranteed to be idempotent.
PUT /users/42/email
Idempotency matters for retries: a client or gateway can safely retry an idempotent request after a timeout. For non-idempotent operations such as payments, use an idempotency key so the server can detect and deduplicate retries. Note that idempotency refers to server side effects, not the response code: the same DELETE may return 204 the first time and 404 the second, yet the end state is unchanged.
2 What is the difference between HTTP 401 and 403? Easy
401 Unauthorized means the request lacks valid authentication credentials. The client should authenticate and retry, and the response should include a WWW-Authenticate header describing the scheme.
403 Forbidden means the server understood the request and knows who the caller is, but the caller is not allowed to perform it. Re-authenticating will not help; the identity simply lacks permission.
HTTP/1.1 401 Unauthorized
WWW-Authenticate: Bearer realm="api"
Practical mapping: a missing or expired token gives 401, while a valid token with an insufficient role gives 403. For sensitive resources, many APIs return 404 instead of 403 so attackers cannot learn whether a resource exists. Avoid returning 400 for permission failures, because it hides the real cause from clients and monitoring.
3 What does HATEOAS mean in REST? Easy
HATEOAS stands for Hypermedia as the Engine of Application State. A response not only carries data but also links describing the actions and related resources the client may follow next, so clients discover transitions at runtime instead of hardcoding URL templates.
{
"id": 42,
"status": "pending",
"_links": {
"self": { "href": "/orders/42" },
"cancel": { "href": "/orders/42/cancel", "method": "POST" },
"pay": { "href": "/orders/42/payment", "method": "POST" }
}
}
Because the server decides which links exist, clients can adapt when workflow rules change. In practice full HATEOAS is rare: it adds payload size and clients often still hardcode behavior. It is the top level of the Richardson Maturity Model and is most valuable for workflow-heavy APIs with many valid state transitions.
4 How do you version a public REST API? Medium
Common strategies:
- URI path versioning:
https://api.example.com/v1/orders. Most visible and easiest to route and cache, at the cost of polluting the URL. - Query parameter:
/orders?version=2. Easy but easy to forget and awkward to cache. - Custom media type:
Accept: application/vnd.example.v2+json. Purest REST approach but harder to test and document. - Custom header:
X-Api-Version: 2. Clean URLs, but invisible and frequently missed.
For a public API, URI versioning is the pragmatic default. More important than the mechanism is the policy: prefer additive, backward-compatible changes; never change the meaning of an existing field; announce deprecations early with Deprecation and Sunset headers; keep old versions running for a defined window; and protect consumers with contract tests in CI.
5 When should you use PUT, PATCH or POST? Medium
- POST creates a subordinate resource or triggers a non-idempotent action. The server assigns the identifier and returns 201 with a
Locationheader. - PUT replaces the entire resource at a known URI and is idempotent. Any omitted field is reset, which surprises clients doing partial updates.
- PATCH applies a partial modification and is generally not idempotent unless the patch document is written to be so.
PATCH /users/42
Content-Type: application/merge-patch+json
{ "email": "new@example.com" }
Two PATCH formats dominate: JSON Merge Patch (RFC 7396, simple) and JSON Patch (RFC 6902, a list of explicit operations). Prefer PUT when the client owns the full representation, PATCH when it does not. A frequent pitfall is using PUT with a partial body, which silently wipes unspecified fields.
6 How would you design pagination for a large collection? Medium
Two main approaches:
- Offset pagination:
GET /items?limit=20&offset=40. Simple and allows jumping to a page, but degrades as offsets grow because the database must scan and discard rows, and results shift when items are inserted or deleted. - Cursor (keyset) pagination:
GET /items?limit=20&after=eyJpZCI6MTIzfQ. The cursor encodes the last seen sort key, so the query uses an indexed range scan and stays stable under concurrent writes.
SELECT * FROM items
WHERE (created_at, id) < (:last_created, :last_id)
ORDER BY created_at DESC, id DESC
LIMIT 20;
Use cursor pagination for feeds and large, changing datasets; offset only for small admin tables. Always cap the limit, return a next link or cursor, avoid exposing raw IDs when they leak information, and document the sort order because cursors are only valid for it.
7 Which HTTP status codes should a REST API return? Medium
Group them by intent and be consistent:
- 2xx success: 200 OK, 201 Created (with
Location), 202 Accepted for async work, 204 No Content after DELETE. - 3xx: 301/308 for permanent redirects, 304 Not Modified for conditional GET.
- 4xx client errors: 400 malformed syntax, 401 unauthenticated, 403 forbidden, 404 not found, 405 wrong method, 409 conflict, 412 precondition failed, 415 unsupported media type, 422 semantic validation failure, 429 rate limited.
- 5xx server errors: 500 unexpected failure, 502 bad gateway, 503 unavailable (include
Retry-After), 504 gateway timeout.
Do not return 200 with an error body: it breaks monitoring, retries and generic clients. Reserve 5xx for genuine server faults so alerts stay meaningful. Pick 400 for malformed requests but 422 for well-formed input that fails business validation, and document your mapping.
8 How do idempotency keys work for POST requests? Medium
The client generates a unique key per logical operation and sends it in a header, typically Idempotency-Key.
POST /payments
Idempotency-Key: 4d7c2e6a-2b1f-4f9a-9c3d-1a2b3c4d5e6f
{ "amount": 5000, "currency": "USD" }
The server stores the key together with the request fingerprint and the final response (or a "processing" marker). On a retry with the same key it returns the stored response instead of charging again. Use a unique constraint on the key to make concurrent duplicates safe: one request wins and others receive 409 while the first is in flight.
Keys should expire after a sensible window, be scoped per account, and detect mismatched payloads by comparing a hash. This pattern is essential for payments, order creation and any non-idempotent POST that clients or gateways may retry.
9 How should a REST API format error responses? Medium
Use one consistent, machine-readable shape. A widely adopted choice is RFC 7807 application/problem+json:
{
"type": "https://example.com/problems/insufficient-funds",
"title": "Insufficient funds",
"status": 422,
"detail": "Account balance is 10 USD, required 50 USD.",
"instance": "/payments/abc",
"errors": [
{ "field": "amount", "code": "above_balance" }
]
}
Key properties: a stable type or code clients can branch on, a human-readable message, the HTTP status mirrored in the body, and field-level details for validation errors. Never leak stack traces, SQL or internal hostnames. Include a correlation or request id so support can trace the failure in logs.
Design the error contract once and reuse it across every endpoint; inconsistent error shapes are one of the most common sources of brittle client code.
10 How do you design filtering, sorting and sparse fieldsets? Medium
Expose them as query parameters with a clear convention:
GET /articles?status=published&author=42&sort=-created_at&fields=id,title
- Filtering: one parameter per field, or a documented DSL for ranges (
price[gte]=10). Only allow filtering on indexed, allow-listed columns to avoid full scans. - Sorting: a
sortparameter with comma-separated fields where a leading-means descending. Whitelist sortable columns because the value may reach anORDER BY. - Sparse fieldsets: a
fieldsparameter to trim payload size, useful for mobile clients and bandwidth-sensitive integrations.
Never interpolate user input directly into SQL; map names to known columns. Cap the number of filters and sort keys, and cache the allowed combinations. These parameters compose naturally with pagination and projection, and are usually preferable to building bespoke endpoints for every view.
11 When is REST the wrong choice, and what would you use instead? Hard
REST excels at resource-oriented CRUD with cacheable, uniform interfaces and a broad tool ecosystem. It becomes awkward when:
- The domain is action-oriented or RPC-like, such as "recalculate rating" or complex algorithms where resource nouns feel forced.
- Clients need many different projections and REST forces over-fetching or many round trips; GraphQL lets the client shape the response.
- You need low-latency, strongly typed, bi-directional streaming between internal services; gRPC with HTTP/2 and protobuf is a better fit.
- You need real-time push; WebSockets or server-sent events are required since REST is request-response.
- You must perform large batches or long-running jobs synchronously.
The alternative is not always all-or-nothing. Many systems expose a REST or GraphQL edge to clients and use gRPC or messaging internally. Choose based on consumers, latency, payload shape and how naturally the domain maps to resources.
12 How do you model a long-running operation in REST? Hard
Do not hold the connection open. Instead accept the work and return 202 Accepted with a pointer to a status resource.
POST /reports
Location: /reports/jobs/789
Retry-After: 5
HTTP/1.1 202 Accepted
{ "id": "789", "status": "running", "progress": 0.4 }
The client polls the job URL, or you notify it via a webhook or server-sent events. When finished, the status resource either includes the result or links to it, and the job may transition to succeeded or failed with error details. Store jobs durably so a server restart does not lose them, and let polling use conditional requests and Retry-After to reduce load.
Design for idempotency: a retried POST should return the same job rather than starting a second one. Also give jobs a retention policy so the status store does not grow without bound, and consider cancellation endpoints for user-initiated work.
Frequently Asked Questions About REST API Design Interviews
What do hiring managers evaluate in REST API Design technical rounds?
Technical interviewers look for foundational fluency, idiomatic syntax, clarity when communicating complex logic, and awareness of performance trade-offs (e.g. memory footprint, render performance, and network latency) in production environments.
What are the best interview tips for practicing REST API Design questions?
Use active recall: summarize each answer in your own words before revealing the model solution. Focus on explaining why a certain approach is chosen rather than just memorizing code syntax.