Restful API Design Best Practices

1. Overview

In this post, I would like to explain the best practices for Restful API design. This post belongs to my favorite Java Best Practices Series category. Before designing and developing Rest API, I suggest you read this guide to develop good Restful API.
The URL is a sentence, where resources are nouns and HTTP methods are verbs.
Here are few best practices to design a clean RESTful API.

2. Restful API Design Best Practices

Restful API Design Best Practices

2.1. Use Nouns for Resource Identification

For an easy understanding use this structure for every resource:
  • GET - /users - Returns a list of users
  • GET - users/100 - Returns a specific user
  • POST - /users - Create a new user
  • PUT - /users/ - Updates a specific user
  • DELETE - /users/711 - Deletes a specific user
Do not use verbs:
/getAllUsers
/getUserById
/createNewUser
/updateUser
/deleteUser

2.2. Use Proper HTTP Headers for Serialization Formats

Both client and server, need to know which format is used for the communication. The format has to be specified in the HTTP-Header.
Content-Type defines the request format.
Accept defines a list of acceptable response formats.

2.3. Get Method and Query Parameters Should Not Alter the State

Use PUT, POST and DELETE methods instead of the GET method to alter the state. Do not use GET for state changes:
GET /users/711?activate or
GET /users/711/activate

2.4. Use Sub-Resources for Relations

If a relation can only exist within another resource, RESTful principles provide useful guidance.
If a resource is related to another resource using subresources.
GET /cars/711/drivers/ Returns a list of drivers for car 711
GET /cars/711/drivers/4 Returns driver #4 for car 711
One more example:
These messages can be logically mapped to the /tickets endpoint as follows:
  • GET /tickets/12/messages - Retrieves a list of messages for ticket #12
  • GET /tickets/12/messages/5 - Retrieves message #5 for ticket #12
  • POST /tickets/12/messages - Creates a new message in ticket #12
  • PUT /tickets/12/messages/5 - Updates message #5 for ticket #12
  • PATCH /tickets/12/messages/5 - Partially updates message #5 for ticket #12
  • DELETE /tickets/12/messages/5 - Deletes message #5 for ticket #12

2.5. Use Proper HTTP Methods (Verbs)

HTTP methods used by most RESTful web APIs are:
The URL is a sentence, where resources are nouns and HTTP methods are verbs.
  • GET retrieves a representation of the resource at the specified URI. The body of the response message contains the details of the requested resource.
  • POST creates a new resource at the specified URI. The body of the request message provides the details of the new resource. Note that POST can also be used to trigger operations that don't actually create resources.
  • PUT either creates or replaces the resource at the specified URI. The body of the request message specifies the resource to be created or updated.
  • PATCH performs a partial update of a resource. The request body specifies the set of changes to apply to the resource.
  • DELETE removes the resource at the specified URI.

2.6. HTTP Response Status Codes

When the client raises a request to the server through an API, the client should know the feedback, whether it failed, passed or the request was wrong. HTTP status codes are a bunch of standardized codes which has various explanations in various scenarios. The server should always return the right status code.
The following are the important categorization of HTTP codes:
2xx (Success category) These status codes represent that the requested action was received and successfully processed by the server.
  • 200 Ok The standard HTTP response representing success for GET, PUT or POST.
  • 201 Created This status code should be returned whenever the new instance is created. E.g on creating a new instance, using POST method, should always return 201 status code.
  • 204 No Content represents the request is successfully processed but has not returned any content.DELETE can be a good example of this. The API DELETE /companies/43/employees/2 will delete the employee 2 and in return we do not need any data in the response body of the API, as we explicitly asked the system to delete. If there is any error, like if employee 2 does not exist in the database, then the response code would be not be of 2xx Success Category but around 4xx Client Error category.
3xx (Redirection Category)
  • 304 Not Modified indicates that the client has the response already in its cache. And hence there is no need to transfer the same data again.
4xx (Client Error Category) These status codes represent that the client has raised a faulty request.
  • 400 Bad Request indicates that the request by the client was not processed, as the server could not understand what the client is asking for.
  • 401 Unauthorized indicates that the client is not allowed to access resources, and should re-request with the required credentials.
  • 403 Forbidden indicates that the request is valid and the client is authenticated, but the client is not allowed access the page or resource for any reason. E.g sometimes the authorized client is not allowed to access the directory on the server.
  • 404 Not Found indicates that the requested resource is not available now.
  • 410 Gone indicates that the requested resource is no longer available which has been intentionally moved.
5xx (Server Error Category)
  • 500 Internal Server Error indicates that the request is valid, but the server is totally confused and the server is asked to serve some unexpected condition.
  • 503 Service Unavailable indicates that the server is down or unavailable to receive and process the request. Mostly if the server is undergoing maintenance.

2.7. Field Name Casing Convention

You can follow any casing convention, but make sure it is consistent across the application. If the request body or response type is JSON then please follow camelCase to maintain the consistency.

2.8. Searching, Sorting, Filtering, and Pagination

All of these actions are simply the query on one dataset. There will be no new set of APIs to handle these actions. We need to append the query params with the GET method API. Let’s understand with a few examples of how to implement these actions.
  • Sorting In case, the client wants to get the sorted list of companies, the GET /companiesendpoint should accept multiple sort params in the query. E.g GET /companies?sort=rank_asc would sort the companies by its rank in ascending order.
  • Filtering For filtering the dataset, we can pass various options through query params. E.g GET /companies?category=banking&location=india would filter the companies list data with the company category of Banking and where the location is India. 
  • Searching When searching for the company name in companies list the API endpoint should be GET /companies?search=Digital .
  • Pagination When the dataset is too large, we divide the data set into smaller chunks, which helps in improving the performance and is easier to handle the response. Eg. GET /companies?page=23 means get the list of companies on 23rd page.

2.9. Restful API Versioning

Make the API Version mandatory and do not release an unversioned API. Use a simple ordinal number and avoid dot notation such as 2.5.
We are using the URL for the API versioning starting with the letter "v"
Examples:
/blog/api/v1
http://api.yourservice.com/v1/companies/34/employees

2.10. Provide Links for Navigating Through Your API (HATEOAS)

Hypermedia as the Engine oApplication State is a principle that hypertext links should be used to create a better navigation through the API.
A hypermedia-driven site provides information to navigate the site’s REST interfaces dynamically by including hypermedia links with the responses.
A HATEOAS-based response would look like this:
{
    "name": "Alice",

    "links": [ {

        "rel": "self",

        "href": "http://localhost:8080/customer/1"

    } ]
}
This response not only has the person’s name but includes the self-linking URL where that person is located.
  • rel means relationship. In this case, it’s a self-referencing hyperlink. For example, an order might have a “rel”:”customer” relationship, linking the order to its customer.
  • href is a complete URL that uniquely defines the resource.

2.11. Handling ERROR JSON

In an API handling error is important and it requires careful planning.
And it’s highly recommended that always return the error message in its own set of field. A JSON error body should provide a few things for the developer – a useful error message, a unique error code (that can be looked up for more details in the docs) and possibly a detailed description.
A good error message response might look something like this:
{
   “code”: 1234,
   “message” : “Something bad happened :(“,
   “description” : “More details about the error here”
}

2.12. How to create Rest API URL

URI is assigned to the extracted resource for identifying it.
It is recommended to use the following formats for the URL.
http(s)://{Domain name (:Port number)}/{A value indicating REST API}/{API version}/{path for identifying a resource}

http(s)://{Domain name indicating REST API(:Port number)}/{API version}/{path for identifying a resource}
A typical example is given below.

3. Conclusion

This post explained the best practices for Restful API design. Learn more about Jersey Rest framework on Jersey Rest Developer Guide.
All the code of this article is available over on Github. This is a Maven-based project, so it should be easy to import and run as it is.

4. Related Posts


If you are new to REST API development, I suggest reading my RESTful Tutorial for beginners.

Comments