# 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: true` - `Sunset: ` - Optionally `Link: ; 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 ``` **Avoid** ``` 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 with `Location` header), `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: ```json { "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_at` or `sort=-created_at` (descending). - **Filtering**: `?status=active&created_from=2025-01-01&created_to=2025-01-31`. - **Sparse fieldsets**: `fields= id,name,email` to limit payloads. - **Expansions** (optional): `expand=owner,items` to 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; `camelCase` is common in JSON). - Include **`createdAt`, `updatedAt`** timestamps where useful (ISO‑8601/RFC3339 in UTC). - For **collections**, wrap in an object with `data` and `meta`: ```json { "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-Match` on GET for conditional responses (304). - **Cache-Control** with appropriate max‑age or `no-store` for 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 Accepted` with 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) 1. **Design** the OpenAPI spec (YAML/JSON). 2. **Review**: API review checklist (naming, pagination, errors, security). 3. **Generate** server stubs & SDKs (if applicable). 4. **Mock server** to unblock consumers. 5. **Implement** handlers behind the contract. 6. **Test** conformance (contract tests). 7. **Publish** documentation & changelog. **Minimal OpenAPI skeleton** ```yaml 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: true` in OpenAPI; `Deprecation` header). - 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" } ``` **Response** ``` 201 Created Location: /api/v1/users/3f25… { "id": "3f25…", "email": "j.smith@example.com", "name": "John Smith", "createdAt": "2025-08-17T12:34:56Z" } ``` ### List users with pagination ``` GET /api/v1/users?page[size]=25&page[cursor]=eyJpZCI6IjNmMjUuLi4ifQ== ``` ### Error example ``` 422 Unprocessable Entity { "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" }] } ``` --- ## Quick Checklist - [ ] Contract written in OpenAPI and reviewed - [ ] `/api/v{major}` base path - [ ] Plural nouns, no verbs in paths - [ ] Correct methods & status codes - [ ] Problem Details error shape - [ ] Consistent pagination/filter/sort - [ ] Idempotency for POST where needed - [ ] ETags & caching as applicable - [ ] AuthN/AuthZ & rate limiting - [ ] Observability (logs, metrics, tracing) - [ ] Deprecation & changelog process