Skip to main content

REST API Cheatsheet

At a glance​

What it isAn architectural style for HTTP APIs: resources identified by URLs, manipulated with standard methods and representations (usually JSON)
Use it forPublic and internal web APIs, mobile/SPA backends, service-to-service calls where HTTP caching and simplicity matter
Latest stableHTTP Semantics RFC 9110 (June 2022) · Problem Details RFC 9457 (July 2023, obsoletes RFC 7807) · OpenAPI 3.2.1 (released 2026-09-10) - checked 2026-10-31
Official docsRFC 9110 · RFC 9457 · OpenAPI Specification

Core concepts​

  • Resource: a noun with a stable URL (/users/42); collections are plural (/users).
  • Representation: what goes over the wire (JSON), negotiated with Accept / Content-Type.
  • Safe method: does not change state (GET, HEAD, OPTIONS).
  • Idempotent method: repeating it has the same effect as once (GET, PUT, DELETE, not POST/PATCH).
  • Stateless: each request carries everything needed (auth token, params); no server session per client.
  • Status code: the first thing clients branch on; the body adds detail.
  • Problem Details: standard error body, media type application/problem+json (RFC 9457).
  • HATEOAS: responses include links to related resources/actions; nice to have, rarely done fully.

Syntax & commands​

Methods

MethodTypical useSafeIdempotentSuccess code
GET /userslist / readyesyes200
POST /userscreate (server picks id)nono201 + Location
PUT /users/42full replace (or create at known id)noyes200 / 204
PATCH /users/42partial updatenono*200 / 204
DELETE /users/42deletenoyes204

* PATCH can be made idempotent by design (e.g. JSON Merge Patch on fields).

Status codes worth memorizing

CodeMeaningUse when
200 OKsuccess with bodyGET, PUT/PATCH returning the resource
201 Createdresource createdPOST; add Location: /users/43
202 Acceptedqueued, not done yetasync jobs; return a status URL
204 No Contentsuccess, empty bodyDELETE, updates without body
304 Not Modifiedcache still validconditional GET with If-None-Match
400 Bad Requestmalformed requestinvalid JSON, wrong types
401 Unauthorizednot authenticatedmissing/invalid token; send WWW-Authenticate
403 Forbiddenauthenticated, not allowedmissing role/scope
404 Not Foundno such resourcealso to hide existence from unauthorized users
409 Conflictstate conflictduplicate, version mismatch
412 Precondition FailedIf-Match failedoptimistic locking with ETag
422 Unprocessable Contentvalid syntax, failed validationbusiness/field validation errors
429 Too Many Requestsrate limitedadd Retry-After
500 / 502 / 503 / 504server / upstream errors503 + Retry-After for maintenance

Success body (pick one envelope and keep it everywhere)

{
"data": [{ "id": 1, "name": "John Doe" }],
"meta": { "total": 120, "page": 1, "per_page": 20 },
"links": { "self": "/users?page=1", "next": "/users?page=2" }
}

Error body - RFC 9457 Problem Details (Content-Type: application/problem+json)

{
"type": "https://api.example.com/problems/validation-error",
"title": "Your request is not valid.",
"status": 422,
"detail": "2 fields failed validation.",
"instance": "/users",
"errors": [
{ "pointer": "#/email", "detail": "must be a valid email address" }
]
}

type, title, status, detail, instance are the standard members; extra members (like errors, trace_id) are allowed extensions.

Requests

curl -s "https://api.example.com/v1/users?page=2&per_page=20" \
-H "Accept: application/json" -H "Authorization: Bearer $TOKEN"

curl -s -X POST https://api.example.com/v1/users \
-H "Content-Type: application/json" -H "Idempotency-Key: 7f1c..." \
-d '{"name":"Jane","email":"jane@example.com"}'

curl -s -X PATCH https://api.example.com/v1/users/42 \
-H "Content-Type: application/merge-patch+json" -H 'If-Match: "v7"' \
-d '{"name":"Jane D."}'

OpenAPI skeleton

openapi: 3.2.0
info: { title: Users API, version: 1.0.0 }
paths:
/users/{id}:
get:
parameters:
- { name: id, in: path, required: true, schema: { type: integer } }
responses:
"200": { description: OK, content: { application/json: { schema: { $ref: "#/components/schemas/User" } } } }
"404": { description: Not found, content: { application/problem+json: { schema: { $ref: "#/components/schemas/Problem" } } } }

Common patterns​

URL design

DoAvoid
GET /users/42/orders (one level of nesting)/users/42/orders/7/items/3/notes
GET /orders?status=paid&sort=-created_at/getPaidOrders (verbs in path)
POST /orders/7/cancel for a real actionoverloading PUT for actions
kebab-case paths, consistent JSON keys (snake_case or camelCase)mixing styles

Pagination

StyleRequestGood forWatch out
Offset?page=3&per_page=20 or ?offset=40&limit=20admin tables, jump to page Nslow on deep pages, items shift on insert
Cursor?cursor=eyJpZCI6...&limit=20feeds, large or live datano "jump to page"; cursor must be opaque

Also: filtering ?status=paid, sorting ?sort=-created_at,name, sparse fields ?fields=id,name.

API versioning patterns

StyleExampleProsCons
URL path/v1/usersexplicit, easy to route and cacheURL changes on upgrade
Query param/users?version=1clean base URLeasy to forget, caching harder
Custom headerApi-Version: 2026-10-01clean URL, date-based versions work wellinvisible in browser/logs, needs docs
Media typeAccept: application/vnd.example.v1+jsonfine-grained, true content negotiationcomplex, poorly understood
  • Version only on breaking changes (removing/renaming fields, changing types or semantics). Adding optional fields is not breaking.
  • Clients must ignore unknown fields (tolerant reader).
  • Announce removal with the Deprecation and Sunset response headers plus a changelog; keep old versions alive for a published window.

Reliability

  • Idempotency-Key header on POST so retries do not double-charge.
  • ETag + If-None-Match for caching, ETag + If-Match for optimistic locking (412 on conflict).
  • Rate limit with 429 + Retry-After; long jobs return 202 + a status URL.

Gotchas​

  • 401 means "who are you?", 403 means "I know you, no". Do not mix them.
  • Do not return 200 with "success": false in the body; use the right status code.
  • PUT replaces the whole resource: missing fields become null/default. Use PATCH for partial updates.
  • Return 404 vs 403 consciously: 404 hides that a resource exists.
  • Use ISO 8601 UTC timestamps (2026-10-31T09:00:00Z) and string IDs if they may exceed JS safe integers (2^53).
  • DELETE twice: second call can be 404 or 204; it is still idempotent (same server state).
  • RFC 7807 is obsolete; new code should reference RFC 9457 (same media type and members, so clients keep working).
  • Never leak stack traces or SQL in detail; log them with a trace_id instead.

What's new in recent releases​

  • OpenAPI 3.2.1 (2026-09-10): patch release clarifying 3.2.0; no new features.
  • OpenAPI 3.2.0 (2025-09-19): hierarchical tags (parent, kind), query HTTP operation plus additionalOperations for other methods, in: querystring parameters, streaming/sequential media types (itemSchema for SSE, JSON Lines), OAuth 2.0 device authorization flow and oauth2MetadataUrl.
  • OpenAPI 3.1.2 / 3.0.4: clarification-only patch releases; 3.1 aligned schemas with JSON Schema 2020-12.
  • RFC 9457 (July 2023): replaced RFC 7807, adds a shared registry of problem types and guidance for multiple problems in one response.
  • RFC 9110 (June 2022): consolidated HTTP semantics for all HTTP versions; 422 renamed to "Unprocessable Content" and became core HTTP.

In these notes​