FoundationNetworkingFree Preview

API Design Principles — REST, Idempotency, Versioning Explained

Define contracts between clients and services with clear resources, errors, pagination, versioning, and idempotency.

An API (Application Programming Interface) is a contract. It defines exactly what a service accepts, what it returns, and what happens when things go wrong. Bad API design creates cascading problems: clients build around undocumented behaviors, changing the API breaks integrations, and error handling becomes a mess of guessing what status codes mean.

Good API design starts with resources, not actions. In REST, the URL is a noun (the resource) and the HTTP method is the verb. `POST /orders` creates an order. `GET /orders/{id}` reads it. `PATCH /orders/{id}` updates it. `DELETE /orders/{id}` removes it. This is the resource-oriented design that makes APIs predictable and self-documenting.

Two concepts are critical for production APIs: idempotency and versioning. Idempotency means calling an endpoint twice with the same request has the same effect as calling it once — essential for retries in the face of network failures. Versioning means you can evolve the API without breaking existing clients. Together they determine whether your API is reliable enough for external developers to build businesses on top of.

Key concepts

RESTGraphQLgRPCpaginationversioningidempotency keyserror model

Step-by-step approach

  1. 1

    Define the resources: what are the nouns in your system? (user, order, product, payment) Each major noun becomes a URL endpoint.

  2. 2

    Define operations on each resource: list, create, read, update (partial vs full), delete, and any domain-specific actions (e.g., POST /orders/{id}/cancel).

  3. 3

    Choose a protocol: REST for broad client compatibility; gRPC for high-throughput internal services; GraphQL for flexible data fetching on client-driven UIs.

  4. 4

    Design the error model: use standard HTTP status codes (400 for client errors, 500 for server errors) and return a consistent error body with a machine-readable code and human-readable message.

  5. 5

    Add idempotency keys for non-idempotent operations (POST, PATCH): clients include a unique key; the server deduplicates based on it, making retries safe.

Key trade-offs

REST vs. gRPC

REST is human-readable, widely supported, and works in browsers. gRPC is binary, 5-10× more efficient, and supports bidirectional streaming — but requires generated clients and isn't browser-native.

Stateless vs. stateful

Stateless APIs (each request is self-contained) are easier to scale horizontally. Stateful APIs (session on server) are simpler to write but create sticky session requirements that complicate load balancing.

Strict versioning vs. backward compatibility

Versioning (/v1/, /v2/) is explicit but requires maintaining multiple versions. Backward-compatible changes (adding fields, not removing) avoid versioning but require careful discipline.

Common pitfalls

Using verbs in URLs: /createUser, /deleteOrder are not RESTful. Use nouns (/users, /orders) and HTTP methods for actions.

Returning 200 OK for errors: HTTP status codes exist for a reason. A 200 response with {"status": "error"} in the body breaks every monitoring tool and client library.

No idempotency for payment or order creation: retrying a failed payment request without idempotency creates duplicate charges — a critical production bug.

Interview questions on this topic

Design the API for a ride-sharing app. What resources would you expose, and how would you handle real-time driver location updates?
How would you version an API that 10,000 external developers depend on, while still shipping breaking changes?

Practice answering these with AI feedback → Start on CrackLab

Continue learning — explore 207 more topics on CrackLab DesignHub

From Classic HLD designs (Twitter, YouTube, Uber) to LLD patterns, distributed systems, databases, and company case studies.

Related topics