Designing a RESTful API
Anatomy of a HTTP request permalink
- HTTP verb
- URL (domain name and path)
- Query parameters (optional)
- Headers (optional)
- Body (optional)
Resources permalink
ReST stands for Representational State Transfer. While the R does not stand for Resource, I wish it did, because designing a good RESTful API is much easier when when you think about organising around resources first and foremost.
The idea of organising around resources is to identify the objects which you wish to communicate about between the client and server. CHances are, you have already though about this at some level either on your back end server code, or your front end client code. You may have defined classes that represent certain objects, and defined database schemas that represent those same objects. If you have, you have already modelled your resources.
Once you have identified what your resources are, you can give each one of them a base URL within your API. For example, if you have a Customer
resource, the base URL
for it could be /api/v1/customers
. An Address
resource might have a base URL of /api/v1/addresses
.
Once you have your base URL, the next step is to create an instance URL for each resource.
/api/v1/customers
- refers to all customers/api/v1/customers/:id
- refers to a single customer whose ID matches the number at the end of the URL
Add HTTP verbs permalink
So far, we have identified what resources we have, and what the base URL and instance URL for each one should be.
The next key part of RESTful API design is the actions. This is where HTTP verbs come into the mix.
Typically, the actions that one wishes to perform of any resource falls into one of four operations:
- Create - create a new instance of a resource
- Read - access one or more existing instances of a resource
- Update - modify an existing instance of a resource
- Delete - destroy an existing instance of a resource
A non RESTful way of designing an API could be to simply append the name of the operation to the instance URL. For example, to delete a Customer
with an ID of 123
, the URL could be:
/api/v1/customers/1/delete
(wrong)
Instead, make use of HTTP verbs in order to do so. This list of commonly used HTTP verbs is a handy resource.
In the context of RESTful API design, however, what we are most concerned about is how they map to the four types of operations which we wish to perform on resources.
- Create -
POST
orPUT
- Read -
GET
- Update -
PATCH
orPUT
- Delete -
DELETE
Delete permalink
Coming back to the example above, to delete a Customer
with an ID of 123
, the HTTP request could be:
DELETE /api/v1/customers/123
(correct)
instead of using GET
, the default HTTP verb, with the name of the action in the URL:
GET /api/v1/customers/1/delete
(wrong)
Read permalink
The read operation is just as simple as the delete operation:
GET /api/v1/customers/123
With read operations, however, it is common place to want to read not just one instance of a resource in one request, but rather multiple ones. For this, we issue a GET
request on the base URL instead of the instance URL.
GET /api/v1/customers
This should receive a response with all of the customers. If, for example, this is excessive, as is likely to be the case in a real world application, simply use query parameters to filter the request.
GET /api/v1/customers?page=0&perPage=30
The example above might be what you issue to obtain a list of customers to display in a paginate form.
Create permalink
Create and update are slightly more complex than read and delete, because they each involve two HTTP verbs, which are used in two different types of situations when creating or updating resources.
Create operations could use either POST
or PUT
HTTP verbs.
When you create a new object in the front end, you will quite often know all the attributes from the user input. All, that is, except for the ID of that object. Since an ID is a key that should be unique among all instances of a particular resource, the correct place to determine an ID for any resource would be in the database layer, as it has the facilities to do so, because it maintains an index of the IDs (or primary keys) of all instances of a resource.
Thus in order to create a new customer, the HTTP request might be
POST /api/v1/customers
{
"name": "Brendan",
"points": 100
}
Let’s say, however, that your front end is somehow already privy to the ID for a resource that is about to be created, perhaps from a previous request. In this case, a PUT
would be appropriate:
PUT /api/v1/customers/123
{
"name": "Brendan",
"points": 100
}
In the default case, however, POST
is preferred.
Update permalink
Similar to create, update operations also make use of two different HTTP verbs - PATCH
and PUT
When the front end wishes to update a resource, it should already have a copy of that resource, and thus will know its ID. However, when updating, it can choose to either:
- update just a select number of properties of that resource, or
- update the entire resource, overwriting the existing copy
To update only select properties, use PATCH
:
PATCH /api/v1/customers/123
{
"points": -10
}
To overwrite all properties, use PUT
:
PUT /api/v1/customers/123
{
"name": "bguiz",
"points": 90
}
Recap permalink
- Create -
POST
orPUT
- When you wish to create the object, but wish to allow the server to decide its ID (primary key), use
POST
- When you know the entire object already, including its ID, use
PUT
- When you wish to create the object, but wish to allow the server to decide its ID (primary key), use
- Read -
GET
- When accessing multiple resources at once, use the base URL instead of the instance URL
- Use query parameters to restrict or filter multiple resources if necessary
- Update -
PATCH
orPUT
- When you wish to submit just the parts of the resource that have changed, use
PATCH
- When you wish to resubmit the entire resource, and have the existing one overwritten, use
PUT
- When you wish to submit just the parts of the resource that have changed, use
- Delete -
DELETE
HATEOAS permalink
What a wonderful acronym, eh? It stands for Hypertext as the Engine of Application State. It means that each request to a resource, should provide links to other related resources. In theory, a front end application should be able to navigate through all other related resources after being pointed at the first one.
The problem with this, and with other aspects of RESTful APIs for that matter, is that there is no standard specifying exactly how this should be done. In fact, there are many who will have different opinions on which HTTP verbs are appropriate to use when.
This brings us to the next thing: Standardisation
Standardisation permalink
One of the main problems with designing a RESTful API, is that everyone has their own interpretation, and execution of it.
This is partly due to the inherent complexities, and often real world application trade off that need to be made, which have optimisation and speed face off against sticking to the specification.
However, it is mostly due to the fact that there is no specification to begin with. All we really have is an academic paper by Roy Fielding who coined the term, Representational State Transfer. While this laid excellent ground work on a conceptual basis, it left too much room for interpretation in technical implementation.
JSON API is one of the many different standards that have built upon RESTful API design. It builds upon two things: Using JSON as the serialization format, and using a RESTful API.
In doing so, I believe that it has also done a great job of codifying RESTful APIs. In addition, it also includes a solution for side-loading, rather than in line embedding, of related data as part of its specification. This is a particularly useful feature that is not part of standard RESTful APIs, but very useful to have in practice.
Thus, if you are designing a RESTful API, I would strongly recommend starting with JSON API.