Implement a Robust REST Create Method
Implement the handler behind POST /orders. It must be safe to retry: a client that times out and sends the same request again must not create a second order. Answer in code — OrdersApi(tokens) with createOrder(request) returning { status, body }, where request is { headers, body }.
tokens maps a bearer token to { userId, scopes }. Header names are case-insensitive. Apply the checks in this order; the first failure wins:
- Authenticate —
Authorization: Bearer <token>with a known token, else401 { error: "unauthorized" }. - Authorise — the caller needs the
orders:writescope, else403 { error: "forbidden" }. - Idempotency key — an
Idempotency-Keyheader of 1–64 characters after trimming, else400 { error: "invalid_idempotency_key" }. - Body shape — the body must be a JSON object, else
400 { error: "invalid_body" }. - Validate and sanitise — else
422 { error: "validation_failed", fields: [...] }naming every offending field, sorted:sku: a string that, once trimmed, is 1–40 characters of letters, digits,_or-;quantity: an integer from 1 to 100 (a numeric string or a boolean is invalid);note: optional; a string of at most 200 characters once control characters (codes below 32, and 127) are removed and it is trimmed; an empty or missing note is stored asnull;- any other field is rejected by name.
- Idempotency — keys are scoped to the authenticated user. A key seen before with the same sanitised request returns the original response again and creates nothing. A key seen before with a different request is
409 { error: "idempotency_key_reused" }. A request that failed validation does not consume its key. - Create — ids are
ord_1,ord_2, … in creation order; respond201 { id, sku, quantity, note, createdBy }with the sanitised values.
count() returns how many orders exist.
createOrder({ headers: { Authorization: "Bearer tok_ann", "Idempotency-Key": "k1" }, body: { sku: " ABC-1 ", quantity: 2 } })
-> { status: 201, body: { id: "ord_1", sku: "ABC-1", quantity: 2, note: null, createdBy: "ann" } }
the same call again -> the same response; count() is still 1Hints
Hint 1
Write the pipeline as a sequence of early returns in the stated order. Look headers up case-insensitively once, at the top, so the rest of the code never thinks about casing.
Hint 2
Validate into a sanitised copy and collect the names of bad fields as you go, instead of returning on the first one. Everything after validation — the fingerprint, the stored order — uses the sanitised values.
Hint 3
The idempotency store maps (userId, key) to a fingerprint of the sanitised request plus the response you sent. Same fingerprint: return the stored response. Different fingerprint: 409. Only write to it when an order is actually created.