APIs are contracts. Break the contract, break the trust. Here's how to design APIs that last.
Choosing the Right Protocol
There's no universal answer. Each protocol excels in different contexts:
| Protocol | Best For | Watch Out For |
|---|---|---|
| REST | Public APIs, CRUD-heavy services | Over-fetching, versioning headaches |
| GraphQL | Frontend-driven development, complex data graphs | N+1 queries, caching complexity |
| gRPC | Service-to-service communication, streaming | Browser support, debugging difficulty |
REST Done Right
Most REST APIs I've seen in enterprise environments are REST in name only. True RESTful design means:
- Resources, not actions —
/orders/123not/getOrder?id=123 - HTTP verbs matter — GET is safe, PUT is idempotent, POST is neither
- HATEOAS — controversial, but hypermedia links make APIs self-documenting
{
"id": "order-123",
"status": "shipped",
"total": 149.99,
"_links": {
"self": { "href": "/orders/order-123" },
"cancel": { "href": "/orders/order-123/cancel", "method": "POST" },
"tracking": { "href": "/shipments/ship-456" }
}
}
Versioning Strategy
URL versioning (/v2/orders) is the simplest and most explicit. Header-based versioning is cleaner in theory but harder to test with a browser or curl.
Pick one approach and stick with it across your entire platform. Consistency matters more than perfection.
Rate Limiting and Throttling
Every public API needs rate limiting. Every internal API probably does too — a misbehaving batch job can DDoS your own services just as effectively as an external attacker.
Use token bucket or sliding window algorithms. Return 429 Too Many Requests with a Retry-After header. Make it easy for consumers to do the right thing.
The Biggest Mistake
Designing your API around your database schema. Your API is a product interface — it should model the domain, not your tables. An order in your API might pull from five different database tables, and that's fine. The consumer shouldn't know or care.