Engrain by ByteRush

WEB.15.01 Mid-level· 12 minCore — asked often

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:

Why offsets duplicate posts in a live feedStep 1 of 4

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
  1. Page 1 of the feed, offset pagination: GET /posts?offset=0&limit=3 returns posts 10, 9, 8.
  2. Two new posts (12, 11) are published while the user reads.
  3. Page 2 with offset=3 now returns 10, 9, 8 again: duplicates. With deletions, items get skipped instead.
  4. 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?

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.”

Stays on your device. Nothing is uploaded.
Follow-up Offset vs cursor pagination: trade-offs?
Offset: page numbers and jumps, but duplicates or gaps on changing data and slow on large offsets. Cursor: stable and fast, but only next and previous.
Follow-up What is a backend-for-frontend?
A thin server layer owned by the frontend team that combines and shapes backend calls for one client, such as web or mobile.
Follow-up How should an API report errors?
The right status code plus one consistent JSON body, such as problem details, with a stable code the UI can switch on and field-level 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.
  • nextCursor is null on the last page.
  • problem returns an RFC 9457 object with any extra fields.
Your solution
Ctrl/⌘ + Enter

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
Use nouns in URLs (/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

Filtering and sorting go in the query string (?status=open&sort=-createdAt).
Cursors should be opaque strings, often an encoded id and sort value, so the server can change their contents later Source: RFC 9457: Problem Details for HTTP APIs.

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
An idempotency key is sent in a header such as 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
Version with a URL prefix (/v2/) or a header, and add fields instead of changing them.
A BFF gives each client one tailored endpoint per screen, hiding many backend calls Source: Microsoft: Backends for Frontends pattern.
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?