API Design & REST

Designing Good Endpoints

35 мин

Consistent error format

Every error should look the same, so clients handle them in one place:

{
  "error": {
    "code": "validation_failed",
    "message": "Title is required.",
    "fields": {"title": "required"},
    "request_id": "req_8f2c1a"
  }
}

Use stable machine-readable code values; messages can change. Never leak stack traces or SQL in error responses.

Filtering, sorting and searching

GET /v1/projects?status=published&category=web&sort=-created_at&q=booking
  • Filters as query parameters with explicit names.
  • sort with a - prefix for descending; allow only whitelisted fields.
  • Validate every parameter and return 400 for unknown values instead of ignoring them silently.

Pagination

Cursor pagination stays fast and consistent on large, changing datasets:

{
  "data": [ ... ],
  "next_cursor": "eyJpZCI6IDEyMH0",
  "has_more": true
}
GET /v1/projects?limit=20&cursor=eyJpZCI6IDEyMH0

The cursor encodes the last item's sort key. Offset pagination (?page=3) is simpler but slows down and skips or repeats items when data changes. Always cap limit (for example at 100).

Partial responses and expansion

Keep default responses lean. Let clients request related data explicitly: GET /v1/orders/7?expand=customer,items.

Versioning

Clients break when you change response shapes. Put a version in the URL (/v1/) or a header, and:

  • Additive changes (new optional fields, new endpoints) are safe within a version.
  • Breaking changes (removing or renaming fields, changing types) require a new version, with the old one supported for an announced period.

Idempotency keys

For POST requests that must not run twice (payments, orders), accept an Idempotency-Key header. Store the key with the result; if the same key arrives again, return the stored result instead of repeating the action. Stripe's API works this way.

Designing first

Write the API contract before the code, in OpenAPI (YAML). It documents the endpoints, generates interactive docs and client SDKs, and lets frontend and backend teams work in parallel.

paths:
  /v1/projects/{id}:
    get:
      summary: Get a project
      parameters:
        - {name: id, in: path, required: true, schema: {type: string}}
      responses:
        "200": {description: The project, content: {application/json: {schema: {$ref: "#/components/schemas/Project"}}}}
        "404": {description: Not found}

Exercise

Design (in OpenAPI or a Markdown table) a v1 API for a booking system: services, availability, bookings and cancellations, with filtering, cursor pagination, an error format and an idempotency key for creating bookings.

Check yourself

  • Why is cursor pagination preferred for large datasets?
  • Which changes are safe without a new version?
  • What problem do idempotency keys solve?

Ваш прогресс сохраняется только в этом браузере.

Отправить на проверку (10 баллов)