Skip to main content

REST API

Contract​

  • Prefix every route with a version: /v1/.... Changing a response shape incompatibly means a new version.
  • JSON field names are camelCase on the wire and snake_case in Python. Use a Pydantic alias generator (to_camel) on request and response schemas.
  • Use plural nouns for collections: /v1/projects, /v1/projects/{project_id}.
  • Keep the OpenAPI schema the single contract. When a path, schema, or auth requirement changes, update the API docs in the same pull request.

Status codes​

CodeUse
200Successful read or update
201Resource created; include the resource
204Success with no body (delete)
400Malformed request
401Missing or invalid credentials
403Authenticated but not allowed
404Resource not found
409Conflict with current state
422Validation failed
500Unhandled server error; never leak internals

Errors​

Return one error shape from every endpoint. TBD: confirm the exact schema (candidate: RFC 9457 problem details) in template-fastapi and record it as an ADR.

Pagination and filtering​

  • List endpoints are paginated by default. Do not return unbounded collections.
  • Accept limit and offset (or a cursor for large or fast-changing data) and return the total or a next cursor.
  • Allow filtering and sorting through query parameters, validated against an allow list.

Idempotency​

  • GET, PUT, and DELETE are idempotent by definition; keep them so.
  • For POST operations that clients may retry (payments, imports), accept an idempotency key.

Security​

Authentication and authorization rules belong in Security. At minimum, every non-public route declares its auth dependency explicitly, and request bodies are validated by Pydantic schemas rather than parsed by hand.