API Design
What is an API?
An API (Application Programming Interface) is like a menu at a restaurant. You don't walk into the kitchen and cook your own food. Instead, you look at the menu, pick what you want, and the kitchen makes it for you. The menu is the interface — it tells you what's available, what you need to provide ("how would you like your steak cooked?"), and what you'll get back.
In software, an API defines how two systems talk to each other. Your mobile app talks to your backend through an API. Your backend talks to Stripe's payment system through an API. APIs are everywhere.
Good API design matters because:
- It's a contract. Once developers start using your API, changing it breaks their code.
- It affects performance. Chatty APIs (many small calls) are slower than well-designed ones.
- It shapes the developer experience. A confusing API means frustrated developers and more support tickets.
REST: The Most Common API Style
REST (REpresentational State Transfer) is the most popular API style on the web. It uses standard HTTP methods to perform operations on resources.
The key principles:
- Resources: Everything is a resource with a URL. Users live at
/users, a specific user at/users/42, their posts at/users/42/posts. - HTTP Methods: Use the right verb for the right action:
GET /users/42 — Read user 42POST /users — Create a new userPUT /users/42 — Replace user 42 entirelyPATCH /users/42 — Update specific fields of user 42DELETE /users/42 — Delete user 42
- Stateless: Each request contains all the information needed. The server doesn't remember previous requests (a key principle for scalability).
- JSON: Most REST APIs use JSON for request/response bodies.
HTTP Status Codes
Status codes tell the client what happened. Think of them as the server's facial expressions:
2xx — Success (smiling)
200 OK— Everything worked. Here's your data.201 Created— New resource created successfully.204 No Content— Success, but nothing to return (common for DELETE).
3xx — Redirection (pointing somewhere else)
301 Moved Permanently— This resource has a new URL forever.304 Not Modified— Use your cached version, nothing changed.
4xx — Client Error (you messed up)
400 Bad Request— Your request doesn't make sense.401 Unauthorized— Who are you? (Not authenticated.)403 Forbidden— I know who you are, but you can't do this.404 Not Found— This resource doesn't exist.429 Too Many Requests— Slow down! You're being rate limited.
5xx — Server Error (we messed up)
500 Internal Server Error— Something broke on our end.502 Bad Gateway— The server behind us is broken.503 Service Unavailable— We're overloaded or in maintenance.
RESTful API Design Example
API Versioning
APIs evolve. You'll add features, change data formats, deprecate endpoints. But you can't break existing clients that depend on the old behavior. Versioning solves this.
Common strategies:
- URL path versioning:
/api/v1/users,/api/v2/users. The most common and most visible approach. - Header versioning:
Accept: application/vnd.myapi.v2+json. Cleaner URLs but harder to test in a browser. - Query parameter:
/api/users?version=2. Easy to implement but messy.
URL path versioning wins in practice because it's the most obvious and the easiest to document, cache, and route at the load balancer level.
Pagination
You never want to return 10 million records in one response. Pagination returns data in manageable chunks.
Offset-based: GET /posts?page=3&per_page=20. Simple but has problems: if new posts are added between page requests, you might see duplicates or miss items. Also slow for large offsets (the DB must skip thousands of rows).
Cursor-based: GET /posts?cursor=abc123&limit=20. The cursor is an opaque token (usually an encoded timestamp or ID) pointing to where the last page ended. Much more efficient for large datasets and doesn't have the duplicate/skip problem. This is what Twitter, Facebook, and most modern APIs use.
Rate Limiting
Without rate limiting, a single client could overwhelm your API with millions of requests. Rate limiting caps the number of requests a client can make in a time window.
Rate limit headers tell clients their status:
X-RateLimit-Limit: 100— You can make 100 requests per windowX-RateLimit-Remaining: 42— You have 42 requests leftX-RateLimit-Reset: 1640000000— The window resets at this Unix timestamp
When the limit is exceeded, return 429 Too Many Requests. We'll go deeper into rate limiting algorithms in the Rate Limiter design lesson.
Beyond REST: GraphQL and gRPC
GraphQL (developed by Facebook) lets clients request exactly the data they need. Instead of multiple REST endpoints, there's one endpoint where you send a query:
query { user(id: 42) { name, email, posts { title } } }
This solves the over-fetching problem (REST returns all fields even when you only need two) and the under-fetching problem (needing to make multiple REST calls to get related data). Great for mobile apps where bandwidth matters.
gRPC (developed by Google) uses Protocol Buffers (binary format) instead of JSON. It's much faster than REST because binary is smaller than text and it supports HTTP/2 features like streaming and multiplexing. Used for internal service-to-service communication where performance matters more than human readability.
When to use each:
- REST: Public APIs, simple CRUD apps, when you want maximum compatibility.
- GraphQL: Complex data requirements, mobile-heavy apps, when clients need flexibility.
- gRPC: Internal microservice communication, low-latency requirements, streaming data.