I'd like to leave a few tips that I think are adamant in writing good APIs. I've come across all of these mistakes, and they are a pain to deal with. Some more than others, but all decrease the enjoyability of working with them.
- First and foremost, be consistent. This might be the most important tip I would give, and will be the most detailed one:
- some cases are more broadly used, but, ultimately, it doesn't matter if you use
snake_case, just use the same kind everywhere;
- the above point goes for naming endpoints too; don't have one endpoint
reference-data and another
- when two endpoints return the same kind of object(s), it's a good idea for the key of said object(s) to be the same (the same goes for all of its keys). For example, if an endpoint has a user under the key
user, other endpoints that contain a user should not have them under the key
- if you have a kind of object under a key, and there's a possibility of it not existing, do not return any other kind of object under that key - either
null, or empty object (at the worst case). For example, do not return an empty array where you'd usually find a dictionary;
- if most of your endpoints have one kind of structure, use it everywhere. For example, if three endpoints have a root dictionary, don't make your other two endpoints have a root array;
- if you have some endpoints making use of
REST methods, for example
DELETE /users/1, don't have other endpoints use a path component for the same functionality, for example
- if you have several endpoints that can be queried with the same parameters, use the same names in all places. If one endpoint expects
pageSize, don't have other endpoints expect
- for the same problem, always return the same
HTTP code, for all endpoints. For example, if a resource can not be found, don't return
400 for one endpoint and
404 for another.
- If you're writing
REST APIs, use its methods instead of path components:
GET to get a resource;
POST to create, instead of
PUT to update, instead of
DELETE to delete, instead of
- Use versioning:
/v1/users/1. Even if you're absolutely sure you won't need it, it's still good practice. Never say never.
- Always have a container dictionary at the root level. This leaves room for adding new data in the future, while keeping the endpoint backwards-compatible. You might say that we can just create a new version for this endpoint, and you'd be right most of the time; but there are cases where you do not want to/can not create a new version yet:
"name": "Roland Leth"
"name": "Roland Leth"
// Room for new data here