APIs Are Contracts
The most important thing to internalize about API design is that an API is a contract. Once external systems depend on it, changing it has a real cost. Design with that permanence in mind.
This doesn't mean you can't evolve — it means you need versioning and deprecation strategies from day one.
REST, GraphQL, or gRPC?
REST is the default for public APIs and developer-facing interfaces. Its simplicity and ubiquity make it the lowest-friction choice when you're not sure what your consumers need.
GraphQL shines when consumers have diverse data needs — especially mobile clients that want to minimize payload size. The cost is schema complexity and caching difficulties.
gRPC is the right choice for internal service-to-service communication where performance and strong typing matter. It's not ergonomic for browser clients without a proxy layer.
Default to REST. Switch when you have a clear reason.
Naming Is Everything
Resources should be nouns, not verbs. "/users" not "/getUsers". Actions happen via HTTP methods. Consistency in naming across your API reduces cognitive load for every consumer.
Use plural nouns for collections (/orders), singular for single resources (/orders/{id}). Never mix conventions.
Version From Day One
Even if you're building a v1, structure your URLs with versioning: /api/v1/.... The cost is near-zero upfront. The alternative — retrofitting versioning into an unversioned API — is painful.
Error Responses Are Part of the Interface
A 500 with no body is an unusable API. Your error responses should be as carefully designed as your success responses. Use consistent error schemas:
{
"error": {
"code": "INVALID_INPUT",
"message": "The email field is required",
"field": "email"
}
}Document It Like Someone Else Will Maintain It
Because they will. Auto-generated docs from OpenAPI specs are a floor, not a ceiling. Add examples, explain the business logic behind constraints, and document rate limits and authentication flows completely.