This is a creation in Article, where the information may have evolved or changed.
Original: RESTful API Design. Best practices in a nutshell.
Author: Philipp Hauer
How should the URL of the project resource be designed? by plural or by noun singular? How many URLs does a resource need? What kind of HTTP method is used to create a new resource? Where should the optional parameters be placed? What about URLs that don't involve resource manipulation? What's the best way to achieve paging and versioning? Because there are so many questions, designing restful APIs becomes tricky. In this article, let's look at the RESTful API design and give a best practice scenario.
Use two URLs per resource
A resource collection uses a URL that uses one URL for a specific resource:
/employees #资源集合的URL/employees/56 #具体某个资源的URL
Use nouns instead of verbs to indicate resources
This makes your API cleaner and the number of URLs less. Don't design this:
/getAllEmployees/getAllExternalEmployees/createEmployee/updateEmployee
Better design:
GET /employeesGET /employees?state=externalPOST /employeesPUT /employees/56
Manipulating resources with HTTP methods
Use the URL to specify the resource you want to use. Use the HTTP method to specify what to do with this resource. Using the four HTTP methods Post,get,put,delete can provide CRUD functionality (create, GET, update, delete).
- get : Use the Get method to get the resource. The GET request does not change the state of the resource. No side effects. The Get method is idempotent. The Get method has a read-only meaning. Therefore, you can use the cache perfectly.
- Create : Use post to create a new resource.
- Update : Update existing resources with put.
- Delete : Deletes an existing resource using Delete.
2 URLs multiplied by 4 HTTP methods is a good set of features. Look at this table:
|
POST (Create) |
GET (Read) |
PUT (update) | Delete
(remove) |
/employees |
Create a new employee |
List all employees |
Batch update of employee information |
Delete all employees |
/employees/56 |
Error |
Get information on employee number 56th |
Update information for Employee No. 56th |
Delete Employee No. 56th |
Use the Post method for the URL of a resource collection to create a new resource
When a new resource is created, how does the client interact with the server?
Use post on the Resource collection URL to create a new resource procedure
- The client sends a POST request to the Resource collection URL
/employees
. The HTTP body contains the properties of the new resource "Albert Stark".
- The RESTful Web server generates an ID for the new employee, creates an employee in its internal model, and sends a response to the client. The HTTP header for this response contains a location field that indicates the URL to which the resource can be accessed.
Use the Put method for URL-specific resources to update resources
Use put to update an existing resource.
- The client sends a PUT request to the URL of the specific resource
/employee/21
. The requested HTTP body contains the attribute value to be updated (the new name of Employee No. 21st "Bruce Wayne").
- The rest server updates the employee name with ID 21 and uses HTTP status code 200 to indicate that the change was successful.
Recommended plural nouns
Recommended:
/employees/employees/21
Not recommended:
/employee/employee/21
In fact, this is a matter of personal preference, but the plural form is more common. In addition, the Get method is used on the Resource collection URL, which is more intuitive, especially,, GET /employees?state=external
POST /employees
PUT /employees/56
. But the most important thing is to avoid mixed use of plural and singular nouns, which is very confusing and error prone.
For optional, complex parameters, use the query string (? )。
Not Recommended Practice:
GET /employeesGET /externalEmployeesGET /internalEmployeesGET /internalAndSeniorEmployees
To make your URLs smaller and more concise. Sets a basic URL for the resource, with optional, complex parameters represented by a query string.
GET /employees?state=internal&maturity=senior
Using HTTP status Codes
RESTful Web services should respond to client requests with appropriate HTTP status codes
- 2XX-Success-everything is fine
- 4XX-Client Error-If the client has an error (such as a client sending an invalid request or not being authorized)
- 5xx– Server Error-refer to the HTTP status code on Wikipedia if the server has an error (for example, an error occurred while trying to process the request). However, most of these HTTP status codes will not be used, only a small portion of them will be used. It usually uses a few:
2xx: Success |
3xx: | redirect
4xx: Client Error |
5xx: Server error |
200 Successes |
301 Permanent Redirection |
400 Error request |
500 Internal Server Error |
201 Create |
304 Resource Not modified |
401 Not authorized |
|
|
|
403 Forbidden |
|
|
|
404 Not Found |
|
Return useful error hints
In addition to the appropriate status codes, you should provide useful error hints and detailed descriptions in the HTTP response body. This is an example. Request:
GET /employees?state=super
Response:
// 400 Bad Request{ "message": "You submitted an invalid state. Valid state values are 'internal' or 'external'", "errorCode": 352, "additionalInformation" : "http://www.domain.com/rest/errorcode/352"}
Using the small Hump naming method
Use the small hump naming method as the attribute identifier.
{ "yearOfBirth": 1982 }
Do not use underscores ( year_of_birth
) or Large hump nomenclature ( YearOfBirth
). Typically, RESTful Web services are used by clients written by JavaScript. The client translates the JSON response into a JavaScript object (by calling var person = JSON.parse(response)
) and then invokes its properties. Therefore, it is best to follow the common specifications for JavaScript code.
Contrast:
person.year_of_birth // 不推荐,违反JavaScript代码通用规范person.YearOfBirth // 不推荐,JavaScript构造方法命名person.yearOfBirth // 推荐
Force the version number to be added in the URL
From start to finish, use the version number to publish your restful API. It is necessary to place the version number in the URL. If you have incompatible and disruptive changes, the version number will make it easier for you to publish the API. When you publish a new API, you only need to increase the number in the version number. In this way, the client can easily migrate to the new API without getting bogged down by invoking a completely different new API.
Use the intuitive "V" prefix to indicate that the following number is the version number.
/v1/employees
You do not need to use the secondary version number ("v1.2") because you should not publish the API version frequently.
Provide paging information
It is not a good idea to return all the resources in a database at once. Therefore, a paging mechanism is required. Commonly known parameters offset and limit are used in the database.
/employees?offset=30&limit=15 #返回30 到 45的员工
If the client does not pass these parameters, the default value should be used. Usually the default value is the offset = 0
and limit = 10
. If the database retrieval is slow, the value should be reduced limit
.
/employees #返回0 到 10的员工
In addition, if you are using paging, the client needs to know the total number of resources. Example: Request:
GET /employees
Response:
{ "offset": 0, "limit": 10, "total": 3465, "employees": [ //... ]}
Non-resource requests with verbs
Sometimes API calls do not involve resources (such as calculations, translations, or transformations). Cases:
GET /translate?from=de_DE&to=en_US&text=HalloGET /calculate?para2=23¶2=432
In this scenario, the API response does not return any resources. Instead, an operation is performed and the results are returned to the client. Therefore, you should use verbs instead of nouns in URLs to clearly differentiate between resource requests and non-resource requests.
Consider specific resource searches and cross-resource searches
It is easy to provide a search for a specific resource. Simply use the appropriate resource collection URL and append the search string to the query parameters.
GET /employees?query=Paul
If you want to provide global search for all resources, you need to use a different method. As mentioned earlier, for non-resource request URLs, verbs are used instead of nouns. Therefore, your search URL might look like the following:
GET /search?query=Paul //返回 employees, customers, suppliers 等等.
Add a link to browse other APIs in the response parameter
Ideally, the client is not allowed to construct a URL using the rest API itself. Let's consider an example. The client wants to access the employee's compensation table. To do this, he must know that he can /employees/21/salaryStatements
access the compensation table by appending the string "salarystatements" to the employee URL (for example). This string connection is error-prone and difficult to maintain. If you change the way you access the rest API of the payroll table (for example, it becomes a /employees/21/salary-statement
or /employees/21/paySlips
), all clients will be interrupted. A better solution would be to add a field to the response parameter to links
allow the client to change automatically.
Request:
GET /employees/
Response:
//... { "id":1, "name":"Paul", "links": [ { "rel": "salary", "href": "/employees/1/salaryStatements" } ] },//...
If the client relies entirely on links
the fields in the payroll, and you change the API, the client will always get a valid URL (as long as you change the link
field, the requested URL will automatically change) and will not be interrupted. Another benefit is that your API becomes self-describing and requires fewer documents to write.
When paging, you can also add an example of a link that gets the next or previous page. Simply provide examples of links with appropriate offsets and restrictions.
GET /employees?offset=20&limit=10
{ "offset": 20, "limit": 10, "total": 3465, "employees": [ //... ], "links": [ { "rel": "nextPage", "href": "/employees?offset=30&limit=10" }, { "rel": "previousPage", "href": "/employees?offset=10&limit=10" } ]}
Related reading:
- The author wrote an article on best practices for testing RESTful services in Java.
- The author strongly recommends a book brain Mulloy's nice paper as the basis for this article.