OpenAPI, Errors & Pagination

OpenAPI as contract, Problem Details (RFC 7807), cursor vs offset pagination, filtering, and rate-limit response headers.

3/5Overview: 35m

OpenAPI (Swagger) as the contract

OpenAPI 3.x describes paths, operations, schemas, security schemes, and examples. Becomes:

  • Documentation (Swagger UI, Redoc)
  • Codegen (clients, servers, types)
  • Validation (request/response middleware)
  • Gateway config (Kong, Apigee import)

Staff practice: contract-first for public APIs — design YAML, review in PR, generate server stubs. Code-first acceptable for fast-moving internal services if CI regenerates spec and breaks on drift.

Key components: components/schemas, responses, reusable parameters, securitySchemes (Bearer, OAuth2, API key).

Error models — RFC 7807 Problem Details

{ "type": "https://api.example.com/errors/insufficient-funds", "title": "Insufficient funds", "status": 402, "detail": "Account 123 balance 4.50, required 10.00", "instance": "/payments/req-abc", "balance": 4.50 }

type is a stable URI (not necessarily dereferenceable). Extension members allowed. Prefer over ad-hoc { "error": "something went wrong" }.

For validation errors, common pattern: errors[] array with field, code, message alongside Problem Details envelope.

Pagination

Offset/limit

GET /items?offset=100&limit=20 — simple, poor performance on large offsets (DB scans skipped rows). Inconsistent under concurrent inserts/deletes.

Cursor/keyset

GET /items?cursor=eyJpZCI6MTIzfQ&limit=20 — encode last-seen sort key; stable under churn. Required for high-volume feeds (Twitter, Stripe).

Response pattern:

{ "data": [...], "pagination": { "next_cursor": "...", "has_more": true } }

Link headers

Link: <...?cursor=abc>; rel="next" — RFC 5988; works without JSON envelope.

Filtering, sorting, sparse fieldsets

  • ?filter[status]=active&sort=-created_at
  • ?fields[users]=name,email — reduce payload (also GraphQL's core idea)

Document limits: max limit, max filter complexity, timeout for expensive queries.

Rate limiting headers

Common conventions (no single RFC winner):

  • X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
  • Retry-After on 429

Token bucket vs sliding window — implementation in gateway; API contract documents limits per tier/key.

Idempotency-Key header

Stripe/GitHub pattern: Idempotency-Key: <uuid> on POST. Server stores response for key TTL; duplicate requests return cached response. Essential for payment and order APIs with retries.

Content negotiation

Accept: application/json vs application/xml — rare today. More relevant: Accept-Language, compression (Accept-Encoding: gzip, br — handled at HTTP layer per Networking).

Long-running operations

Google pattern: POST returns 202 + Operation resource with done: false; client polls GET /operations/{id} or receives webhook. Alternative: 202 + Location to status URL.

Further Reading

Hands-On Tasks (Optional)

API design drills and whiteboard exercises — protocol selection, contract design, and bulk-transfer architecture. Assumes Networking and sibling tracks on the hub page (Distributed Systems, Databases, Concurrency, LLD).

  • Design an error response schema

    Define Problem Details JSON for: validation error (multiple fields), rate limit, conflict (409), and internal error. Include machine-readable `type` URIs and stable `code` fields.

    15m