REST API Conventions
Our HTTP APIs should feel like one team designed them: consistent URLs, verbs, status codes, error shapes, pagination, and versioning. This is the concrete conventions reference that goes with the broader API & Contract Design guideline. Consistency makes APIs predictable to use, safe to change, and easy to secure.
API & Contract Design covers the principles (consumer-first, stable, safe). This page sets the specific conventions so every endpoint looks and behaves the same. Pick one convention and apply it everywhere. A consistent API is far easier to consume, document, and maintain than one where every endpoint is a surprise.
All the security rules still apply: authenticate and authorise every endpoint, validate input at the boundary, never return too much data, and never leak internals (see Authentication & Authorization, Trust Boundaries).
Resources & URLs
- DoModel resources as plural nouns in
kebab-caseor lowercase paths (/customers,/customers/{id}/documents). Use ids in the path, not verbs in the URL. - DoUse HTTP methods correctly:
GET(read, safe),POST(create or action),PUT/PATCH(replace or update),DELETE(remove). Keep GET, PUT, and DELETE idempotent. - DoBe consistent with casing in every place: lowercase
kebab-casein URL paths,camelCasein JSON bodies, andcamelCasein query parameters so they match the body. Keep date and time format (ISO 8601, UTC) and identifier types consistent too. - AvoidRPC-style verbs in URLs (
/getCustomerById,/doThing) and inconsistent singular/plural or casing between endpoints. - NeverLeak
PascalCasefield names by serialising .NET objects with default settings.PascalCaseis not a JSON convention, just an unconfigured serialiser. SetJsonNamingPolicy.CamelCase(the ASP.NET Core default) so the contract is camelCase on purpose.
Status codes & responses
- DoReturn correct status codes: 200/201/204 for success, 400 for validation, 401 for unauthenticated, 403 for unauthorised, 404 for not found, 409 for conflict, 422 for unprocessable, 429 for rate-limited, and 5xx for server errors. See HTTP Status Codes for the full list and when to use each.
- NeverReturn
200 OKfor a failed request. The status code is the result. A 200 with an error in the body hides the failure from clients, proxies, caches, and monitoring, so problems go unnoticed. Use the right 4xx or 5xx code. - DoUse Problem Details (
application/problem+json, RFC 9457, the successor to RFC 7807) as the one error shape across the whole API. Settype,title,status, anddetail, add a stable applicationcode, and use theerrorsextension for field-level validation. In ASP.NET Core, enable the built-in Problem Details service rather than inventing your own error body. - DoShape responses on purpose with DTOs. Return only the fields the caller needs and is allowed to see. Never serialise whole entities (see API & Contract Design).
- NeverLeak internal details (stack traces, SQL, secrets, file paths) in responses, or return another tenant's or user's data (see Multi-Tenancy, Error Handling).
Collections, filtering & versioning
- DoPaginate collection endpoints the same way across the API and cap the page size. Document the default and the maximum.
- DoSupport filtering and sorting through consistent query parameters, and validate them. Never build SQL from them unsafely (see Data Modelling & Persistence).
- DoVersion the API and add to it rather than change it. Make breaking changes a new version with a deprecation path (see Backward Compatibility).
- DoDocument the contract as the source of truth (for example OpenAPI), and keep it in sync with the implementation.
Safety & robustness
- AlwaysAuthenticate and authorise every endpoint by default, derive identity and tenant on the server, and validate every request against the contract at the boundary (see Authentication & Authorization, Trust Boundaries).
- DoUse explicit request models to prevent over-posting and mass-assignment, so a caller cannot set role, tenant, or price. Apply rate and size limits (see Rate Limiting & Abuse Prevention).
- DoSupport idempotency for unsafe operations where retries are likely (idempotency keys on POST), so a retry does not apply the change twice (see Data Integrity & Transactions).
- DoReturn
429withRetry-Afterwhen rate-limiting, and a meaningfulLocationheader on a 201 created.
An endpoint, end to end
POST /getCustomerById?id=5 -> 200 { error: "not found" }
POST /deleteCustomer -> 200 { ok: true }
// 500 body: stack trace and SQL
Verbs in URLs, a 200 for a not-found and for errors, inconsistent shapes, and an internal stack trace and SQL leaked to the caller. Unpredictable and unsafe.
GET /customers/{id} -> 200 CustomerResponse | 404
DELETE /customers/{id} -> 204 | 404
// errors: application/problem+json (type/title/status/detail and code), no internals; 401/403/422/429 as appropriate
Nouns and HTTP verbs, correct status codes, a single Problem Details error shape with no internal detail, and identity and tenant derived on the server.
Self-review checklist
- AskDo the URL, verb, status codes, casing, and error shape match the rest of the API?
- AskIs the endpoint authenticated and authorised, with identity and tenant derived on the server?
- AskCould a caller over-post a field they should not, or get back data they should not?
- AskIs the collection paginated and capped, and is the change additive or properly versioned?