Skip to content

API design

View Markdown
  • The API contract MUST be written down before implementation, as an OpenAPI document (REST) or schema (GraphQL), and kept in the repo.
  • Generated clients and server validation SHOULD come from that contract so they cannot drift.
  • Nouns for resources, plural, lowercase, hyphenated: /v1/orders/{orderId}/line-items.
  • GET reads (safe, cacheable), POST creates or runs an action, PUT replaces, PATCH partially updates, DELETE removes.
  • GET MUST NOT change state.
  • 200 OK, 201 Created (with Location), 204 No Content, 400 invalid input, 401 not authenticated, 403 not allowed, 404 not found, 409 conflict, 422 valid syntax but failed rules, 429 rate limited (with Retry-After), 5xx server faults only.
  • Error responses MUST use one format across the API. Use Problem Details (RFC 9457, application/problem+json): type, title, status, detail, instance, plus field-level errors where useful.
  • Errors MUST NOT leak stack traces, SQL, internal hostnames or whether a user account exists.
  • Paginate every list endpoint. Prefer cursor pagination for large or changing data; return next cursors.
  • Set a default and a maximum page size.
  • Filtering and sorting through documented query parameters only.
  • POST endpoints that create payments, orders or messages MUST accept an Idempotency-Key header and return the original result on retry.
  • Validate every input against the schema; reject unknown fields on writes.
  • Authenticate every non-public endpoint; authorise every object access (check the caller owns or may see that record).
  • Rate-limit by user and by IP.
  • Version in the path (/v1/) or a header; pick one per API.
  • Adding optional fields is non-breaking. Removing, renaming or changing meaning is breaking and needs a new version and a deprecation period.
  • Timestamps in ISO 8601 UTC; IDs as opaque strings.
  • Contract written and committed
  • Consistent error format
  • Pagination with limits
  • Idempotency on state-changing money/message endpoints
  • Authn + per-object authz on every endpoint
  • Rate limits