Best Practices For RESTful API
RESTful is currently the most popular API design specification used for designing web data interfaces.
Its main principles are easy to grasp, but getting the details right takes work. This article summarizes the design details of RESTful and introduces how to design APIs that are easy to understand and use.

1. URL design
1.1 Verb + Object
The core idea of RESTful is that the data operation instructions sent by the client are in the “verb + object” structure. For example, in the command GET /articles, GET is the verb, and /articles is the object.
The verbs usually correspond to the five HTTP methods, which represent CRUD operations.
- GET: Read
- POST: Create
- PUT: Update
- PATCH: Update, Usually it is a partial update.
- DELETE: Delete
According to the HTTP specification, verbs are always capitalized.
1.2 Coverage of verbs
Some clients can only use the GET and POST methods. The server must accept POST to simulate the other three methods (PUT, PATCH, DELETE).
In this case, the client’s HTTP request should include the X-HTTP-Method-Override property to tell the server which verb to use and override the POST method.
POST /api/Person/4 HTTP/1.1 X-HTTP-Method-Override: PUT
In the above code, X-HTTP-Method-Override specifies that the method of this request is PUT instead of POST.
1.3 The object must be a noun
The object is the URL of the API, which is the target of the HTTP verb. It should be a noun and not a verb. For example, /articles is a correct URL, while the following URLs are incorrect because they are not nouns.
- /getAllCars
- /createNewCar
- /deleteAllRedCars
1.4 plural URLs
Since URL is a noun, should it be used in plural or singular form?
There is no unified rule for this, but the common practice is to read a collection, such as GET /articles (read all articles), where it should be in plural form.
For the sake of consistency, it is recommended to use plural URLs. For example, GET /articles/2 is better than GET /article/2.
1.5 Avoid multi-level URLs.
The common situation is that resources need to be classified into multiple levels, so it is easy to create multi-level URLs, such as accessing a certain author’s articles of a specific category.
GET /authors/12/categories/2
This kind of URL is not conducive to scalability and the semantics are also unclear. Often, it takes some time to understand the meaning.
A better approach is to use query strings for all levels except the first level.
GET /authors/12?categories=2
Here is another example, querying published articles. You may design it as the following URL.
GET /articles/published
The writing style of the query string is better.
GET /articles?published=true
2. Status code
2.1 The status code must be accurate
For every request from the client, the server must respond. The response includes an HTTP status code and data.
The HTTP status code is a three-digit number divided into five categories.
1xx:
Relevant information2xx:
Operation successful3xx:
Redirection4xx:
Client error5xx:
Server error
These five categories include more than 100 status codes in total, covering the majority of possible situations. Each status code has a standard (or agreed upon) explanation, and clients can determine what happened by simply checking the status code. Therefore, servers should return as accurate a status code as possible.
APIs do not require 1xx status codes. The precise meanings of the other four categories of status codes are described below.
2.2 2xx Status Codes
The 200 status code indicates a successful operation, but different methods can return more accurate status codes.
- GET: 200 OK
- POST: 201 Created
- PUT: 200 OK
- PATCH: 200 OK
- DELETE: 204 No Content
In the above code, POST returns a status code of 201, indicating that a new resource has been created; DELETE returns a status code of 204, indicating that the resource no longer exists.
In addition, the status code 202 Accepted indicates that the server has received the request but has not yet processed it. It will be processed in the future and is usually used for asynchronous operations. Here is an example.
HTTP/1.1 202 Accepted
{
"task": {
"href": "/api/company/job-management/jobs/2130040",
"id": "2130040"
}
}
2.3 3xx status codes
API does not need to use the 301 status code (permanent redirect) and the 302 status code (temporary redirect, also known as 307), because they can be returned at the application level and the browser will directly jump. The API level does not need to consider these two situations.
The 3xx status codes used by APIs mainly include 303 See Other, which means referring to another URL. It has the same meaning as 302 and 307, which is “temporary redirect”, but differs in that 302 and 307 are used for GET requests, while 303 is used for POST, PUT, and DELETE requests. After receiving a response with a status code of 303, the browser will not automatically redirect but let users decide what to do next. Here is an example.
HTTP/1.1 303 See Other
Location: /api/orders/12345
2.4 4xx status codes
4xx
Status codes indicate client errors, mainly the following types:
400 Bad Request:
The server does not understand the client’s request and does not take any action.
401 Unauthorized:
The user did not provide authentication credentials or did not pass the authentication.
403 Forbidden:
The user has passed identity verification but does not have the necessary permissions to access the resources.
404 Not Found:
The requested resource does not exist or is unavailable.
405 Method Not Allowed:
The user has been authenticated, but the HTTP method used is not within their permissions.
410 Gone:
The requested resource has been moved from this address and is no longer available.
415 Unsupported Media Type:
The requested return format is not supported. For example, the API can only return JSON format, but the client requests XML format to be returned.
422 Unprocessable Entity:
The attachment uploaded by the client cannot be processed, resulting in a failed request.
429 Too Many Requests:
The number of client requests exceeds the limit.
2.5 5xx status codes
5xx
The status code represents a server error. Generally speaking, the API will not disclose detailed information about the server to the user, so only two status codes are sufficient.
500 Internal Server Error:
The client’s request is valid, but an unexpected error occurred during server processing.
503 Service Unavailable:
The server is unable to process the request, typically used for website maintenance status.
3. Server response
3.1 Do not return pure plaintext
The format of the data returned by the API should not be plain text, but a JSON object, so that standardized structured data can be returned. Therefore, the Content-Type attribute of the HTTP header in the server’s response should be set to application/JSON.
When requesting the client side, it is also necessary to explicitly inform the server that JSON format is acceptable. This means that the ACCEPT attribute of the HTTP header in the request should also be set to application/JSON. Here is an example.
GET /orders/2 HTTP/1.1 Accept: application/json
3.2 When an error occurs, do not return a 200 status code
There is an inappropriate practice, which is to return a 200 status code even if there is an error and put the error message inside the data body, just like the example below.
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "failure",
"data": {
"error": "Expected at least two items in list."
}
}
After parsing the data body in the above code, only then can we know that the operation has failed.
This approach eliminates the status code, which is completely unacceptable. The correct approach is to have the status code reflect the occurred error and specific error information should be returned within the data body. Here is an example.
HTTP/1.1 400 Bad Request
Content-Type: application/json
{
"error": "Invalid payoad.",
"detail": {
"surname": "This field is required."
}
}
3.3 Provide a link
API users may not necessarily know how URLs are designed. One solution is to provide relevant links in the response to facilitate further operations. In this way, users only need to remember one URL to discover other URLs. This method is called HATEOAS.
For example, GitHub’s API is located at the api.github.com domain. By accessing it, other URLs can be obtained.
{
...
"feeds_url": "https://api.github.com/feeds",
"followers_url": "https://api.github.com/user/followers",
"following_url": "https://api.github.com/user/following{/target}",
"gists_url": "https://api.github.com/gists{/gist_id}",
"hub_url": "https://api.github.com/hub",
...
}
In the above response, by selecting a URL to access, you can obtain other URLs. For users, there is no need to remember URL designs, just search step by step from api.github.com.
There is no unified specification for the format of HATEOAS. In the example above, GitHub puts them together with other attributes. A better practice would be to separate related links from other attributes.
HTTP/1.1 200 OK
Content-Type: application/json
{
"status": "In progress",
"links": {[
{ "rel":"cancel", "method": "delete", "href":"/api/status/12345" } ,
{ "rel":"edit", "method": "put", "href":"/api/status/12345" }
]}
}
4. Reference link
- RESTful API Design: 13 Best Practices to Make Your Users Happy, by Florimond Manca
- API design, by Microsoft Azure
Thank you for your viewership, until we meet again!