REST API Design Basic Rules
Next to providing good documentation, following RESTful conventions is the best way to guarantee developers will love your API T.
At Miredot, we feel quite strongly about API design. Nevertheless, we always try to be pragmatic. If someone cites Fielding's thesis during a design session, that's usually a sign that things are getting out of hand ;). The idea is to provide a REST API that:
- is easy to use and comprehend for developers,
- has predictable behavior,
- plays nice with proxies, caches, browsers.
In this article, I'd like to share the basic rules for URI/Resource design and selection of HTTP methods that we use at Miredot.
URI/Resource Design
REST is all about defining things or resources instead of actions (SOAP, RPC). We only have a few simple rules regarding resource naming and URIs.
- Use plural for collections
- Don't use verbs
Use /dogs/1/
instead of /dog/1/
Almost every resource is a collection, so make it a plural noun. Use the base resource /dogs/
to
manipulate the whole collection or specify a specific dog like this: /dogs/1
.
/dogs/1/breed
is fine since it refers to a specific piece of information of a dog, not
to a a collection.
Relations are easily expressed by separating collection resources by IDs:
/dogs/5/toys/3/parts/1
.
IDs can be numbers or UUIDs. Avoid business IDs such as the dog's name as that might collide with fixed
subresource names. For example, if someone names his/her dog 'analytics', this means we can never use
/dogs/analytics
for something more useful.
Verbs hint towards an action or a method call. Resources should only model where the data is, HTTP methods (GET, PUT, POST, DELETE) will tell you what the action is. These are bad:
/getAccount
/createDirectory
/group/update
/dogs/4/bark
HTTP Methods
We use the table below as a guideline to choose the correct HTTP method. Remember that:
GET
should NEVER have side effects as these might be prefetched or cached,GET
,PUT
andDELETE
must be idempotent.
Resource | GET | POST | PUT | DELETE |
---|---|---|---|---|
/dogs |
List all dogs.
200 (OK)
[{"id": "5", "name": "Snoopy"}, {"id": "6", "name": "Charlie"}]
|
Add a new dog to the other dogs.
{"name": "Pluto"}
201 (Created)
{"id": "1", "name": "Pluto"} OR "1" OR HATEOAS url
|
Replace the whole collection - usually not needed. |
Remove all dogs - usually not needed.
204 (No content)
|
/dogs/1 |
Get details of dog nr 1.
200 (OK)
{"id": "1", "name": "Pluto"}
|
Semantics not clear. Can be used for partial update - better use PATCH in this case. |
Replace existing dog or create dog 1.
{"name": "Pluto"}
200 (OK) / 201 (Created)
{"id": "1", "name": "Pluto"} OR "1" OR HATEOAS url
|
Remove dog 1
204 (No content)
|
This table is by no means the only correct way to design a REST API, but we feel it's a good starting point. In order to design a consistent API, it might be a good idea to compile your own table with your own specific design decisions.
We hope you enjoyed this post. We're preparing a next one on REST API smells, a way to recognize bad design. If you have any questions or remarks, feel free to add a comment. We'd love to hear from you!