APIs are quickly taking over as the world networks more and more devices and technologies. We are fortunate enough to live in the age of the internet and APIs, which allow us to create complex solutions integrating different technologies more quickly and easily than ever.
REST has grown to become the popular favorite for Web Service API implementation. Even so, there seems to be a lot of confusion over how to implement a REST API. I believe that the majority of this confusion stems from the fact that REST is an architectural style with a set of best practices and guidelines, but is not a tight specification with an RFC. This post will help alleviate some of the confusion and help you determine if your API is RESTful, which is key in making a straightforward, popular, and easy to use API.
For this post to make sense I’m expecting you to have some background in APIs, Web Services, and REST. This is not a “from the ground up how to”.
Constructing Your Resource URIs
Perhaps the most important thing when designing your API to be RESTful is careful planning of your resources and their URIs. This means you should take careful consideration of your application and how resources will be defined. For this discussion we will use a blog application as an example. A typical blog could have several resources such as blog entries, categories, and reader comments. When examining your own API to determine if it is RESTful you should think about the entities that it involves. These entities are important because they play directly into how your URIs are defined.
Define Your Entities to Define Your Resources
In order to design a URI scheme that makes sense you will need to define your application entities. Again, in the blog example we will use the entities of entries, categories, and reader comments. This would translate into URIs such as
http://blog.com/entries http://blog.com/categories http://blog.com/comments
You should try and have a one-to-one relationship of your base entities to resources and each resource should implement the standard REST actions, unless there is a specific reason not to.
Use Nouns to Define Your Resource URIs
With a REST API you should use descriptive nouns when defining your endpoints. Avoid calls to action such as /getcomments. Just use /comments instead. When it comes to pluralization of your nouns I’ve seen both ways listed as best practice but personally it makes more sense to me to use a plural endpoint when more than one result is returned.
Treat Your URIs As If You Are Serving Static Content
When accessing application content you should structure your URIs as if you were serving static content. So, in the blog example, to access a specific blog entry, our URI would look like:
You can think of this like having a directory called “entries” that holds a file for each entry that is named with the entry ID. You should avoid passing the entry ID in a parameter, or some other convoluted way. This method provides a straightforward way to access content and eliminates the need for unnecessary parameter passing.
Handling Resource Relationships
The above example makes sense when we are dealing with an independent entity but what about the case of reader comments? The URI
would be used to access a comment with an ID of 3. However, in our blog example, we most likely would not be accessing reader comments directly. A blog entry actually has a one-to-many relationship with a reader comment. In this example we only care about viewing comments related to a specific entry. Therefore, a more likely URI for comments would be via the entries endpoint. For example
With this URI we would retrieve all comments for a specific blog entry.
Use Parameters For Filtering Collection Results
URI parameters should be used to allow the client to filter results from collection URIs that return large sets of data.
You should implement pagination to allow the client to pull portions of collections in sequence to step through all data. For pagination to work you will need to return data in a consistent order, such as by ID. A fairly common way to enable pagination is shown in the following URI:
In this URI the offset parameter says to start returning after the 100th record and the limit parameter says to only return 50 results.
In addition to pagination it may make sense to narrow down collection results by specific search conditions. This should also be done for using parameters. In our blog example if we wanted to display all posts for May of 2017 we could use a URI like the following:
Your API should also support the combination of pagination with search parameters as some searches could still return a large number of results.
Choosing Your HTTP Methods Wisely
HTTP methods, which are passed as part of the HTTP protocol, should be used to perform different actions via the same URL. For example retrieving a blog entry or editing a blog entry could both be done by the following URL:
We can do both actions from the same URL if our API is RESTful and implements the common HTTP methods. So, what are the HTTP methods and what do they mean?
Get should be used when requesting data from the server. A GET request to the resource /entries would return all blog entries. A GET request to /entries/11/comments/13 would return the comment with ID 13 for the entry with ID 11. GET is probably the type of request you are most used to in the HTTP space. That is we are simply asking the HTTP server (in this case our API) for data.
A GET request should be idempotent. That is, repeated calls to a GET request do not change any state and the request can be repeated over and over without consequence.
The POST method is used when creating a new item for a resource. There is an important distinction in the URI for creating new items than the URIs used for other actions. When we are creating an item we do not yet know the item ID. As such, we can not use an ID specific resource. So, the creation of new items is done to the collection URI. For example to create a new blog post, you should POST to the /entries URI with the new item in the request body. The POST response should then return the new item’s ID so that it may be used by the client.
The POST action is not idempotent as subsequent calls to the POST method with the same payload and URI will continue to create new objects, violating the definition of idempotence and further changing the server state. This is an important distinction as it is the only non-idempotent HTTP action based on specification. This is why POST should be used for creating new resources as opposed to the PUT method.
The PUT method is used to update or change existing data. The new data should be passed in the PUT request’s body. A PUT request to the endpoint /categories/3 would update or modify the current category with ID 3 to the contents of the new request.
The PUT method is also idempotent. Repeated PUT calls to the same URI with the same payload will not cause any harm or change (other than being inefficient).
The DELETE method is fairly straightforward and should be used to delete or remove items from your resources. A call to the resource /entries/4 in our blog example would delete the blog entry with an ID of 4.
The DELETE method is actually idempotent in that it is safe to make subsequent calls to the same URI with a DELETE request, although it wouldn’t make sense to do so. The first call to DELETE would delete the record and follow-up calls would be inert.
In order for your API to be RESTful you should use the standard HTTP return codes and use them in the appropriate situations. There are a lot of HTTP response codes. The following are some of the more popular codes when it comes to Web Service APIs. The important take away is that you use the appropriate descriptive response code for the situation and don’t just always return a generic code like 200 for every success and 400 for every failure.
Every request should receive a response code, even when successful. A successful request will include the response in the request body and a status of 200 OK.
This response code should be returned for any successful post when a new resource is created.
204 No Content
This response code should be used when satisfying a request that does not warrant any data being returned, for instance a DELETE request may not have any data associated with it. In this case a 204 No Content should be returned to signify the operation was successful but there is no data in the response body.
304 Not Modified
This status can be used by the server to signal the client that a requested resource has not been modified since the last time it was provided. This response can help cut down on the amount of unnecessary traffic when using large data sets.
400 Bad Request
This code should be returned when the server is unable to understand or interpret the request.
This code should be used when a client attempts to access a protected resource without proper authorization.
This differs slightly from a 401 Unauthorized in that you should use it if the client has authorized itself but doesn’t have the appropriate role or permission to access the resource.
404 Not Found
This response code should be used any time the resource URI is not found. It should not be used for other arbitrary error responses. Simply put the 404 should only be returned if the resource did not exist.
500 Internal Server Error
Use this status code when the server screws up. This tells the client that it didn’t do something wrong, but the server has run into an unexpected problem.
It is important for a RESTful API to use a standard supported content type. The two obvious choices are XML and JSON. In my opinion there is no reason to use XML anymore however given modern libraries and OSS it is not difficult to support both. Your API should use content negotiation with the client to determine it’s preferred format.
The Richardson Maturity Model
So now that I’ve covered the basics how would you categorize your API? Fortunately there is already a model to do so developed by Leonard Richardson called the Richardson Maturity Model. This model can be used to determine how RESTful an API has. It has the following four levels:
This isn’t really a level of the model but it is used to categorize APIs that are not at all RESTful.
This is the first RESTful level of the model. For an API to reach level 1 it needs to implement resource based URIs.
The second level is achieved when you have implemented your HTTP methods and status codes in a RESTful way.
Level 3 is achieved when implementing HATEOS (which is out of scope of this article) within your API. In short, the server returns useful, relative links to the client in the response.
If you want to create an easy to use API that has the highest potential for wide acceptance you should take a look at making it as RESTful as possible. The following abbreviated list should give you a start on what to take a look at:
- Define your URIs based on resources and their relationships. Use nouns not verbs and be consistent.
- Understand idempotency and how and when do use different HTTP request methods.
- Return the appropriate HTTP status codes based on the specific outcome.
- Lastly, look in to implementing HATEOS to achieve full RESTfulness.
Now get coding!