APIs are awesome, but they’re also extremely hard to design. When creating an API from scratch, you need to get many details right. From basic security considerations to using the right HTTP methods, implementing authentication, deciding which requests and responses you should accept and return, … the list goes on.
In this post, I’m trying my best to compress everything I know about what makes a good API. An API, that your consumers will enjoy using. All tips are language-agnostic, so they apply to any framework or technology.
1. Be consistent
I know it sounds logical, but it’s hard to get this one right. The best APIs I know are predictable. When a consumer uses and understands one endpoint, they can expect that another endpoint works the same way. This is important for the entire API and one of the key indicators of whether or not an API is well-designed and great to use.
- Use the same casing for fields, resources, and parameters (I prefer
snake_case
) - Use either plural or singular resource names (I prefer plural)
/users/{id}
,/orders/{id}
or/user/{id}
,/order/{id}
- Use the same authentication and authorization methods for all endpoints
- Use the same HTTP headers across the API
- For example
Api-Key
for passing an API key
- For example
- Use the same HTTP status codes based on the type of response
- For example
404
when a resource can not be found
- For example
- Use the same HTTP methods for the same kind of actions
- For example
DELETE
when deleting a resource
- For example
2. Use ISO 8601 UTC dates
When dealing with date and time, APIs should always return ISO 8601-formatted strings. Displaying dates in a specific time zone is generally a concern of client applications.
{
"published_at": "2022-03-03T21:59:08Z"
}
3. Make an exception for public endpoints
Every endpoint should require authorization by default. Most endpoints require an authenticated user to be called, so making this the default makes sense. If an endpoint needs to be called publicly, explicitly set this endpoint to allow unauthorized requests.
4. Provide a health check endpoint
Provide an endpoint (for example GET /health
) that determines whether or not a service is healthy. This endpoint can be called by other applications such as load balancers to act in case of a service outage.
5. Version the API
Make sure you version your API and pass the version on each request so that consumers aren’t affected by any changes to another version. API versions can be passed using HTTP headers or query/path parameters. Even the first version of the API (1.0) should be explicitly versioned.
Some examples:
https://api.averagecompany.com/v1/health
https://api.averagecompany.com/health?api_version=1.0
6. Accept API key authentication
If an API needs to be called by a third party, it makes sense to allow authentication via API keys. API keys