HTTP Methods • Status Codes • Auth • Caching • API Design • 2026

REST API Interview Questions

30 questions What each one tests, an answer frame, a spoken answer 37 min read

This page is for backend, full-stack and integration developers facing a round on REST API design. Most rounds start with what REST really means, HTTP methods and status codes, then move to resource naming, PUT versus PATCH, pagination and versioning. Mid and senior rounds add authentication with API keys, OAuth 2 and JWTs, rate limiting, caching and ETags, a comparison with GraphQL and gRPC, and a live design exercise. Each question shows what the interviewer is really checking, the shape of a strong answer and a short answer you can say out loud. Practise saying them, then swap in your own projects.

Search all questions by round, difficulty and level, or save the ones you want to practise.

REST Basics 4 questions

Easy Technical round Fresher, Mid-level Practice question

1. People call almost any JSON-over-HTTP API a REST API. What actually makes an API RESTful?

What the interviewer is really testing:
Whether you know REST is an architectural style with specific constraints, not just 'JSON over HTTP', and can name them without reciting a textbook.
Answer frame:

Origin: an architectural style described by Roy Fielding, defined by a set of constraints.

Constraints: client-server, stateless, cacheable, uniform interface, layered system, and optional code on demand.

Uniform interface: resources named by URLs, changed through representations, self-descriptive messages, and links between resources.

Reality check: most real APIs follow some of this, which is fine if you know which parts you skipped.

Sample spoken answer:

"REST is an architectural style, not a protocol, and it's defined by constraints. The client and server are separate. Every request is stateless, so it carries everything the server needs. Responses say whether they can be cached. There's a uniform interface: everything is a resource with its own URL, you act on it with standard HTTP methods, and messages describe themselves through things like content types and status codes. The system can be layered, so a client doesn't care if there's a proxy or a CDN in the middle. Code on demand is the one optional constraint. In practice, most APIs people call REST use resources, methods and status codes properly but skip hypermedia links. I think that's fine, as long as you're honest that you're doing pragmatic REST and you're consistent about it."

Red flag to avoid:

Defining REST as 'an API that returns JSON' or confusing it with HTTP itself.

They may ask next:
  • Which of those constraints do most real-world APIs quietly skip?
  • Is an API that uses only POST for everything still RESTful?
Say it in 60 seconds
Medium Technical round Fresher, Mid-level Practice question

2. REST says the server should be stateless. Does that mean the server stores nothing at all? What does it really mean?

What the interviewer is really testing:
Whether you can separate session state from resource state, and see why statelessness makes horizontal scaling easy.
Answer frame:

Session state: the server keeps nothing about the client's conversation between requests.

Resource state: data in the database is fine; that's the whole point of the API.

Each request: carries its own credentials and context, such as a token and the IDs it needs.

Payoff: any instance behind a load balancer can serve any request, with no sticky sessions.

Sample spoken answer:

"It doesn't mean the server stores nothing. The database obviously holds orders, users and so on; that's resource state. What stateless means is that the server doesn't remember anything about the client's conversation between requests. So there's no 'the user is on step two of the wizard' kept in server memory. Every request has to carry what's needed to understand it: the access token, the resource ID, any filters. The big payoff is scaling. If each request stands alone, I can put ten instances behind a load balancer and any of them can answer any request, and if one dies, nobody loses a session. It also makes requests easier to cache, retry and debug, because you can read one request and know exactly what it asked for."

Red flag to avoid:

Saying a stateless API can't use a database, or that stateless simply means using JWTs.

They may ask next:
  • Is a server-side session cookie a violation of statelessness?
  • Where would you keep multi-step wizard progress if the server must stay stateless?
Say it in 60 seconds
Medium Technical round Mid-level, Senior Practice question

3. What is HATEOAS? Have you used it, and is it worth the effort in a typical API?

What the interviewer is really testing:
Whether you understand hypermedia as a REST constraint and can give a balanced, honest view of how much of it real APIs use.
Answer frame:

Idea: responses include links to related resources and the actions available right now.

Benefit: clients follow links instead of hard-coding URLs, and the server can change paths or hide actions.

Reality: few public APIs go all the way; most use it lightly, like pagination links and a Location header.

Formats: HAL and JSON:API are common conventions for putting links in JSON.

Sample spoken answer:

"HATEOAS stands for hypermedia as the engine of application state. The idea is that each response tells the client what it can do next, with links. So an order response includes a link to itself, to its customer and, only if it's still cancellable, a link to cancel it. The client follows links instead of building URLs by hand, so the server can change paths, and the client learns which actions are allowed without copying business rules. It's the top level of the Richardson Maturity Model. In practice, few APIs do it fully, because most clients are written against documentation and hard-code URLs anyway. What I do use are the cheap, high-value parts: next and previous links for pagination, a Location header after create, and sometimes an actions list so the UI knows which buttons to show."

Code:
{
  "id": 981,
  "status": "paid",
  "_links": {
    "self":     { "href": "/orders/981" },
    "customer": { "href": "/customers/42" },
    "cancel":   { "href": "/orders/981/cancellation", "method": "POST" }
  }
}
Red flag to avoid:

Dismissing it without knowing what it is, or claiming every REST API must implement it fully to be useful.

They may ask next:
  • What are the levels of the Richardson Maturity Model?
  • How could links help a mobile app you can't force users to update?
Say it in 60 seconds
Medium Technical round Mid-level, Senior Practice question

4. When would you choose REST, when GraphQL and when gRPC? Give me a concrete case for each.

What the interviewer is really testing:
Whether you choose API styles by consumer and trade-off rather than by fashion, and know the real costs of each.
Answer frame:

REST: resources over plain HTTP; simple, widely understood and friendly to HTTP caching; best for public APIs.

GraphQL: one endpoint where clients ask for exactly the fields they need; great for varied UIs, harder to cache and to protect.

gRPC: Protocol Buffers over HTTP/2 with generated clients and streaming; best for internal service-to-service calls.

Decide by: who the consumers are, how varied their data needs are, and your need for caching and speed.

Sample spoken answer:

"I decide by who's calling. For a public API used by partners I don't know, REST wins. Everyone understands it, any language can call it with plain HTTP, and CDNs and browsers cache GET responses for free. GraphQL fits when many different screens need different slices of connected data, like a mobile app and a web dashboard showing the same products in different ways. The client asks for exactly the fields it needs in one round trip. The costs are real, though: plain HTTP caching helps less, because queries usually go as POST to one endpoint, and you need query depth and cost limits and batching to avoid N+1 lookups. gRPC is what I'd use between internal services. It's contract-first with Protocol Buffers, generates typed clients, runs over HTTP/2 with streaming and is compact on the wire. Browsers can't call it directly; they need gRPC-Web and usually a proxy, so it's rarely public-facing."

Red flag to avoid:

Saying GraphQL replaces REST everywhere, or choosing gRPC for a public browser-facing API without mentioning the proxy it needs.

They may ask next:
  • How do you stop a single expensive GraphQL query from overloading the database?
  • Could you run REST for external clients and gRPC internally in the same system? What sits in between?
Say it in 60 seconds

HTTP Methods 3 questions

Easy Technical round Fresher, Mid-level Practice question

5. Which HTTP methods are safe and which are idempotent? Why should an API developer care about the difference?

What the interviewer is really testing:
Whether you know the method semantics exactly and connect them to retries, caching and crawlers rather than treating them as trivia.
Answer frame:

Safe: GET, HEAD, OPTIONS and TRACE; the client is not asking to change server state.

Idempotent: all safe methods plus PUT and DELETE; repeating the call leaves the same end state.

Neither guaranteed: POST, and PATCH unless the patch is written to be repeatable.

Why it matters: clients, proxies and libraries retry idempotent calls on a timeout; safe calls can be cached and prefetched.

Sample spoken answer:

"Safe means the request doesn't ask to change anything on the server: GET, HEAD and OPTIONS, plus TRACE, which you rarely see. Idempotent means sending it once or five times leaves the server in the same state. All safe methods are idempotent, and so are PUT and DELETE. If I PUT the same body twice, the resource ends up the same. If I DELETE twice, it's still gone, even though the second call might return 404. So idempotency is about the state, not the response code. POST isn't idempotent, and PATCH isn't guaranteed either, because a patch like 'add 10 to the balance' changes things every time. This matters because networks fail. When a client times out, it can safely retry an idempotent call, but retrying a POST might create a second order. And if a GET changes data, a crawler or a prefetching browser can trigger it by accident."

Red flag to avoid:

Saying idempotent means 'returns the same response every time', or listing POST as idempotent.

They may ask next:
  • The second DELETE returns 404 instead of 204. Does that break idempotency?
  • What goes wrong if a GET endpoint has side effects, like marking a message as read?
Say it in 60 seconds
Easy Technical round Fresher, Mid-level Practice question

6. What is the difference between PUT and PATCH? Show me what each request body would look like for updating a user's email.

What the interviewer is really testing:
Whether you know PUT replaces the whole representation, the risk of sending partial bodies with PUT, and the common PATCH formats.
Answer frame:

PUT: replaces the full resource with the body you send; fields you leave out are cleared or reset.

PATCH: sends only the changes; the server applies them to what exists.

PATCH formats: JSON Merge Patch sends a partial object; JSON Patch sends a list of operations.

Idempotency: PUT is idempotent; PATCH only if the change itself is repeatable.

Sample spoken answer:

"PUT means 'here is the whole resource, replace what you have with this'. So to change the email with PUT, I send the full user: name, email, phone, everything. If I leave out the phone, a correct PUT implementation clears it. PATCH means 'apply these changes'. With JSON Merge Patch I'd send just the email field, and setting a field to null removes it. With JSON Patch I'd send a list of operations, like replace the value at the path slash email. In practice PATCH is what most clients want for edits, because they don't have to fetch and resend the whole object, and two people editing different fields don't wipe each other out. PUT is always idempotent. PATCH is idempotent for a simple 'set email to this', but not for something like 'append to this list'."

Code:
PUT /users/42
Content-Type: application/json

{"name": "Asha Rao", "email": "asha@example.com", "phone": "555-0101"}

PATCH /users/42
Content-Type: application/merge-patch+json

{"email": "asha@example.com"}
Red flag to avoid:

Saying PUT is for create and PATCH is for update, or that the two are interchangeable.

They may ask next:
  • Your PUT endpoint ignores fields the client leaves out. Is that a bug?
  • How do you remove a field with JSON Merge Patch, and when would you prefer JSON Patch instead?
Say it in 60 seconds
Hard Technical round Mid-level, Senior Practice question

7. A mobile client calls POST /payments, times out and retries. Now the customer is charged twice. How do you make that endpoint safe to retry?

What the interviewer is really testing:
Whether you can make a non-idempotent operation retry-safe with idempotency keys, including the storage, concurrency and mismatch edge cases.
Answer frame:

Client key: the client generates a unique key per logical payment and sends it in a header on every retry.

Server record: store the key with a hash of the request and the final response; replay the stored response on a repeat.

Edge cases: same key with a different body is rejected; a repeat while the first is still running gets a conflict.

Atomic and bounded: save the key and the payment in one transaction or under a unique constraint, and expire keys after a set time.

Sample spoken answer:

"The root problem is that the client can't tell if the first request succeeded, so retrying POST is a gamble. I'd add an idempotency key. The client generates a random ID for this one payment attempt, say a UUID, and sends it in an Idempotency-Key header, reusing the same key on every retry. On the server, I store the key with a hash of the request body and, once done, the response. If the same key comes in again, I skip the charge and return the saved response. If the same key comes with a different body, that's a client bug, so I reject it. If the first request is still in flight, I return 409 so the client waits and retries. The key record and the payment must be written atomically, usually with a unique constraint, or two parallel retries can both slip through. Keys expire after a day or so."

Code:
POST /payments
Idempotency-Key: 5f0c2a8e-1b7d-4e39-9a61-2c4d8f7e3b10
Content-Type: application/json

{"order_id": "ord_981", "payment_method_id": "pm_7731"}
Red flag to avoid:

Suggesting you deduplicate by amount and time window, or that switching the method to PUT alone fixes it.

They may ask next:
  • Where do you store the keys, and what happens if that store is down?
  • Why must the client, not the server, generate the key?
  • How would you handle a retry that arrives after the key has expired?
Say it in 60 seconds

Status Codes & Errors 5 questions

Easy Technical round Fresher Practice question

8. Walk me through the HTTP status code classes and the specific codes you use most often in an API.

What the interviewer is really testing:
Whether you use status codes precisely, especially the success codes, instead of returning 200 or 500 for everything.
Answer frame:

Classes: 1xx informational, 2xx success, 3xx redirection, 4xx client error, 5xx server error.

Success: 200 OK, 201 Created with a Location header, 202 Accepted for async work, 204 No Content.

Client errors: 400, 401, 403, 404, 409, 422 and 429.

Server errors: 500 for bugs, 502 and 504 from gateways, 503 when overloaded or in maintenance.

Sample spoken answer:

"The first digit tells the client who's responsible. 2xx means it worked, 3xx means look somewhere else, 4xx means the client did something wrong and shouldn't resend the same request unchanged, apart from 429 after waiting, and 5xx means the server failed and a retry might work later. For success I use 200 for a normal read or update, 201 when something was created, with a Location header pointing to the new resource, 202 when I've accepted work that will finish later, and 204 when there's nothing to return, like after a delete. For client errors: 400 for a malformed request, 401 when you're not authenticated, 403 when you are but aren't allowed, 404 when it doesn't exist, 409 for a conflict with the current state, 422 for validation failures and 429 for rate limits. On the server side, 500 is a bug, and 502, 503 and 504 usually come from gateways or overload."

Red flag to avoid:

Returning 200 with an error message inside the body as the normal way to report failures.

They may ask next:
  • Why does it matter that 4xx and 5xx are separate when a client decides whether to retry?
  • When would you return 202 instead of 201?
Say it in 60 seconds
Easy Technical round Fresher, Mid-level Practice question

9. When do you return 401 and when do you return 403? Is there ever a reason to return 404 instead of either?

What the interviewer is really testing:
Whether you separate authentication from authorization and think about not leaking the existence of resources.
Answer frame:

401: no valid credentials; the client should log in or refresh its token. Sent with a WWW-Authenticate header.

403: the caller is known but not allowed to do this; logging in again won't help.

404 on purpose: when even revealing that a resource exists would leak information.

Sample spoken answer:

"401 is about who you are. The token is missing, expired or invalid, so the client should authenticate and try again. The name 'Unauthorized' is a bit misleading, because it really means unauthenticated, and the response should carry a WWW-Authenticate header. 403 is about what you're allowed to do. The server knows exactly who you are, and you still can't have it, so re-sending the same credentials won't help. A normal user calling an admin endpoint gets 403. The 404 case is about leaking information. If I'm user 7 and I request user 9's invoice, returning 403 confirms that invoice exists. For private resources, many APIs return 404 so an attacker can't probe which IDs are real. I pick one rule for the whole API and document it, so clients aren't guessing."

Red flag to avoid:

Using 401 and 403 interchangeably, or returning 403 for an expired token.

They may ask next:
  • A client's access token has expired. Which code do you send, and what should the client do next?
  • How would you log these so security can still tell a 403 from a real 404?
Say it in 60 seconds
Medium Technical round Fresher, Mid-level Practice question

10. A sign-up request has valid JSON, but the email is already registered and the password is too short. Which status codes fit, and why?

What the interviewer is really testing:
Whether you can reason about the fine line between 400, 409 and 422 and then choose one consistent rule for the API.
Answer frame:

400 Bad Request: the request itself is broken: unparseable JSON, wrong types, missing required fields.

422 Unprocessable Content: well-formed, but the values break business rules, like a short password.

409 Conflict: clashes with the current state of the server, like a duplicate email.

Consistency: pick a rule, document it, and return field-level details either way.

Sample spoken answer:

"I split it by what went wrong. If the body can't be parsed or a field has the wrong type, that's 400. Here the JSON is fine, so it's not really 400. A password that's too short is a validation failure: the request is well-formed but the content breaks a rule, and 422, now called Unprocessable Content, fits that well. The duplicate email is different. Nothing is wrong with the request on its own; it conflicts with what already exists, so 409 Conflict is the most accurate. If both problems happen at once, I'd usually return 422 with both field errors, because the client needs to fix the password anyway. Honestly, some teams use 400 for all of this, and that's acceptable. What matters more is one documented rule and an error body that says which field failed and why."

Red flag to avoid:

Returning 500 for validation errors, or 200 with a success flag set to false.

They may ask next:
  • Does telling the client the email is already registered create a security problem?
  • How would your error body look so a form can show the message next to the right field?
Say it in 60 seconds
Medium Technical round Mid-level, Senior Practice question

11. How would you design the error response body for an API used by several teams? What goes in it and what must never go in it?

What the interviewer is really testing:
Whether you design errors for both machines and humans, keep one shape everywhere, and avoid leaking internals.
Answer frame:

One shape: every endpoint returns the same structure; Problem Details from RFC 9457 is a ready standard.

For code: a stable machine-readable error code plus field-level details for validation.

For humans: a clear message and a request ID that support can search in the logs.

Never: stack traces, SQL, internal hostnames or which part of a login was wrong.

Sample spoken answer:

"First, one shape for every error across the whole API, so clients write one handler. I'd lean on Problem Details, which is an RFC, served as application/problem+json. It gives you type, title, status, detail and instance, and you can add your own fields. I add a stable error code like 'card_declined' that clients can switch on, because messages get reworded but codes shouldn't change. For validation, a list of field errors with the field path and reason. And a request ID, which is the same one in our logs, so when a partner emails support we find the exact request in seconds. What never goes in: stack traces, database errors, server names or file paths. That's free reconnaissance for an attacker. And for login, I say 'email or password is wrong', not which one."

Code:
HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json

{
  "type": "https://api.example.com/errors/validation",
  "title": "Some fields are not valid",
  "status": 422,
  "code": "validation_failed",
  "errors": [{"field": "password", "reason": "too_short"}],
  "request_id": "req_7f3a91"
}
Red flag to avoid:

Letting each endpoint return its own error format, or passing raw exception messages straight to the client.

They may ask next:
  • Should the human-readable message be translated for the end user, or is that the client's job?
  • How do you stop one team from inventing its own error format?
Say it in 60 seconds
Medium Situational round Fresher, Mid-level, Senior Practice question

12. Your tech lead wants every API response to return 200 with a success flag in the body, errors included, to 'keep the frontend simple'. How do you respond?

What the interviewer is really testing:
Whether you can disagree respectfully with concrete technical costs and offer a compromise that still meets the lead's real goal.
Answer frame:

Acknowledge the goal: one simple way for the frontend to handle every response is reasonable.

Concrete costs: caches may store errors as success, monitoring on 5xx rates goes blind, and client libraries and retries rely on status codes.

Compromise: proper status codes plus one consistent error body, and a small shared client wrapper.

Decide together: agree, document, and move on, whichever way it goes.

Sample spoken answer:

"I'd start by agreeing with the goal. The frontend should handle every response one way. Then I'd show what we lose with always-200. Our dashboards and alerts count 5xx rates, so a broken endpoint would look perfectly healthy. A CDN or proxy might cache an error as a good response. Retry logic, HTTP client libraries and the partner teams who'll call this API all expect status codes to mean something, so they'd each have to parse bodies to detect failures. Then I'd offer a compromise that meets his aim: real status codes, plus one error body shape used everywhere, and a small shared fetch wrapper on the frontend that turns any non-2xx into the same error object. The frontend code stays just as simple. If he still prefers his approach after hearing that, I'd ask for it in writing as a team standard, so it's applied consistently."

Red flag to avoid:

Either caving without mentioning the monitoring and caching costs, or dismissing the lead's concern as simply wrong.

They may ask next:
  • What if the frontend team says the wrapper is extra work they don't have time for?
  • Are there cases where returning 200 with partial errors in the body is legitimate?
Say it in 60 seconds

Resource Design 6 questions

Easy Technical round Fresher Practice question

13. What rules do you follow when naming REST endpoints? Fix this one for me: GET /getOrdersForUser?id=42.

What the interviewer is really testing:
Whether you model URLs as nouns for resources and let the HTTP method carry the verb.
Answer frame:

Nouns, not verbs: the method says the action; the URL names the thing.

Plural collections: /orders for the list, /orders/981 for one item.

Relationships: nest one level for ownership, /users/42/orders; avoid deep chains.

Style: lowercase, hyphens in multi-word names, filters in the query string.

Sample spoken answer:

"The URL should name a resource, and the HTTP method should be the verb. So 'get' in the path is redundant, because GET already says that. Collections are plural nouns: /orders is the list, /orders/981 is one order. For orders that belong to a user, I'd write GET /users/42/orders, which reads naturally and makes the relationship clear. Or, if orders are also fetched in other ways, GET /orders?user_id=42 works well and keeps the API flatter. I keep nesting to one level, because /users/42/orders/981/items/3 gets painful fast, and the item usually has its own ID anyway. Other habits: lowercase, hyphens for multi-word names like /shipping-addresses, no file extensions, and whatever casing I pick for JSON fields, I use it everywhere."

Red flag to avoid:

Keeping verbs in the path, like /createUser and /deleteUser, and using POST for all of them.

They may ask next:
  • When would you choose /orders?user_id=42 over /users/42/orders?
  • How would you name an endpoint that searches across several resource types?
Say it in 60 seconds
Medium Technical round Mid-level, Senior Practice question

14. Not everything is CRUD. How would you model actions like cancelling an order or sending a password reset email in a REST API?

What the interviewer is really testing:
Whether you can map real business operations onto resources sensibly, and know when a pragmatic action endpoint is acceptable.
Answer frame:

State change: if the action is a status change, PATCH the resource's status field.

Noun the action: create a resource that represents it, like POST /password-resets.

Action sub-resource: POST /orders/981/cancel is a common, readable compromise.

Choose by rules: if the action has its own data, rules or history, it deserves its own resource.

Sample spoken answer:

"I first ask whether the action is really just a state change. Cancelling might be PATCH /orders/981 with status set to cancelled. That's clean if cancelling is simple. But usually it isn't: there's a reason, a refund, maybe a rule that shipped orders can't be cancelled. Then I turn the action into a noun: POST /orders/981/cancellation creates a cancellation record, which can carry the reason and the refund status and be fetched later. The password reset is a great example of this. POST /password-resets with the email creates a reset request, and it returns 202 whether or not the email exists, so it doesn't leak who has an account. I'm also fine with POST /orders/981/cancel. Plenty of mature APIs do this, it's clear to read, and it beats forcing an awkward model just for purity."

Red flag to avoid:

Using GET for an action because it's easy to click, or insisting there's no RESTful way to express actions at all.

They may ask next:
  • Why should the password reset endpoint answer the same way for an unknown email?
  • What status code would you return if someone tries to cancel an order that has already shipped?
Say it in 60 seconds
Medium Technical round Mid-level, Senior Practice question

15. How would you paginate a list endpoint? Compare offset pagination with cursor pagination and tell me when each one breaks.

What the interviewer is really testing:
Whether you understand the performance and consistency problems of deep offsets, and how cursor or keyset pagination solves them.
Answer frame:

Offset and limit: simple and lets users jump to page 40, but the database still reads and throws away skipped rows.

Drift: new or deleted rows shift pages, so items get duplicated or skipped between requests.

Cursor: an opaque token holding the last sort key plus an ID tie-breaker; the next query continues after it.

Always: a default and maximum page size, and a next link or cursor in the response.

Sample spoken answer:

"Offset pagination is limit 20, offset 400. It's easy to build, and users can jump to any page. It breaks in two ways. Deep pages get slow, because the database reads and discards all the skipped rows. And if someone inserts a row while I'm paging, everything shifts, so I see an item twice or miss one. Cursor pagination fixes both. I sort by something stable, say created time plus the ID as a tie-breaker, and the cursor encodes the last values I returned. The next query asks for rows after that point, which an index answers quickly at any depth, and inserts don't shift anything. The trade-off is no jumping to page 40, and total counts need a separate, often expensive, query. For feeds, logs and big tables I use cursors. For a small admin table with page numbers, offset is fine."

Code:
-- Next page after the last row the client saw
SELECT id, created_at, total
FROM orders
WHERE (created_at, id) < ('2026-09-01 10:15:00', 981)
ORDER BY created_at DESC, id DESC
LIMIT 20;
Red flag to avoid:

Returning the whole collection with no limit, or not knowing why large offsets get slow.

They may ask next:
  • Why do you need the ID as a tie-breaker in the cursor?
  • Should the cursor be readable by the client, or opaque? Why?
  • How would you give a total count without making every page request slow?
Say it in 60 seconds
Easy Technical round Fresher, Mid-level Practice question

16. How would you let clients filter, sort and choose fields on a list endpoint without the query string turning into a mess?

What the interviewer is really testing:
Whether you design a consistent query-string convention and protect the database with allow-lists and limits.
Answer frame:

Filters: plain query parameters named after fields, with a clear pattern for ranges.

Sorting: one sort parameter, comma-separated fields, a minus sign for descending.

Fields: an optional fields parameter so clients fetch only what they show.

Guard rails: allow-list what can be filtered and sorted, validate values, and cap the page size.

Sample spoken answer:

"I keep it boring and consistent. Filters are just query parameters named after the fields: status=shipped, customer_id=42. For ranges I use a clear suffix pattern like created_after and created_before, and I use the same pattern on every endpoint. Sorting is one parameter, sort=-created_at,total, where the minus means descending. If payloads are big, a fields parameter lets a mobile client ask for just id, name and price. The important part is the guard rails. I only allow filtering and sorting on fields I've listed, usually ones with an index, because sorting a huge table on an unindexed column can take the database down. I validate every value and return 400 with a clear message for an unknown filter, instead of silently ignoring it. And list endpoints always have a default page size and a maximum."

Code:
GET /orders?status=shipped&created_after=2026-09-01&sort=-created_at,total&fields=id,status,total&limit=50
Red flag to avoid:

Passing sort or filter fields from the query string straight into SQL.

They may ask next:
  • Should an unknown filter parameter be ignored or rejected? Why?
  • When does filtering get complex enough that you'd add a search endpoint instead?
Say it in 60 seconds
Hard System design round Mid-level, Senior Practice question

17. Design a REST API for booking meeting rooms: list rooms, check availability, book, change and cancel. Talk me through resources, endpoints and status codes.

What the interviewer is really testing:
Whether you can turn a feature into clean resources, pick the right methods and codes, and spot the real hard part: double bookings under concurrency.
Answer frame:

Resources: rooms and bookings; availability as a query on rooms rather than a separate stored thing.

Endpoints: list and filter rooms, create a booking with 201 and Location, read, update with If-Match, cancel.

Hard part: overlapping bookings return 409, enforced in the database, not just by a check before insert.

Details: times in ISO 8601 with an offset, pagination on lists, only the owner or an admin may change a booking.

Sample spoken answer:

"I'd start with two resources, rooms and bookings. GET /rooms lists rooms, with filters like min_capacity, and available_from and available_to, so the client can ask which rooms are free in a slot. GET /rooms/12 returns one room. POST /bookings takes a room ID, start, end and title, and returns 201 with a Location header. GET /bookings lets me filter by room or date range, paginated. PATCH /bookings/340 changes the time, with If-Match to avoid lost updates. For cancel, I'd set status to cancelled rather than delete, so history is kept. The hard part is two people booking the same slot at once. Checking for overlap and then inserting isn't enough under concurrency, so the database itself has to enforce it, for example with an exclusion constraint on room and time range, and the loser gets 409 with the clashing booking. All times go in ISO 8601 with an offset, stored in UTC."

Code:
GET    /rooms?min_capacity=6&available_from=2026-10-01T09:00:00Z&available_to=2026-10-01T10:00:00Z
GET    /rooms/12
POST   /bookings            -> 201 Created, Location: /bookings/340 | 409 if the slot is taken
GET    /bookings?room_id=12&from=2026-10-01&to=2026-10-07&limit=50
GET    /bookings/340
PATCH  /bookings/340        (If-Match) -> 200 | 409 overlap | 412 stale
PATCH  /bookings/340        {"status": "cancelled"} -> 200
Red flag to avoid:

Checking availability in application code and then inserting, with nothing in the database to stop a race.

They may ask next:
  • How would you support recurring bookings, like every Monday at ten?
  • Two requests for the same slot arrive at once. What exactly stops both from succeeding?
  • How would you tell other clients that a booking changed, without them polling?
Say it in 60 seconds
Medium Situational round Mid-level, Senior Practice question

18. A frontend developer asks you for one endpoint that returns everything the app's home screen needs in a single call. Do you build it?

What the interviewer is really testing:
Whether you balance clean resource design against real client performance and know the options, like a backend-for-frontend or expand parameters.
Answer frame:

Understand why: round trips on a slow mobile network are a real cost, not laziness.

Options: an expand or include parameter on existing resources, or a composite endpoint owned for that screen.

Where it lives: a backend-for-frontend layer keeps screen-shaped endpoints out of the core resource API.

Guard: clear ownership, caching and limits so it doesn't become a slow catch-all.

Sample spoken answer:

"Probably yes, but I'd first ask why and where it should live. If the home screen makes six calls on a slow mobile network, that's real latency, so the request is fair. My first option is an expand parameter, so GET /users/me?expand=recent_orders,notifications pulls related data in one call without inventing new resources. If the screen needs data from many unrelated places, I'd rather build a small backend-for-frontend endpoint owned for that app, something like GET /mobile/home, which calls the core APIs server-side and shapes the response. That keeps the public resource API clean while the app gets its single call. I'd make sure it's cached where it can be, has a timeout on each internal call so one slow part doesn't block the whole screen, and has an owner. If every screen starts needing this, that's the point to consider GraphQL."

Red flag to avoid:

Refusing because 'that isn't RESTful' without weighing the latency, or bolting screen logic into the core resource endpoints.

They may ask next:
  • What happens to this endpoint when the home screen is redesigned?
  • One of the six internal calls is slow. Do you fail the whole response or return partial data?
Say it in 60 seconds

Versioning & Docs 3 questions

Medium Technical round Mid-level, Senior Practice question

19. How do you version a REST API? Compare putting the version in the URL with putting it in a header, and tell me what counts as a breaking change.

What the interviewer is really testing:
Whether you know the versioning options and, more importantly, that most changes should be additive and not need a new version at all.
Answer frame:

URL version: /v1/orders is visible, easy to route and test in a browser, but coarse.

Header or media type: keeps URLs clean and allows finer control, but is harder to see and cache correctly.

Breaking: removing or renaming a field, changing a type or meaning, adding a required input, changing status codes.

Non-breaking: new optional fields, new endpoints, new optional parameters, if clients ignore unknown fields.

Sample spoken answer:

"The common options are the URL, like /v1/orders, or a header, either a custom one or a version inside the Accept media type. URL versioning is the most popular because it's obvious: you see it in logs, you can route on it at the gateway, and you can try it in a browser. Header versioning keeps URLs stable and lets you version more finely, but it's invisible, easy to forget, and caches need a Vary header to handle it. More important than where is when. I only bump a major version for breaking changes: removing or renaming a field, changing a type, making an optional input required, or changing what a status code means. Adding a new optional field or a new endpoint isn't breaking, as long as clients are told to ignore fields they don't recognise. Good design means versions are rare."

Red flag to avoid:

Bumping the version on every release, or claiming renaming a field is safe because 'it's the same data'.

They may ask next:
  • Is adding a new value to an enum field a breaking change?
  • How long would you keep v1 running once v2 ships?
Say it in 60 seconds
Easy Technical round Fresher, Mid-level Practice question

20. How do you document a REST API so other teams can use it without asking you? Where does OpenAPI fit in?

What the interviewer is really testing:
Whether you treat the API contract as a real artefact that drives docs, tests and clients, not a wiki page that goes stale.
Answer frame:

OpenAPI: a YAML or JSON description of paths, parameters, schemas, responses and auth; formerly the Swagger spec.

Design-first or code-first: write the spec before coding for review, or generate it from annotated code.

Uses: interactive docs, generated client SDKs, mock servers and contract tests in CI.

Beyond the spec: a getting-started guide, auth steps, real examples and an error catalogue.

Sample spoken answer:

"I treat the OpenAPI document as the source of truth. It's a YAML or JSON file that describes every path, its parameters, request and response schemas, status codes and how auth works. It used to be called the Swagger specification. I prefer design-first for anything shared: we write the spec, other teams review it before code exists, and they can even build against a mock server generated from it. From the same file we get interactive docs, typed client SDKs and contract tests in CI that fail if the code drifts from the spec. But a spec alone isn't enough documentation. People also need a short getting-started page, how to get a token, working examples for common tasks, and a list of error codes with what to do about each one. If a new developer can make their first successful call in a few minutes, the docs are working."

Code:
openapi: 3.1.0
info:
  title: Bookings API
  version: 1.0.0
paths:
  /bookings/{bookingId}:
    get:
      summary: Get one booking
      parameters:
        - name: bookingId
          in: path
          required: true
          schema:
            type: string
      responses:
        '200':
          description: The booking
        '404':
          description: No booking with that ID
Red flag to avoid:

Saying the docs are a hand-written wiki page updated 'when we get time'.

They may ask next:
  • How do you stop the spec and the code drifting apart?
  • What are the pros and cons of generating the spec from code annotations?
Say it in 60 seconds
Hard Situational round Mid-level, Senior Practice question

21. Product wants to remove a field from a response, but partners you can't see may still depend on it. How do you handle it?

What the interviewer is really testing:
Whether you run a deprecation properly with data, communication and a timeline instead of either refusing forever or breaking clients.
Answer frame:

Measure: find who still reads or sends the field, through logs per API key or client.

Signal: mark it deprecated in the OpenAPI spec and changelog, and send Deprecation and Sunset headers.

Talk: email the known consumers with a date and a migration path.

Remove safely: only after the date and near-zero usage, or in a new major version.

Sample spoken answer:

"I wouldn't just remove it, and I wouldn't refuse either. First, I'd find out who actually uses it. If our logs record calls per API key, I can see which partners still hit endpoints returning that field, and if clients send it back in requests, I can count that too. Next, I'd mark it deprecated in the OpenAPI spec and the changelog, and add Deprecation and Sunset headers to responses so anyone watching their traffic gets a machine-readable warning. Then I'd contact the known partners directly with the date and what to use instead. I'd set a realistic window, usually a few months for external partners. As the date nears, I check usage again and chase anyone left. If a big partner truly can't move, the field stays until the next major version. The goal is that nobody finds out by their integration breaking."

Red flag to avoid:

Removing the field in a normal release and waiting to see who complains.

They may ask next:
  • How would you run a brown-out test before the final removal?
  • What if product says the field exposes data that must stop being returned right away?
Say it in 60 seconds

Security & Auth 3 questions

Medium Technical round Fresher, Mid-level Practice question

22. API keys, OAuth 2 and JWTs often get mentioned in the same breath. How are they different, and when would you use each?

What the interviewer is really testing:
Whether you know these solve different problems: a JWT is a token format, OAuth 2 is a delegation framework, and an API key identifies a calling application.
Answer frame:

API key: a long-lived secret that identifies the calling app or project; simple, good for server-to-server.

OAuth 2: a framework for getting scoped, expiring access tokens, often for acting on a user's behalf.

JWT: a signed token format; it can be an OAuth access token, but it isn't a login protocol.

Pick by caller: backend partner, key; third-party app acting for a user, OAuth; your own services, short-lived tokens.

Sample spoken answer:

"They're not three competing options; they sit at different levels. An API key is a secret string that says which application is calling. It's simple and fine for server-to-server use, like a partner's backend calling our pricing API, but it usually doesn't say which user, and it lives a long time, so it needs rotation. OAuth 2 is a framework for getting access tokens, especially when a third-party app wants to act on a user's behalf without ever seeing their password. The user approves specific scopes, and the app gets a short-lived token. A JWT is just a format for a token: signed JSON with claims like who, which audience and when it expires. OAuth servers often issue access tokens as JWTs, so the two work together. So I'd pick based on who's calling and whether a user is involved."

Red flag to avoid:

Treating JWT and OAuth 2 as alternatives, or saying an API key alone identifies the end user.

They may ask next:
  • Where should a partner store an API key, and how would you let them rotate it without downtime?
  • Why shouldn't a mobile app use a single shared API key for all its users?
Say it in 60 seconds
Hard Technical round Mid-level, Senior Practice question

23. Walk me through the OAuth 2 authorization code flow with PKCE. What problem does PKCE solve?

What the interviewer is really testing:
Whether you can explain the redirect dance step by step and understand the code interception attack PKCE prevents.
Answer frame:

Start: the client makes a random code verifier, hashes it into a code challenge, and redirects the user to the authorization server with it and a state value.

Consent: the user logs in and approves scopes; the browser comes back to the redirect URI with a short-lived code.

Exchange: the client checks the state, then sends the code plus the original verifier to the token endpoint.

Why PKCE: a stolen code is useless without the verifier, which never went through the browser redirect.

Sample spoken answer:

"The client, say a mobile app, first generates a random secret called the code verifier and hashes it with SHA-256 to get the code challenge. It sends the user to the authorization server's authorize endpoint with its client ID, redirect URI, scopes, a random state value and that challenge. The user logs in there, not in the app, and approves the scopes. The server redirects back with a one-time authorization code. The app checks the state matches, to block forged callbacks, then calls the token endpoint with the code and the original verifier. The server hashes the verifier, compares it to the challenge it saw earlier, and only then issues an access token and usually a refresh token. PKCE exists because codes can be intercepted, for example by another app registered for the same redirect scheme. Without the verifier, a stolen code can't be exchanged. Current guidance is to use PKCE for every client type."

Red flag to avoid:

Having the app collect the user's password and send it to the API, or thinking PKCE replaces HTTPS.

They may ask next:
  • What is the state parameter protecting against, and how is that different from what PKCE protects?
  • Why is the old implicit flow discouraged now?
  • Where should a single-page app keep its tokens?
Say it in 60 seconds
Medium Technical round Mid-level, Senior Practice question

24. Your API receives a JWT as a bearer token. What exactly should the API check before trusting it, and why is revoking one hard?

What the interviewer is really testing:
Whether you know a JWT is signed, not encrypted, which claims to validate, and the revocation trade-off of self-contained tokens.
Answer frame:

Structure: header, payload and signature, base64url-encoded; anyone can read the payload.

Checks: signature with an expected algorithm and trusted key, then expiry, not-before, issuer and audience.

Then authorize: scopes or roles in the claims decide what the caller may do on this endpoint.

Revocation: the token is valid until it expires, so keep access tokens short and use refresh tokens or a denylist.

Sample spoken answer:

"A JWT has three parts: a header, a payload of claims and a signature. The payload is only encoded, not encrypted, so I never put secrets in it. Before trusting it, I verify the signature with the issuer's key, and I pin the algorithm I expect. I never let the token's own header choose it, and I reject 'none'. Then I check exp so it hasn't expired, nbf if it's set, iss so it came from our auth server, and aud so it was issued for this API and not some other service. Only then do I look at scopes or roles to decide if this caller can hit this endpoint. Revocation is the catch. The API doesn't call anyone to check, so a stolen token works until it expires. That's why access tokens are short-lived, with refresh tokens that can be revoked, and a denylist by token ID for emergencies."

Red flag to avoid:

Decoding the token and trusting the claims without verifying the signature, or storing sensitive data in the payload.

They may ask next:
  • What is the risk if your API skips the audience check?
  • How do you rotate the signing keys without logging everyone out?
Say it in 60 seconds

Caching & Limits 3 questions

Hard Technical round Mid-level, Senior Practice question

25. How would you add rate limiting to a public API that runs on several servers? Which algorithm, what do clients see, and where does the counter live?

What the interviewer is really testing:
Whether you can pick an algorithm, share state across instances, communicate limits clearly and decide what happens when the limiter itself fails.
Answer frame:

Who: limit per API key or user, with an IP limit for anonymous traffic; different limits for costly endpoints.

Algorithm: token bucket allows short bursts and a steady rate; fixed windows allow double bursts at the boundary.

Shared counter: a fast shared store with atomic updates so every instance sees the same count.

Client view: 429 Too Many Requests with Retry-After and headers showing the limit and what's left.

Sample spoken answer:

"First, who am I limiting? Usually the API key or user, with a per-IP limit for unauthenticated calls, and tighter limits on expensive endpoints like search or exports. For the algorithm I like a token bucket. Each client has a bucket that refills at a steady rate and has a maximum size, so short bursts are fine but sustained floods get cut off. A simple fixed window per minute is easier, but a client can send double the limit across the boundary. Because we run several servers, the counters can't live in each server's memory. I'd keep them in a shared in-memory store like Redis, updated atomically. When a client is over, they get 429 with a Retry-After header, plus headers for the limit and how many calls remain, so well-behaved clients slow down. And I decide upfront whether to fail open or closed if the store goes down."

Code:
import time

class TokenBucket:
    def __init__(self, capacity, refill_per_sec):
        self.capacity = capacity
        self.tokens = capacity
        self.refill = refill_per_sec
        self.last = time.monotonic()

    def allow(self):
        now = time.monotonic()
        self.tokens = min(self.capacity, self.tokens + (now - self.last) * self.refill)
        self.last = now
        if self.tokens >= 1:
            self.tokens -= 1
            return True
        return False
Red flag to avoid:

Keeping counters only in each server's memory behind a load balancer, or returning 500 or 403 for rate-limited calls.

They may ask next:
  • If the shared store goes down, do you let all traffic through or block it? Why?
  • How would you stop one noisy customer from hurting everyone else on a shared plan?
  • Should rate limiting live in the gateway or in the application?
Say it in 60 seconds
Medium Technical round Fresher, Mid-level Practice question

26. How do you use Cache-Control on API responses? What is the difference between no-cache and no-store?

What the interviewer is really testing:
Whether you can use HTTP caching deliberately, and especially that you won't let a shared cache serve one user's private data to another.
Answer frame:

Freshness: max-age says how many seconds a response can be reused without asking the server.

Who may cache: public allows shared caches like CDNs; private allows only the user's own client.

no-cache vs no-store: no-cache may be stored but must be revalidated before every use; no-store must not be stored at all.

Vary: tells caches which request headers change the response.

Sample spoken answer:

"Cache-Control tells browsers, CDNs and proxies what they may do with a response. max-age sets how many seconds it stays fresh. So a product catalogue that changes hourly might get public, max-age of 300, and a CDN can answer most requests without touching my servers. public versus private is about who can store it. Anything user-specific, like 'my orders', is private, so only that user's client caches it, never a shared cache that could hand it to someone else. The names no-cache and no-store confuse people. no-cache means you can store it but must check with the server before reusing it, usually with an ETag. no-store means don't keep it anywhere, which I use for sensitive data like account details or tokens. And if the response depends on a header, like Accept-Language, I send Vary so caches keep separate copies."

Red flag to avoid:

Thinking no-cache means 'never cache', or marking personalised responses as public.

They may ask next:
  • A user sees another user's data after you put a CDN in front of the API. What went wrong?
  • Why are POST responses rarely cached in practice?
Say it in 60 seconds
Hard Technical round Mid-level, Senior Practice question

27. What is an ETag? Show me how you'd use it both to save bandwidth and to stop two users from overwriting each other's edits.

What the interviewer is really testing:
Whether you know both uses of conditional requests: revalidation with If-None-Match and optimistic concurrency with If-Match.
Answer frame:

ETag: an identifier for one version of a resource's representation, sent in a response header.

Save bandwidth: the client sends If-None-Match; if nothing changed, the server replies 304 Not Modified with no body.

Lost updates: the client sends If-Match on PUT or PATCH; if the resource changed, the server replies 412 Precondition Failed.

Strong vs weak: If-Match needs a strong ETag; weak ones marked W/ are for 'close enough' caching.

Sample spoken answer:

"An ETag is a version tag for a resource, like a hash of the content or a version number, sent in a response header. It has two big uses. First, caching. When the client already has a copy, it sends If-None-Match with the ETag it holds. If nothing changed, I return 304 Not Modified with an empty body, and the client reuses its copy. That saves bandwidth, though the server still does the lookup. Second, and this is the one people forget, it prevents lost updates. Two people open the same document at version 17. The first saves with If-Match 17, which succeeds, and the version becomes 18. The second saves with If-Match 17, and I return 412 Precondition Failed instead of silently overwriting. Their client refetches and merges. I can even require If-Match on updates and return 428 when it's missing. That's optimistic locking, over plain HTTP."

Code:
GET /documents/55            -> 200, ETag: "v17"
GET /documents/55
If-None-Match: "v17"         -> 304 Not Modified (no body)

PATCH /documents/55
If-Match: "v17"              -> 200, ETag: "v18"
PATCH /documents/55
If-Match: "v17"              -> 412 Precondition Failed
Red flag to avoid:

Only knowing ETags as a browser cache feature, with no idea they can guard concurrent updates.

They may ask next:
  • How would you generate the ETag cheaply without hashing a large response on every request?
  • What should the client do after it gets a 412?
Say it in 60 seconds

Real Work 3 questions

Medium Behavioral round Mid-level, Senior Practice question

28. Tell me about an API you designed that other teams or external clients depended on. What would you design differently now?

What the interviewer is really testing:
Whether you've owned an API contract with real consumers and can reflect honestly on design decisions that aged badly.
Answer frame:

Context: what the API did, who used it and roughly how much.

Decisions: two or three design choices you made and why, like pagination, errors or auth.

Hindsight: one choice that hurt later, what it cost consumers, and what you'd do instead.

Lesson: the habit you carry into every API since.

Sample spoken answer:

"At my last company I designed the internal API that our billing, support and reporting teams used to read customer accounts. I made a few choices I'm still happy with: cursor pagination from day one, one error format with stable codes, and an OpenAPI spec reviewed by all three teams before we wrote code. What I'd change is how I modelled status. I exposed account status as a free-text string that mirrored our database. When we added two new statuses, the reporting team's dashboards broke, because they'd hard-coded the list. The API was technically unchanged, but for them it was a breaking change. Now I document enums as open lists that clients must expect to grow, give them a safe default for unknown values, and announce new values in a changelog before they ship. I learned that a contract includes meaning, not just field names."

Red flag to avoid:

A story with no real consumers, or a hindsight answer that blames the other teams for 'using it wrong'.

They may ask next:
  • How did you find out the reporting team was affected?
  • How do you gather requirements from consumers before the API exists?
Say it in 60 seconds
Hard Behavioral round Mid-level, Senior Practice question

29. Tell me about a time a change to an API broke a client in production. What happened, how did you fix it, and what did you put in place afterwards?

What the interviewer is really testing:
Whether you take ownership of an incident, restore service quickly, and add process or tooling so the same class of break can't recur.
Answer frame:

What broke: the change, why it seemed safe, and how it surfaced.

Response: how you confirmed the cause and restored the client, usually by rolling back first.

Root cause: why your checks didn't catch it.

Prevention: contract tests, spec diffs in CI, usage metrics or a deprecation process.

Sample spoken answer:

"In a previous role we changed a price field in our orders API from a number to a string, to avoid rounding issues. We thought it was internal-only. Within an hour, a partner's warehouse integration stopped importing orders, because their parser expected a number. Support spotted it through a spike in the partner's failed calls in our logs. I rolled back the deploy first, which restored them in about twenty minutes, and then called their developer to confirm. The root cause was that we had no view of who used which fields, and no check that flagged a type change. Afterwards, I added an OpenAPI diff step in CI that fails the build on breaking changes unless someone approves it, and we started logging which API keys called which endpoints. The price change came back later as a new field alongside the old one, with a deprecation date."

Red flag to avoid:

Blaming the partner for fragile code, or skipping straight to a fix without restoring the client first.

They may ask next:
  • Why did you roll back before investigating further?
  • What does your CI check consider a breaking change?
Say it in 60 seconds
Medium Behavioral round Fresher, Mid-level, Senior Practice question

30. Tell me about integrating with a third-party REST API that was slow, flaky or badly documented. How did you make your side reliable?

What the interviewer is really testing:
Whether you know how to consume APIs defensively with timeouts, retries, backoff and fallbacks, and handle an unreliable dependency calmly.
Answer frame:

Situation: which API, what it did for you, and how it misbehaved.

Defences: timeouts, retries only on safe or idempotent calls, backoff with jitter, and respecting their rate limits.

Isolation: queues, caching or a circuit breaker so their outage doesn't become yours.

Result: what improved and how you knew.

Sample spoken answer:

"At my first job I integrated a shipping provider's API for tracking updates. It sometimes took ten seconds to answer, sometimes returned 503, and the docs didn't match real responses. First, I set a short timeout, because we had none and slow calls were tying up our request threads. Then I added retries with exponential backoff and jitter, but only for timeouts and 5xx, never for 4xx, and I honoured their Retry-After on 429. Because the docs were wrong, I logged sample responses and wrote our parser around what really came back. The biggest win was moving the calls out of the user's request path: a background job polled for updates and cached them, so a provider outage only made tracking a little stale instead of breaking our order page. Page errors from that integration dropped close to zero."

Red flag to avoid:

Retrying every failure immediately in a loop, including 4xx errors and non-idempotent calls.

They may ask next:
  • Why add jitter to the backoff?
  • When would a circuit breaker help more than retries?
Say it in 60 seconds
Were you asked something else? Share it A person checks every question before it goes on the site. No name is shown.
For the call itself

The questions above are the prep. The call has ten more.

ClapAssist is an AI interview assistant for Mac and Windows. It listens to the interview on your computer and shows you what to say, in short lines you can read while you talk. Your resume and notes are never stored on our servers. It stays out of screen share on every plan; only you can see it.

Download ClapAssist with 10 free minutes
Mac and Windows · Stays out of screen share · No card