hectoday
DocsCoursesChangelog GitHub
DocsCoursesChangelog GitHub

Access Required

Enter your access code to view courses.

Invalid code

← All courses REST API Design with @hectoday/http

What Makes an API RESTful

  • APIs are contracts
  • Project setup
  • Resources, not actions

HTTP Methods

  • GET, POST, PUT, PATCH, DELETE
  • Idempotency
  • Method safety and side effects

Status Codes

  • The status codes that matter
  • Error responses

Resource Design

  • Modeling resources
  • Partial responses and field selection
  • Pagination
  • Filtering, sorting, and searching

API Lifecycle

  • Versioning
  • Content negotiation
  • Rate limiting and quotas

Advanced Patterns

  • Bulk operations
  • Long-running operations
  • HATEOAS and discoverability

Putting It All Together

  • API design checklist
  • Summary

API design checklist

Everything in one place

We’ve covered a lot of ground. URLs, methods, status codes, error formatting, pagination, filtering, versioning, rate limiting, bulk operations, long-running tasks, and HATEOAS. That’s a lot to keep in your head when you’re building an endpoint.

This lesson pulls everything together into a checklist you can use before shipping any new endpoint or API version. Think of it as the review process for your API design.

The checklist

URLs

  • URLs use nouns, not verbs (/books, not /getBooks)
  • Collection URLs are plural (/books, not /book)
  • Item URLs use the collection path plus an ID (/books/:id)
  • Nesting is limited to two levels (/books/:id/reviews, not deeper)
  • Nested routes are used only when the child depends on the parent
  • Independent resources use flat routes with query filters

HTTP methods

  • GET retrieves data and has no side effects
  • POST creates new resources
  • PUT replaces an entire resource
  • PATCH updates specific fields
  • DELETE removes a resource
  • No data modification happens on GET

Status codes

  • 200 for successful GET, PUT, PATCH
  • 201 for successful POST (with Location header)
  • 204 for successful DELETE (no body)
  • 400 for malformed requests
  • 401 for unauthenticated
  • 403 for unauthorized
  • 404 for not found
  • 409 for conflicts (duplicates)
  • 422 for validation errors (optional, 400 is also acceptable)
  • 429 for rate limiting (with Retry-After)

Error responses

  • Every error uses the same format: { error: { code, message, details? } }
  • Error codes are machine-readable strings (NOT_FOUND, not 404)
  • Validation errors include per-field details
  • Error messages are helpful but don’t leak implementation details

Pagination

  • List endpoints are paginated (never return unbounded results)
  • Default limit is reasonable (20)
  • Maximum limit is enforced (100)
  • Cursor-based pagination for data that changes frequently
  • Response wraps data in an object: { data: [...], pagination: { ... } }

Filtering and sorting

  • Filters use field names as query parameters (?genre=fiction)
  • Sort uses - prefix for descending (?sort=-publishedAt)
  • Search uses ?q= for full-text
  • Unknown parameters are ignored (not errored)
  • Sort field whitelist prevents SQL injection

Versioning

  • Breaking changes require a version bump
  • Additive changes do not require a version bump
  • Deprecated versions include Deprecation and Sunset headers

Rate limiting

  • Every response includes X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset
  • 429 responses include Retry-After
  • Limits are per-client (API key or IP)

General

  • Responses are JSON with Content-Type: application/json
  • POST and PUT endpoints validate Content-Type
  • Idempotency keys are supported for non-idempotent operations
  • Long-running operations return 202 with a status URL

Common mistakes to watch for

Returning bare arrays. If GET /books returns [...] instead of { data: [...] }, you can’t add pagination metadata later without breaking every consumer. Always wrap lists in an object from the start.

Using 200 for everything. A created resource returns 200 instead of 201. A deleted resource returns 200 with { success: true } instead of 204. Status codes carry meaning. Use them.

Inconsistent naming. One endpoint returns authorId, another returns author_id, a third returns AuthorID. Pick a convention (camelCase or snake_case) and stick with it everywhere.

Exposing database internals. Column names like created_at in your responses leak the database schema. Consider mapping to createdAt (camelCase) for the API surface, or at least use the same convention consistently.

No pagination on list endpoints. Works fine with 10 items. Falls over with 10,000. Always paginate, even if the list is small today.

Ignoring idempotency. A payment API without idempotency keys charges the customer twice when the network drops the response and the client retries.

The review process

Before merging a new endpoint, walk through these questions:

  1. Read the URL aloud. Does it describe a resource? Can you guess what it does without documentation?
  2. Check the method. Is it the right HTTP method? Does GET have side effects?
  3. Check the status codes. Does the happy path return the right code? Do error cases return the right codes?
  4. Check the error format. Does it match the standard format? Does it include a machine-readable code?
  5. Test with curl. Can you use the endpoint with curl and understand the response?
  6. Check pagination. If it returns a list, is it paginated? Is the limit capped?

If all six pass, the endpoint is ready.

Exercises

Exercise 1: Go through the checklist for your bookstore API. How many items pass?

Exercise 2: Find any inconsistency in naming (like author_id vs authorId). Fix it across all endpoints.

Exercise 3: Review a real API you use against this checklist. How does it score?

What is the most common API design mistake?

← HATEOAS and discoverability Summary →

© 2026 hectoday. All rights reserved.