skip to content

REST

The resource-oriented HTTP style most public APIs still use: modelling resources, treating verbs and status codes as the contract, statelessness, caching, and versioning. Interviewers ask because 'we built a REST API' is the default claim and they want to know how much of REST you actually applied.

part ofAPI stylesoverview, primer and where to startread it →
on this pageshow

explore

questions

120 · 9 sections

When designing URL paths for an HTTP API, what naming conventions do you follow, and why is POST /createUser considered worse than POST /users?

level: juniorimportance: must knowfreq 72%
basics
~10 s

Paths name things, not actions: nouns, usually plural collections (/users, /users/42/orders). The HTTP method supplies the verb, so POST /users beats POST /createUser. Verbs in paths duplicate the method and multiply near-identical endpoints.

open as a page

In an HTTP API, how do you decide whether a value belongs in a path segment such as /orders/{id} or in the query string such as ?status=open?

level: juniorimportance: must knowfreq 66%
basics
~20 s

Path carries identity and hierarchy — what resource you are addressing; it is required and usually part of a single thing's URL. Query carries modifiers on a collection — filtering, sorting, pagination, field selection; these are optional and any combination is valid.

open as a page

When designing an HTTP API, how do you decide between exposing a nested path like `/orders/{orderId}/items` and a top-level collection with a filter like `/items?orderId={orderId}`? What does each choice commit you to?

level: middleimportance: must knowfreq 60%
basics
~20 s

Nest when the child is owned by the parent, has no meaning or identity outside it, and is always accessed through it. Use a top-level collection with a filter when the child is independently identifiable and queried across parents. Many APIs do both: nested for creation and scoped listing, a canonical top-level URI for the item itself.

open as a page

When designing an HTTP API, how do you decide what becomes a resource? Explain why a resource is not simply a database table or a domain entity, and give an example where they differ.

level: middleimportance: must knowfreq 65%
basics
~20 s

A resource is anything worth naming with a URI and giving a representation — driven by what clients need to address, not by storage. Entities usually become resources, but resources also cover projections, computed views, and processes that no table matches, and one entity may back several resources.

open as a page

Your HTTP API needs to let a client cancel an order. Cancelling is not a plain create, read, update, or delete. How do you model it, and what are the options?

level: middleimportance: must knowfreq 62%
basics
~20 s

Three mainstream options: POST a state-transition sub-resource (POST /orders/{id}/cancellation), PATCH the status field, or an explicitly-marked custom method (POST /orders/{id}:cancel). Prefer the sub-resource when the action has its own data or history; keep POST for anything with side effects.

open as a page

In an HTTP API contract, what is the difference between a method being safe and being idempotent, and which of GET, POST, PUT, PATCH and DELETE are which?

level: juniorimportance: must knowfreq 70%
basics
~20 s

Safe means the request does not change server state - GET and HEAD. Idempotent means doing it N times leaves the same state as doing it once - GET, HEAD, PUT and DELETE. POST and PATCH are neither by default. Safe implies idempotent.

open as a page

When you design a write endpoint in an HTTP API, how do you choose between the PUT, PATCH and POST methods, and what does each one promise the client?

level: juniorimportance: must knowfreq 82%
basics
~20 s

POST creates a resource or runs a process; the server picks the URL and repeating it repeats the effect. PUT sends the complete new representation to a URL you already know; repeating it is harmless. PATCH sends only the fields to change.

open as a page

You are specifying the successful responses for create, update and delete endpoints in an HTTP API. How do you choose between status 200, 201 with a Location header, and 204, and when would you return a body at all?

level: juniorimportance: must knowfreq 74%
basics
~20 s

201 plus a Location header when the request created a new resource; 200 with a body when you have something useful to return; 204 when the operation succeeded and there is genuinely nothing to send. Deletes typically return 204.

open as a page

Why can a client safely retry an HTTP PUT or DELETE after a timeout, but not a bare POST? Explain what actually goes wrong.

level: middleimportance: must knowfreq 65%
basics
~20 s

A timeout hides whether the server applied the request. PUT and DELETE describe an end state, so reapplying converges to the same result. POST creates something new each time, so a retry after a lost response creates a duplicate.

open as a page

Your API lets clients create resources with HTTP PUT to a URL they choose, instead of POSTing to a collection. What does that buy you, what identifier scheme does it require, and what should the server return?

level: middleimportance: must knowfreq 62%
basics
~20 s

PUT-as-upsert makes creation idempotent: the client generates the id (usually a UUID), so a retried request lands on the same URL and cannot create a duplicate. Return 201 when it created, 200 or 204 when it replaced.

open as a page

A candidate says a REST API cannot be stateless because it stores orders in a database. Explain why that is wrong by distinguishing the two kinds of state involved.

level: juniorimportance: must knowfreq 72%
basics
~20 s

Two different things. Resource state is the durable data the API manages - orders, users - and storing it is the point of the API. Application state is per-client context between requests, like where you are in a flow. Statelessness forbids only the second.

open as a page

A REST API is described as stateless so that any instance can serve any request. Explain concretely what that means for load balancing and horizontal scaling, and what kinds of server-side data break the property.

level: middleimportance: must knowfreq 70%
basics
~20 s

Each request carries everything needed to process it, so no instance holds per-client memory. The load balancer can send any request to any instance and you scale by adding instances. Per-client data in one instance's local memory breaks it.

open as a page

Compare a self-contained signed token, such as a JWT whose claims the API validates locally, with an opaque token that the API must resolve by calling an introspection or lookup service. What does each cost at request time?

level: middleimportance: must knowfreq 68%
basics
~20 s

A self-contained token carries its claims and a signature, so the API validates it locally with no lookup: fast and dependency-free, but the claims are a snapshot valid until expiry. An opaque token is a random string the API must resolve remotely: always current and instantly revocable, at the cost of a call on every request.

open as a page

What does it mean for an HTTP request to be self-contained, and how would you redesign a paginated endpoint that currently relies on the server remembering which page each client last received?

level: middleimportance: should knowfreq 55%
basics
~20 s

Self-contained means the request carries everything needed to process it: credentials, target, and position. For pagination, put the position in the request - an offset or an opaque cursor the server returns to the client - instead of a server-held cursor.

open as a page

REST lists 'cacheable' as one of its architectural constraints. What does that constraint actually require of an API's responses, and which responses in a typical HTTP API can be cached at all?

level: juniorimportance: must knowfreq 48%
basics
~20 s

It requires every response to say, implicitly or explicitly, whether it may be reused and for how long. In practice GET and HEAD responses are the cacheable ones; POST responses only with explicit freshness; PUT, PATCH and DELETE responses are never cached.

open as a page

You are designing a JSON API and must decide, for each resource, whether responses carry an ETag validator, a Last-Modified date, both, or neither. How do you make that call?

level: middleimportance: must knowfreq 52%
basics
~20 s

Use an ETag when you have a cheap exact version (row version, sequence, content hash) or when changes can happen within the same second. Use Last-Modified when a meaningful modification time already exists and human readability or heuristic freshness helps. Emit both when free; emit neither for tiny or per-request-volatile responses.

open as a page

How do you choose a TTL for an HTTP API response — the number you put in Cache-Control: max-age or s-maxage — for resources that change at very different rates?

level: middleimportance: must knowfreq 55%
basics
~20 s

Pick the TTL from how stale the data may safely be, not from how often it changes. Volatile or personalised resources get seconds or no shared caching; stable reference data gets minutes to hours; immutable, uniquely-addressed content gets a year. Use s-maxage to give shared caches a different, usually longer, value.

open as a page

An API endpoint returns data that differs per authenticated user. What has to be true before any shared cache such as a CDN or reverse proxy may store that response, and how do you design so one user's data can never be served to another?

level: seniorimportance: must knowfreq 46%
basics
~20 s

A shared cache must not store an authenticated response unless the response explicitly permits shared storage. Safer than tuning directives: separate public resources from per-user ones, put the user identity in the URL path, and mark per-user responses as storable only by that user's own client.

open as a page

Reviewing a client integration, you notice every API call appends a unique query parameter such as ?_=1739382736 or ?nocache=<uuid>. What effect does that have on caches, and when is a changing URL the right tool rather than a mistake?

level: middleimportance: should knowfreq 36%
basics
~20 s

A unique parameter makes a unique cache key, so nothing is ever reused: hit rate is zero and every request reaches the origin. A changing URL is right only in the inverse case — content-addressed or versioned URLs that change when the content changes, allowing very long lifetimes.

open as a page

For a JSON REST API, which changes to a request or response are backward-compatible (additive) and which break existing clients? Give concrete examples.

level: juniorimportance: must knowfreq 68%
basics
~20 s

Additive: new endpoints, new response fields, new optional request parameters, relaxed validation. Breaking: removing or renaming a field, changing its type, units or format, making a parameter required, tightening validation, changing status codes or the error body shape.

open as a page

Compare the main ways to version an HTTP API — a version in the URI path such as /v1/orders, a query parameter, a custom request header, and media-type versioning via the Accept header. What are the trade-offs?

level: middleimportance: must knowfreq 70%
basics
~20 s

URI path versioning is the most visible, cacheable and easiest to route or test in a browser, but versions the whole API. Header and media-type versioning keep URIs stable and allow per-resource versions, at the cost of discoverability, tooling friction and cache correctness needing Vary.

open as a page

An HTTP API version has been switched off permanently. What status code should its endpoints return — 404, 410 Gone, 301, or something else — and what should the response body contain?

level: juniorimportance: should knowfreq 42%
basics
~20 s

Return 410 Gone: the resource existed and is intentionally, permanently removed. Include a machine-readable error body naming the version, the removal date and the replacement. Use 301/308 redirects only when the new endpoint is genuinely equivalent.

open as a page

What is a tolerant-reader client in the context of consuming a JSON HTTP API, and what concrete parsing rules does it follow so that additive server changes do not break it?

level: middleimportance: should knowfreq 48%
basics
~20 s

A tolerant reader ignores unknown fields, reads only what it needs, does not depend on field order, and handles unknown enum values with a default branch instead of failing. That lets the server add fields and values without redeploying clients.

open as a page

How do the HTTP `Deprecation` and `Sunset` response headers work, what do they carry, and how should a client and a provider each use them?

level: middleimportance: should knowfreq 40%
basics
~20 s

Sunset (RFC 8594) gives an HTTP-date after which the resource becomes unresponsive; Deprecation says it is already or will be deprecated. Pair them with Link rel="sunset" or rel="deprecation" to documentation. Clients should log and alert on them.

open as a page

An order resource returns a cancel link while the order is pending, and stops returning it once the order has shipped. What is the client supposed to gain from that, and what does the client still have to know on its own?

level: middleimportance: should knowfreq 42%
basics
~20 s

The response advertises the transitions currently available, so the server owns the state machine and the client renders whatever affordances it is given instead of reimplementing the rules. The client still needs to understand each relation's meaning and what payload it takes, and the server still enforces every rule itself.

open as a page

Describe how a HAL document (media type application/hal+json) is laid out. What do the reserved _links and _embedded properties hold, and what problem does _embedded solve?

level: middleimportance: should knowfreq 38%
basics
~20 s

A HAL resource is ordinary JSON plus two reserved keys. _links maps relation names to link objects with an href (optionally templated, type, title). _embedded maps relation names to full nested resources, so a client gets related data in one response instead of following every link.

open as a page

How is a JSON:API document (media type application/vnd.api+json) laid out - what goes in data, relationships and included - and what does that structure buy you over ad-hoc JSON?

level: middleimportance: should knowfreq 34%
basics
~20 s

Top level holds data, errors or meta. data is a resource object with type, id, attributes and relationships; relationships hold identifier objects (type plus id) and links; included carries the full related resources, deduplicated. It gives you a normalised graph plus fixed conventions for includes, sparse fields and paging.

open as a page

Walk through the four levels of the Richardson Maturity Model for HTTP APIs, from level 0 to level 3, with an example of what an API looks like at each level.

level: middleimportance: should knowfreq 45%
basics
~20 s

Level 0: one URL, one verb, the operation named in the body. Level 1: many resource URLs. Level 2: proper HTTP verbs and status codes per resource. Level 3: responses carry hypermedia links telling the client what it can do next.

open as a page

Design the query parameter that lets a client of a REST list endpoint sort by several fields at once, in either direction — for example newest first, then by name ascending. What syntax would you choose and why?

level: juniorimportance: must knowfreq 58%
basics
~10 s

Use one comma-separated sort parameter where order matters and a leading - means descending: sort=-created_at,name. Whitelist the allowed field names, define a default sort, and always append a unique tiebreaker such as the id.

open as a page

A REST list endpoint accepts a `limit` (or `size`) query parameter. What should the API do when a client omits it, sends `limit=0`, sends `limit=100000`, or sends something non-numeric?

level: juniorimportance: must knowfreq 52%
basics
~20 s

Omitted: apply a documented default (often 20-50) — never "everything". Over the maximum: either clamp to the max or return 400, but document which. Non-numeric or negative: 400. Echo the effective limit in the response so the client can see what actually applied.

open as a page

Plain `field=value` query parameters can only express equality. Compare the common ways a REST API expresses richer filter operators — bracket suffixes like `created_at[gte]=`, right-hand-side prefixes like `created_at=gte:`, and full expression languages such as RSQL/FIQL or OData `$filter` — and say which you'd pick.

level: middleimportance: must knowfreq 52%
basics
~20 s

Bracket suffixes (created_at[gte]=2024-01-01) and RHS prefixes (created_at=gte:2024-01-01) add per-field operators while keeping ordinary query parsing; RSQL/FIQL and OData $filter add a real expression language with AND/OR/grouping, at the cost of a parser, a validator, and unbounded query complexity. Start with the simple forms.

open as a page

Why is it a problem for an HTTP API to return stack traces, SQL fragments, framework class names or internal database identifiers in an error response body, and what do you return instead?

level: juniorimportance: must knowfreq 62%
basics
~20 s

Those details leak your internals to attackers — stack, framework versions, table names, ID ranges — and are useless to callers. Return a stable code, a safe message and a request id; keep the trace server-side in logs, keyed by that id.

open as a page

What is the application/problem+json media type defined by RFC 9457, and which members does a problem document define?

level: juniorimportance: must knowfreq 47%
basics
~20 s

It is a standard JSON format for HTTP error bodies, media type application/problem+json. Its members are type (a URI identifying the problem kind), title, status, detail and instance — all optional, plus your own extension members.

open as a page

What does the HTTP Retry-After response header mean, what value formats does it accept, and on which responses should an API send it?

level: juniorimportance: must knowfreq 58%
basics
~20 s

Retry-After tells the client how long to wait before trying again. It takes either delay seconds (Retry-After: 120) or an HTTP-date. Send it on 429 and 503, and on 3xx redirects that ask the client to wait.

open as a page

A client posts a JSON body to your REST API and several fields fail validation. How would you shape the response body so the caller can highlight the exact inputs that failed, rather than returning one human-readable sentence?

level: juniorimportance: must knowfreq 62%
basics
~20 s

Return an array of violations, one per failed field. Each entry carries a machine-readable code, a target naming the field, and a human message. Clients switch on the code and attach the message to the right input; a prose string cannot be parsed.

open as a page

What should the body of an HTTP API error response contain, and why do teams separate a stable machine-readable error code from the human-readable message?

level: middleimportance: must knowfreq 68%
basics
~20 s

An error body should carry a stable machine-readable code, a human message, and a request id for support. Clients branch on the code; the message is prose that can be reworded or localized without breaking any caller.

open as a page

What is the Idempotency-Key HTTP header pattern used by payment and other write APIs, who generates the key, and which requests should carry one?

level: juniorimportance: must knowfreq 58%
basics
~20 s

The client generates a unique key (usually a UUID) per logical operation and sends it as the Idempotency-Key request header. The server records the key with the result; if the same key arrives again it returns the stored response instead of re-executing. It makes retrying a POST safe.

open as a page

You are implementing support for the Idempotency-Key request header on a POST endpoint. What does the server store, and what is the request-handling flow for a first request versus a replay?

level: middleimportance: must knowfreq 55%
basics
~20 s

Store a row keyed by (scope, key) holding a fingerprint of the request, a state (in-progress / completed), and the saved status, headers and body. First request: insert the row, execute, save the response. Repeat: find the completed row and return the stored response without re-executing.

open as a page

Your HTTP client times out waiting for a response to a POST request. What do you actually know about whether the server applied it, and how should the client behave?

level: middleimportance: must knowfreq 56%
basics
~20 s

Almost nothing: a timeout means you lost the answer, not that the work did not happen. The request may have been fully applied. Retrying a non-idempotent POST can duplicate the effect, so either make the operation retry-safe first, or reconcile by querying before retrying.

open as a page

A client's write to your API is rejected with HTTP 412 because the version token it sent was stale. Walk through what the client should do next, and what the API has to provide for that step to be possible.

level: middleimportance: should knowfreq 40%
basics
~20 s

Re-read the resource to get current state and a fresh validator, reconcile the user's intended change against what actually changed, then resend with the new validator. Never blindly resend the same body with a refreshed token, and cap the retry loop.

open as a page

A client reuses the same Idempotency-Key HTTP header value but sends a different request body than the first time. How should the API respond, and how does the server detect this?

level: middleimportance: should knowfreq 42%
basics
~20 s

Reject it without executing anything. The server stores a fingerprint (hash of method, path and body) with each key and compares on every arrival; a mismatch means the client has a bug, so return an error — commonly 422 Unprocessable Content — rather than replaying or executing.

open as a page