REST API design for frontend engineers
Design APIs your UI can use well: resources and URLs, methods and status codes, problem-details errors (RFC 9457), offset vs cursor pagination, filtering, idempotency keys, versioning and the backend-for-frontend pattern.
Comes up in: Frontend system design, Backend design, Recruiter screen
Learn#
Varun’s news feed shows the same post twice when users scroll during busy hours, and errors appear as “Something went wrong” because the API returns a different error format from every endpoint.
REST organizes an API around resources, things with URLs such as /posts/42, and uses HTTP methods for actions on them: GET to read, POST to create, PATCH or PUT to update, DELETE to remove. Status codes carry the outcome (WEB.12.01).
Offset pagination (?offset=20&limit=10) is simple but breaks when the list changes while users page. Cursor pagination asks for items “after this one”, so inserts at the top cannot shift the next page:
State
- feed: 10 9 8 | 7 6 5 …
Page 1 of the feed, offset pagination: GET /posts?offset=0&limit=3 returns posts 10, 9, 8.
Read the steps as text
- Page 1 of the feed, offset pagination: GET /posts?offset=0&limit=3 returns posts 10, 9, 8.
- Two new posts (12, 11) are published while the user reads.
- Page 2 with offset=3 now returns 10, 9, 8 again: duplicates. With deletions, items get skipped instead.
- Cursor pagination asks for "after post 8": GET /posts?after=8&limit=3 returns 7, 6, 5, whatever was added on top.
For errors, use one format everywhere. RFC 9457 “problem details” is a standard JSON shape:
{ "type": "about:blank", "title": "Invalid input", "status": 422,
"detail": "Email is already registered.", "field": "email" }Predict#
Predict first
A user double-taps Pay. Both POST /payments requests reach the server. How do you make sure only one charge happens?
The client generates one key per payment attempt and sends it with every retry. The server remembers the key and its result, so repeats return the stored response instead of charging again. Disabling the button helps, but retries after network errors still need the key.
Interview angle#
Say it like this — about 30 seconds
“I model resources with nouns in URLs and use HTTP methods and status codes for their meaning. Errors use one shape, such as RFC 9457 problem details, with a machine-readable field for the UI. For feeds I prefer cursor pagination: it is stable when items are added, and fast on big tables, while offset is fine for small admin tables that need page numbers. POSTs that create things accept an idempotency key. A backend-for-frontend shapes data for one client.”
Follow-up Offset vs cursor pagination: trade-offs?
Follow-up What is a backend-for-frontend?
Follow-up How should an API report errors?
Practice#
On your own
Implement cursor pagination that stays correct while new posts arrive, and a problem-details error builder.
Done when
- Pages continue after the cursor, even when new posts are added at the top.
nextCursoris null on the last page.problemreturns an RFC 9457 object with any extra fields.
Remember#
Try to answer each card before you open it. Then add them to your reviews.
Why does offset pagination duplicate items in a live feed?
New items at the top shift every later offset.
What is an idempotency key?
A client-chosen ID so the server runs a request once, even if it is retried.
What is RFC 9457?
Problem details: a standard JSON format for API errors.
What is a BFF?
A backend-for-frontend that shapes data for one client.
Go deeper
Four layers. Stop at the one your interview needs; each ends with a quick check.
The core ideaEvery round
/posts/42/comments) and methods for verbs. Return 201 with a Location header after creating, 204 for success with no body, 422 for validation errors.Check yourself: Which method updates part of a resource?
PATCH.
How it works underneathSenior rounds
?status=open&sort=-createdAt).Check yourself: Why should a cursor be opaque to clients?
So the server can change what it encodes without breaking clients.
Edge cases and trapsWhere people slip
Idempotency-Key. The server stores the key with its response for a while (often 24 hours) and returns the same response for repeats; a repeat with a different body is an error.Check yourself: How long should a server remember idempotency keys?
Long enough to cover client retries, often 24 hours.
In productionStaff-level answers
/v2/) or a header, and add fields instead of changing them.Check yourself: Name two ways to version an API.
A URL prefix such as /v2, or a header or media type.
Finished the five steps? Mark it, and its cards join your reviews.
Last checked 2026-11-01. Spot a mistake? Use “Report an error” below — fixes are listed on the corrections page.
Interview questions this answers
- Offset vs cursor pagination: trade-offs?
- What is a backend-for-frontend?
- How should an API report errors?
- What is an idempotency key and when do you need one?