API Endpoint Conventions (Contract‑First, REST, Versioning)¶
Note: Repository content must be in English. This guide follows that rule and provides conventions and examples for HTTP APIs.
1) Principles¶
- Contract‑first: Define the API contract (OpenAPI/Swagger) before implementation. Treat the contract as source of truth and version‑control it.
- Resource‑oriented: Model endpoints around nouns (resources), not verbs.
- Consistency: Consistent naming, casing, pagination, filtering, and errors across all services.
- Backward compatibility: New versions must not break existing clients without a deprecation path.
- Security by default: AuthN, AuthZ, and secure defaults (TLS, scopes, least privilege).
- Observability: Correlation IDs, structured logging, metrics, and tracing for every request.
2) Versioning¶
- Base path versioning: Use a major version in the URL:
/api/v1. Avoid embedding minor/patch versions in URLs. - Breaking changes → increment major (
/api/v2). Non‑breaking changes (adding fields, new optional params) stay in the same major. - Sunset headers: For deprecated versions, return:
Deprecation: trueSunset: <RFC3339 date>- Optionally
Link: <URL>; rel="deprecation"
Examples
/api/v1/users
/api/v1/orders/{orderId}
/api/v2/users # after breaking change
3) Naming & URL Design¶
- Plural resource names:
/users,/orders,/products. - Lowercase, kebab-case for path segments when needed:
/payment-methods. - Stable IDs: Use opaque IDs (UUIDs) where possible.
- Relationships:
- Sub‑resources:
/users/{userId}/orders - Linking via IDs for many‑to‑many; avoid deep nesting (
>2 levels). Prefer filters instead. - No verbs in paths. Use HTTP methods to express actions.
Good
GET /api/v1/users/{id}
POST /api/v1/users
POST /api/v1/createUser
4) HTTP Methods & Semantics¶
| Method | Safe | Idempotent | Typical Use |
|---|---|---|---|
| GET | ✓ | ✓ | Retrieve resources |
| POST | ✗ | ✗ | Create resource / non‑idempotent operations |
| PUT | ✗ | ✓ | Replace entire resource |
| PATCH | ✗ | ✗* | Partial update (use JSON Patch/Merge Patch) |
| DELETE | ✗ | ✓ | Delete resource |
*PATCH may be made idempotent by design of patch document.
5) Status Codes¶
200 OK(GET),201 Created(POST withLocationheader),202 Accepted(async),204 No Content(DELETE/PUT with no body)- Client errors:
400(validation),401(unauthenticated),403(forbidden),404(not found),409(conflict),422(semantic errors) - Server errors:
500,502,503,504— never expose internals.
6) Error Model (Problem Details)¶
Use RFC 9457 – Problem Details for HTTP APIs style:
{
"type": "https://api.example.com/errors/validation-failed",
"title": "Validation failed",
"status": 422,
"detail": "email must be a valid address",
"instance": "urn:trace:44f5a8...",
"errors": [
{ "field": "email", "message": "invalid format" },
{ "field": "password", "message": "min length is 12" }
]
}
Always include a correlation/trace ID (e.g., in instance) and return it also as a header, e.g. X-Request-Id.
7) Filtering, Sorting, Pagination, Fields¶
- Pagination: cursor‑based recommended (
page[size],page[cursor]). Offset allowed for small datasets (page,page_size). - Sorting:
sort=created_atorsort=-created_at(descending). - Filtering:
?status=active&created_from=2025-01-01&created_to=2025-01-31. - Sparse fieldsets:
fields= id,name,emailto limit payloads. - Expansions (optional):
expand=owner,itemsto embed related resources.
Example
GET /api/v1/orders?status=shipped&sort=-created_at&page[size]=50&page[cursor]=eyJvcmRlcmlkIjoiLi4uIn0=
8) Request/Response Bodies¶
- JSON only by default (
application/json; charset=utf-8). - Use snake_case or camelCase consistently (choose once for all services;
camelCaseis common in JSON). - Include
createdAt,updatedAttimestamps where useful (ISO‑8601/RFC3339 in UTC). - For collections, wrap in an object with
dataandmeta:{ "data": [{ "id": "...", "name": "..." }], "meta": { "total": 123, "nextCursor": "..." } }
9) Idempotency¶
- For non‑idempotent POSTs (e.g., payments), support Idempotency‑Key header. Store key + request hash + result for a TTL.
10) Caching¶
- ETags and
If-None-Matchon GET for conditional responses (304). - Cache-Control with appropriate max‑age or
no-storefor sensitive data.
11) Security¶
- TLS everywhere.
- Auth: OAuth2/OIDC (Bearer tokens), or mTLS where appropriate.
- Scopes/claims → fine‑grained Authorization.
- Input validation & output encoding. Reject unknown fields if strictness is required.
- Rate limiting (
429), API keys for server‑to‑server if needed. - Never leak stack traces or internal messages in responses.
12) Async Operations & Webhooks¶
- Long‑running tasks return
202 Acceptedwith a status resource:POST /api/v1/exports → 202 Location: /api/v1/exports/6f…/status - Provide webhooks for completion events; sign webhook requests and retry on 5xx/timeout.
13) OpenAPI (Contract‑First Workflow)¶
- Design the OpenAPI spec (YAML/JSON).
- Review: API review checklist (naming, pagination, errors, security).
- Generate server stubs & SDKs (if applicable).
- Mock server to unblock consumers.
- Implement handlers behind the contract.
- Test conformance (contract tests).
- Publish documentation & changelog.
Minimal OpenAPI skeleton
openapi: 3.0.3
info:
title: Example API
version: 1.0.0
servers:
- url: https://api.example.com/api/v1
paths:
/users:
get:
summary: List users
parameters:
- in: query
name: page[size]
schema: { type: integer, minimum: 1, maximum: 100 }
responses:
'200':
description: OK
14) Deprecation Policy¶
- Announce in changelog & docs.
- Mark endpoints as deprecated (
deprecated: truein OpenAPI;Deprecationheader). - Provide migration guidance and a minimum 90‑day window before removal (adjust to your domain).
15) Observability & Reliability¶
- Structured logs (JSON): include
service,env,version,traceId,spanId. - Metrics: request count, latencies, error rates, saturation, dependency health.
- Tracing: propagate
traceparent/baggage(W3C), instrument outbound calls. - SLOs/SLIs: define target latency and uptime; alert on breach.
16) Examples¶
Create user¶
POST /api/v1/users
Content-Type: application/json
Idempotency-Key: 4b1f…
{ "email": "j.smith@example.com", "name": "John Smith" }
201 Created
Location: /api/v1/users/3f25…
{ "id": "3f25…", "email": "j.smith@example.com", "name": "John Smith", "createdAt": "2025-08-17T12:34:56Z" }