API Design Best Practices
Document breaking changes like database migrations: deliberate, reviewed, and announced. These practices keep Node.js HTTP APIs predictable for integrators.
How to Use This List
- Review on every public endpoint PR
- CI enforces OpenAPI diff and Zod validation
- Pair with Versioning & Deprecation
- Internal admin APIs can relax some rules - document which surface is public
A - Resources and HTTP
- URLs use nouns and plural collections.
/v1/orders, not/getOrders. - HTTP methods express intent. POST create, PATCH partial update, DELETE remove.
- Correct status codes. 201 on create, 204 on delete without body, 409 on conflict.
- No business errors in 200 bodies. Use 4xx/5xx with structured JSON.
- Nested resources max one level unless domain clearly requires more.
B - Request and Response Shape
- Consistent envelope.
{ data }success,{ error }or Problem Details on failure. - Validate query, params, and body with Zod at HTTP boundary.
- Document every public field in OpenAPI. Required vs optional explicit.
- Use ISO8601 UTC for timestamps in JSON strings.
- Money as integer minor units (cents) or string decimal - pick one org-wide.
C - Errors
- Stable
codeper error type. Clients never parse Englishmessage. - RFC 9457 Problem Details for public B2B APIs.
- Central error middleware maps domain errors to HTTP.
- Include
requestIdin error payload for support correlation. - No stack traces in production JSON responses.
D - Pagination, Filtering, Performance
- Cursor pagination default for public lists. Cap
limitat 100. - Whitelist filter query params. Reject unknown filters with 400.
- Indexes match filter and sort columns. Review query plans for list endpoints.
- Rate limit headers on expensive list/search routes.
- Async export for bulk data - not unbounded synchronous lists.
E - Versioning and Compatibility
- Path version prefix
/v1. New breaking major ->/v2. - Deprecation and Sunset headers on old versions with published date.
- Migration guide for every breaking change linked from changelog.
- OpenAPI spec per major version in CI artifacts.
- Additive changes only within a major version unless emergency security fix.
F - Security and Ops
- Authenticate before body parsing on large payloads where possible.
- Idempotency-Key on POST payments and creates with server-side dedup store.
- CORS explicit allowlist - not
*with credentials. - Request size limits via
express.json({ limit })or Fastify bodyLimit. - Health endpoints separate from versioned API at
/health/liveand/health/ready.
FAQs
Public vs internal API rules?
Public B2B follows full list. Internal /admin may use offset pagination and simpler errors if documented.
GraphQL exceptions?
Use GraphQL conventions for errors and versioning; REST list still applies to webhook payloads.
When is RPC style OK?
Internal tools and Stripe-style POST actions (/v1/payment_intents/:id/capture) as sub-resources, not top-level verbs.
snake_case or camelCase JSON?
Pick one org-wide. JavaScript APIs usually camelCase; document in OpenAPI.
How to review API PRs?
Checklist + OpenAPI diff + example curl in PR description.
Webhooks versioning?
eventVersion field; separate signing secret per major version if payload shape changes.
Include ETag?
Worth it for cacheable GET resources; If-None-Match returns 304.
Batch endpoints?
POST /v1/orders:batch or /v1/orders/batch - document partial success shape.
File uploads?
Multipart documented separately; not forced into JSON envelope.
Top API incident cause?
Undocumented breaking field rename without version bump - prevented by section E.
Related
- API Design Basics - introductory patterns
- OpenAPI & Swagger - contract source
- Error Response Standards - Problem Details
- Pagination & Filtering - list endpoints
- Versioning & Deprecation - sunset policy
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.