Build a Production API

One endpoint — `POST /checkout` — built in the order you would actually build it. At each step there is a question that decides whether the endpoint is correct or merely working. Think about it before you open the answer; the answer is much less useful if you have not first been wrong.

Checkout is the example because it has every hard property at once: money, an external dependency, a race on shared stock, a client that retries, a transaction, and an event other systems depend on. An endpoint that only reads a row can hide all six.

  1. 1
    Authenticate

    Establish who is calling from the session or token.

    The question

    Should the tenant come from the request body, since the client already knows it?

  2. 2
    Validate

    Check the request is well-formed and the cart is in a checkout-able state.

    The question

    The cart was valid when we checked. Is it still valid when we charge?

  3. 3
    Check the idempotency key

    Look up the client-supplied key; if this request was already processed, return the original result.

    The question

    Where does this check belong — before the work, or after?

  4. 4
    Reserve inventory

    Decrement available stock for the items in the cart.

    The question

    Two customers buy the last unit at the same moment. Who gets it?

  5. 5
    Charge payment

    Call the payment provider — a slow, external, failable dependency.

    The question

    Should this happen inside the database transaction?

  6. 6
    Handle a payment timeout

    The provider does not respond before your deadline expires.

    The question

    Did the charge happen?

  7. 7
    Write the order

    Persist the order and its line items.

    The question

    What belongs inside this transaction?

  8. 8
    Publish OrderCreated

    Tell the rest of the system an order exists.

    The question

    The commit succeeded and the publish failed. Now what?

  9. 9
    Respond

    Serialize the result and return it.

    The question

    The connection drops before the client reads the response. What does the client do?