Designing Good Endpoints
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.
sortwith 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?
Seu progresso fica salvo apenas neste navegador.
Enviar para revisão (10 pontos)