Module 2 / Start with a simple system / Designing an API

Lesson10 minModule 2 · lesson 2 of 7

Designing an API

Names, verbs and shapes that last.

The API (application programming interface) is the contract between client and server. Once phones in the wild depend on it, changing it is painful, since you cannot force millions of people to update their app. So API design is one of the first decisions that is genuinely hard to undo. The most common style on the web is REST: you describe things as resources with names, and use standard HTTP verbs to act on them.

A resource is a noun: restaurants, orders, users. Give each a plural path, and nest only when the child cannot exist without the parent. The verb is not in the path; the HTTP method carries it. So POST /orders creates an order, GET /orders/42 reads it, PATCH /orders/42 changes part of it, and DELETE /orders/42 removes it. Avoid paths such as /createOrder or /getOrderById.

GET    /restaurants               list restaurants
GET    /restaurants/12            one restaurant
GET    /restaurants/12/menu       its menu
POST   /orders                   create an order
GET    /orders/42                 read order 42
PATCH  /orders/42                 change part of it
DELETE /orders/42                 cancel it
Nouns in the path, verbs in the method.

Two properties of methods matter a great deal in practice. A method is safe if it does not change anything on the server (GET). A method is idempotent if doing it twice has the same effect as doing it once. GET, PUT and DELETE are idempotent; POST is not. This matters because networks fail: a phone sends an order, loses signal and does not see the reply. It will retry. If POST /orders is retried naively, the customer is charged twice.

Making a POST safe to retry

Step 1 of 4

Client creates a key

The app generates a unique idempotency key, for example a random id, once per attempted order.

Status codes tell the client what happened without parsing the body. Use 200 for success, 201 when something was created, 204 for success with no body, 400 for a malformed request, 401 when not signed in, 403 when signed in but not allowed, 404 when it does not exist, 409 for a conflict, 429 for too many requests and 500 for a server fault. For lists, never return everything: use pagination with a limit and a cursor, such as GET /orders?limit=20&after=9132. Cursors beat page numbers because rows added mid-browse do not shift the pages.

Question 1

Which method is NOT idempotent by default?

Question 2

A user is signed in but tries to view another person's order. Which status fits best?

Question 3

Why prefer cursor pagination to page numbers on a busy feed?

Your turn

Design the paths and methods to let a customer add a review to a restaurant and list its reviews.

Stuck? Use nouns for paths and think about which method creates and which reads.

What to remember

  1. A REST API names resources with nouns and acts with HTTP methods.

  2. GET, PUT and DELETE are idempotent; POST is not, so use idempotency keys for retries.

  3. Pick status codes that say what happened.

  4. Paginate every list, preferably with cursors.

  5. Version the API and prefer adding fields to changing them.