A great API is one that developers don't have to read docs for — it's discoverable, predictable, and forgiving. Building APIs that developers enjoy is a craft, and it separates platforms that get adopted from those that don't.
How should you name REST API resources?
- Plural nouns for resources: /orders, /products, not /order, /getProduct.
- Nested resources for clear ownership: /users/{id}/orders.
- Consistent casing: kebab-case for URLs, camelCase for JSON properties.
- No verbs in URLs — use HTTP methods for actions.
What should an API error response look like?
Errors should tell developers what went wrong AND what to do about it. Use structured error responses: { code, message, details, helpUrl }. Map errors to semantic HTTP status codes. Never return 200 with an error body — it breaks every HTTP client in existence.
{
"code": "validation_failed",
"message": "The order could not be created.",
"details": [
{ "field": "items[0].quantity", "issue": "must be greater than 0", "received": 0 },
{ "field": "shippingAddress.postalCode", "issue": "required for country US" }
],
"helpUrl": "https://api.example.com/docs/errors/validation_failed",
"requestId": "req_01HQ8Z3K2"
}
// requestId is the difference between "it's broken" and a support
// conversation that resolves in one message — always include it.Should you use offset or cursor pagination?
Offset pagination (?page=3&limit=50) is fine for small, static datasets and quietly wrong for everything else: rows inserted while a client is paging shift the offsets, so records get skipped or returned twice. Cursor pagination encodes a stable position instead, and it stays correct under concurrent writes. Return the cursor as an opaque string — the moment integrators start decoding it, its format becomes your public API.
GET /v1/orders?limit=50&cursor=eyJpZCI6Im9yZF8xOTIzIn0
200 OK
{
"data": [ /* 50 orders, newest first */ ],
"pagination": {
"nextCursor": "eyJpZCI6Im9yZF8xODcxIn0", // null on the last page
"hasMore": true
}
}
// No total count: computing it costs a full table scan on large
// datasets. Expose it as a separate endpoint if clients genuinely
// need it, rather than taxing every page request.How do you stop API docs from going stale?
Hand-written API docs drift from the implementation within a release or two — and stale docs are worse than none, because integrators trust them. Generate the reference from the same source the server validates against.
- Keep an OpenAPI description as the source of truth and generate the reference docs from it, so a shipped endpoint change cannot leave the docs behind.
- Validate real requests against that schema in CI — a contract test catches the mismatch before integrators do.
- Give every endpoint a copy-pasteable example with a real (sandbox) payload, not just a field table.
- Document the error codes as thoroughly as the success paths; that is what developers actually search for at 2am.
How should you version a REST API?
URL versioning (/v1/, /v2/) is still the most practical approach for REST APIs. Deprecation notices via Deprecation and Sunset headers give integrators time to migrate. Document your API lifecycle policy upfront — 12 months minimum support after deprecation announcement.
