> cs·fundamentals
interview 0% 28m read
9.2 ★ core [B][J] 1 interview Q's

API contracts & REST

An API is a promise about shapes and verbs. Design the contract well and the AI fills in the implementation correctly.

An API is a promise about shapes and verbs: hit this URL with this method and this body, and you’ll get back that shape with this status code. Get the contract right and the AI fills in the implementation correctly — and your frontend and backend can move independently. This chapter is how to design that contract precisely. (The interview-depth HTTP/REST material is 2.1 and 2.2; this is the builder’s view.)

The noun goes in the URL, the verb in the method

A RESTful API names a resource in the URL (/api/todos, /api/todos/:id) and uses the HTTP method for the action. The same path serves several operations by varying the method — that’s the whole convention, and it’s why anyone can guess your API once they know the resource. The anti-pattern that screams “not thought through” is verbs in the URL: POST /createTodo, GET /deleteTodo/1. Name it right and the AI gets the verb, the path, and the status code on the first try.

A list of five endpoints for the todos resource: GET list, POST create, GET one, PATCH update, DELETE remove.GET/api/todos→ list allPOST/api/todos→ create (201)GET/api/todos/:id→ read onePATCH/api/todos/:id→ updateDELETE/api/todos/:id→ remove (204)
FIG 1 · one resource, the standard endpoints The noun (/todos) stays put; the method changes the action. Knowing the resource lets you guess every endpoint.

Status codes that tell the truth

The status code is a contract too — clients, caches, and monitoring all rely on it. Returning 200 OK for everything (and hiding failure in the body) breaks all three. Use the families: 2xx for success, 4xx when the caller did something wrong, 5xx when the server broke. The leading digit tells you where to look first: a 4xx is on the request, a 5xx is in your logs.

CodeMeansUse it when
200 / 201 / 204OK / Created / No Contentsuccess; 201 after a create, 204 after a delete
400 / 422Bad Request / Unprocessablemalformed or invalid input
401 / 403Unauthenticated / Forbiddennot logged in vs logged in but not allowed
404 / 409Not Found / Conflictno such resource; or a duplicate/conflicting state
429 / 500Too Many Requests / Server Errorrate-limited; or the handler threw
401 = “who are you?”, 403 = “I know you, you still can't.” Don't 200-for-everything.

The contract: shapes in, shapes out

The valuable artifact isn’t the code — it’s the agreed shapes: what the request body must contain, what comes back, and what an error looks like. Pin that down and the frontend can build against it before the backend exists (and vice versa).

A contract, written before any implementation
POST /api/todos
 Request  { title: string (required), dueDate?: string }
 201 →    { id: string, title: string, dueDate: string | null, done: boolean }
 400 →    { error: "title required" }
 401 →    (not authenticated)

GET /api/todos      → 200 { todos: Todo[] }      (this user's only)
PATCH /api/todos/:id { done?: boolean } → 200 Todo | 403 (not owner) | 404

Handing the AI this contract — not “make a todos API” — gets you correct verbs, status codes, required-field checks, and ownership scoping in one pass.

A frontend box and a backend box both pointing at a central contract box.frontendCONTRACTshapes + codesbackend
FIG 2 · the contract is the handshake Both sides depend on the agreed shape, not on each other's code — so they can be built and changed independently.

REST, GraphQL, or RPC?

REST is the default and the right starting point. The alternatives solve specific pains: GraphQL exposes one endpoint where the client asks for exactly the fields it needs (great when many clients need different slices, at the cost of more setup); RPC (like tRPC) is “call a typed function across the wire” (great inside one TypeScript codebase). At orientation level: pick REST unless you have a concrete reason, and know the words when the AI proposes an alternative.

01 Learning objectives

0 / 6 done

02 Curated reading

03 Knowledge check

knowledge check3 questions · pass ≥ 70%
  1. 01easy

    Which is the RESTful way to delete the note with id 42?

  2. 02medium

    A logged-in user requests something they're not permitted to do. The right status code is…

  3. 03medium

    Returning 200 for every response and signalling failure only in the body is fine.

04 Interview questions

browse all ↗

What gets asked on this topic — tap a card for how to approach it, the follow-ups, and the trap. Company tags are best-effort & sourced.

  • Commonly asked mid concept common When would you return 401 vs 403 vs 404, and why is “200 for everything” a problem?

    401 Unauthorized means *not authenticated* — we don't know who you are (log in). 403 Forbidden means *authenticated but not allowed* — we know you, you still can't do this. 404 Not Found means the resource doesn't exist (and is sometimes returned instead of 403 to avoid leaking that a resource exists). Returning 200 for everything and hiding failure in the body breaks clients, caches, and monitoring, which all key off the status code — the first digit is supposed to tell you whose fault it is (4xx caller, 5xx server).

    What a strong answer covers
    • 401 = not authenticated; 403 = authenticated but not authorized.

    • 404 = doesn't exist (sometimes used instead of 403 to avoid leaking existence).

    • Status codes are a contract clients/caches/monitoring depend on.

    • 200-for-everything hides failure and breaks all three.

    Red flag Using 200 with an { error } body — tooling and caches treat it as success, so failures go unnoticed.

    source: MDN — HTTP response status codes ↗