RESTful API Design Best Practices

Source: Internet
Author: User
Tags print format representational state transfer rfc unsupported

1. Background

REST(English: Representational State Transfer Representational State transfer) describes a schema-style network system, such as a Web application.

At present, the Internet is flooded with RESTful API articles about how to design (for convenience, " RESTful API shorthand for" API ), but there is no "universal" design standard: How to Authentication? What is the API format? Should your API include version information? When you start to write an app, especially when the backend model is finished, you have to design and implement the public API part of your app. Because once published, the API will be difficult to change.

In order to design an API that is easy to use, easy to deploy, and flexible enough, this article is born.

2. Basic Requirements for API design

Many of the ideas on the web about API design are "college", they may be more theoretical, but sometimes derail the real world (so I'm a liberal). So my goal in this article is to start from a practical point of view and give the best practices of API design for current Web applications. Of course, as the basis of design, a few of the principles must be adhered to:

    • Comply with standards when the standards are reasonable.
    • The API should be programmer-friendly and easy to enter in the browser's address bar.
    • The API should be simple, intuitive, easy to use and elegant at the same time.
    • The API should be flexible enough to support the upper UI.
    • The API design weighs several of these principles.

It is important to emphasize that the API is the programmer's UI, and like any other UI, you must carefully consider its user experience!

3. Use RESTful URLs and action.

Although I said before I did not have a universal API design standard. But there is one that is universally recognized and adhered to: RESTful design principles. It was presented by Roy Felding (fifth chapter in his "Web-based Software Architecture" paper). The core principle of rest is to split your API into logical resources . These resources are manipulated via HTTP ( GET ,,, POST PUT DELETE ).

4. How should I split these resources?

Obviously from an API user's point of view, " resources " should be a noun. Even if your internal data model and resources already have a good correspondence, API design you still do not need to expose them to one-on. The key here is to hide the internal resources and expose the necessary external resources.

In SupportFu , resources are ticket , and user group .


Once you have defined the resources you want to expose, you can define the actions that are allowed on the resource, and the corresponding relationships between those actions and your API:

    • Get/tickets # Get Ticket list

    • GET/TICKETS/12 # to view a specific ticket POST

    • /tickets # Create a new ticket

    • PUT/TICKETS/12 # Update Ticket 12.

    • DELETE/TICKETS/12 #删除ticekt 12

It can be seen REST that the advantage of using HTTP is to make full use of the powerful implementation of the ( CURD Create ( Create ), update ( Update ), read (Read ) and delete () Delete ) functions of the resource. And here you just need a endpoint:/tickets, no other naming rules and URL rules, cool!

5. The singular plural of this endpoint

One rule to follow is that although it seems awkward to use complex numbers to describe a resource instance, unifying all of them endpoint makes your URLs more structured using complex numbers. This makes it easier for API users to understand and easier for developers to implement.

How do I handle associations? There is also a description of how to handle the management principles between resources REST :

    • Get/tickets/12/messages-retrieves (Enquiry) 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

Where, if this association and resource are independent, we can save the corresponding resource in the output representation of the resource endpoint . The user of the API can then find the relevant resources by clicking on the link. If the association and resources are closely linked. The output of the resource indicates that the corresponding resource information should be saved directly. (for example, if the message resource exists independently, the get/tickets/12/messages on the above will return a link to the corresponding message; If the message does not exist independently, he and ticket are attached, The above API call returns a direct return message)

6. Non-conformance to curd operation

For this puzzling question, here are some workarounds:

    1. Refactor your behavior action . When your behavior does not require parameters, you can put the active corresponding to activated this resource, (update use patch ).

    2. Treated with sub-resources. For example: github on, to one gists star operation: PUT /gists/:id/star and Cancel star operation: DELETE /gists/:id/sta R.

    3. Sometimes it action is not difficult to correspond with a resource for example search . Then let's do it. I don't think the user of the API /search will have much of a problem with this URL (he's easy to understand, after all). Just note that you can write clearly in the document.

7. Always use SSL (secure Sockets Layer Security socket)

SSL is always used, without exception. Your app doesn't know who to be, and what the situation is. Some are safe, some are not. Using SSL can reduce the cost of authentication: You only need a simple token () to token be able to be authenticated, rather than having the user sign each request every time.

It is important to note that non-SSL URL access is not redirected to the SSL URL.

8. Documentation

Documentation is as important as the API itself. Documents should be easy to find and open (hiding them in a PDF or saving them in a place where they need to be logged in is not very good). The document should have an example of displaying requests and outputs: either by clicking on the link or by means of curl. If there is an update (especially a public API), the document should be updated in a timely manner. The documentation should have a schedule and details about when to discard an API. It's a good way to use mailing lists or blog entries.

9. Versioning

Adding version information to the API effectively prevents users from accessing the updated API, while also allowing for a smooth transition between different major versions. There is a controversy over whether to put the version information into the URL or the request header: API version should be included in the URL or in a header. Academia says it should be put in the header, but if you put it in the URL we can access the resources across versions.

The method used by strip is good: It has the main version information in its URL, and the request of the first two sides has the child version information. This makes the URL stable during the change of the child version. Change is sometimes unavoidable, and the key is how to manage change. Complete documentation and a reasonable schedule make it easier for API users to use.

10. Results filter, sort, search:

URLs are best as short as possible, and results are filtered, sorted, and search-related functions should be implemented via parameters (and also easily implemented).

filtering : Provides uniform parameters for all interfaces that provide filtering functionality. For example: you want to limit get /tickets The return result: only those states are returned open ticket–get /tickektsstate=open here state is the filter parameter.

sort : As with filtering, a good sort parameter should be able to describe the collation rather than the business-related. Complex collations should be implemented by combining:

    • Get/ticketssort=-priority-retrieves a list of tickets in descending order of priority

    • Get/ticketssort=-priority,created_at-retrieves a list of tickets in descending order of priority. Within a specific priority, older tickets is ordered first

In the second query here, the collation has more than one rule that is combined with a comma interval.

Search : Sometimes a simple sort is not enough. We can use search technology (Elasticsearch and Lucene) to implement (still as a parameter to the URL).

    • Get/ticketsq=return&state=open&sort=-priority,created_at-retrieve the highest priority open tickets Mentioning the word ' return '

For frequently used search queries, we can create aliases for them, which will make the API more elegant. For example:
get /ticketsq=recently_closed -> get /tickets/recently_closed.

11. Domains that limit API return values

Sometimes the API consumer does not need all the results, and it should be possible to limit the vertical when the horizontal limit is placed (for example, the top ten of the value return API results). And this function can effectively improve the network bandwidth usage and speed. You can use the fields query parameter to limit the domains returned, such as:

    • Get/ticketsfields=id,subject,customer_name,updated_at&state=open&sort=-updated_at
12. Update and create operations should return resources

PUT, POST and PATCH operations often have some side effects when working with resources: for example created_at , timestamps updated_at . To prevent the user from making multiple API calls (for this update), we should return the updated resource ( updated representation .) For example: After the POST operation, 201 created a status code is returned, and a URL to the new resource is included as the return header.

13. Need for "HATEOAS" (Hypermedia as the Engine of application state)

Online about whether to allow users to create a new URL has a big objection (note is not to create a resource-generated URL). The REST HATEOAS endpoint behavior should be defined in the metadata return value of the resource when it is developed to describe and interact with it.

(the author thinks that Hateoas is not mature yet)

14. Provide JSON as return format only

Now it's time to compare XML and json . XMLthat is lengthy, difficult to read, and not suitable for various programming language parsing. Of course XML There is the advantage of extensibility, but if you just serialize it to internal resources, then his extended advantage is not going to work out. Many applications ( youtube , twitter , box ) have started to abandon XML . Give the trend map on Google:



Of course if you use users inside the majority of enterprise users, then may need support XML . If this is the case, you have another question: is the http type in your request to be media synchronized with the accept head or with url ? In order to facilitate ( browser explorability ), it should be in url (the user as long as they spell url it good). The best way to do this is to use .xml or .json the suffix.

15. Naming Methods

is the serpentine command (underscore and lowercase) or hump named (mixed with uppercase and lowercase letters to form the names of variables and functions)? If you use JSON then the best thing to do is JAVASCRIPT to follow the naming method-that is, the camel name method. If you are writing a library in multiple languages, it is best to follow the recommendations of those languages, java C# using camels, python and ruby using snake .

Personal opinion: I always feel that the snake command better make some, of course, there is no theoretical basis for this. Some people say that snake name read faster, can reach 20%, do not know true and false http://ieeexplore.ieee.org/xpl/articleDetails.jsptp=&arnumber=5521745

16. Use pretty print format by default, using gzip

Just use the return results of the spaces from the browser always feel disgusting. Of course you can provide the parameters on the URL to control the use of "pretty print", but it is more friendly to turn on this option by default. The loss on the extra transmission will not be too great. Conversely if you forget to use gzip then the transfer efficiency will be greatly reduced and the loss greatly increased. Imagine a user is debugging so the default output is readable--without having to copy the results to any other software in the format--it's cool to think about it, isn't it?

Here is an example:

$ curl https://API.github.com/users/veesahni > with-whitespace.txt$ ruby -r json -e ‘puts JSON JSON.parse(STDIN.read)‘ < with-whitespace.txt > without-whitespace.txt$ gzip -c with-whitespace.txt > with-whitespace.txt.gz$ gzip -c without-whitespace.txt > without-whitespace.txt.gz

The output is as follows:

    • without-whitespace.txt-1252 bytes
    • with-whitespace.txt-1369 bytes
    • without-whitespace.txt.gz-496 bytes
    • with-whitespace.txt.gz-509 bytes

In the example above, the extra space makes the result more than 8.5% (gzip not used), instead only 2.6% more. It is said that Twitter has reduced 80% (Link:https://dev.twitter.com/blog/announcing-gzip-compression-streaming-apis) by using Gzip after its streaming API transfer.

17. Use "envelope" (envelope) only when needed

Many APIs return results like this:

{  "data" : {    "id" : 123,    "name" : "John"  }}

The reason is simple: this can easily extend the return result, you can add some paging information, some meta-information of the data, etc.-this is useful for those API users who are not easily accessible to the return header, but with the development of "standards" ( cors and http://tools.ietf.org/html/rfc5988#page-6 all of them beginning to be added to the standard), I personally recommend not doing that.

18. When to use envelope?

There are two situations that should be used envelope . If the API consumer does not have access to the return header, or the API needs to support cross-domain requests (through jsonp ).

jsonpThe request contains a function parameter in the URL of the request callback . If this parameter is given, then the API should return 200 and put the real state into the return value (wrapped in an envelope), for example:

callback_function({  status_code: 200,  next_page: "https://..",  response: {    ... actual JSON response body ...   }})

Similarly, to support an API consumer that cannot return a header to a method, envelope=true such a parameter can be allowed.

19. Use JSON as input on Post,put,patch

If you agree with what I said above, then you should decide to use json as all the API output formats, then we'll consider the input data format of the API next.

Many APIs use URL-encoded formats: Just like the format of URL query parameters: Simple key-value pairs. This method is simple and effective, but it has its own problem: it has no concept of data type. This allows the program to parse the Boolean and integer based on the string, and there is no hierarchy – although there are some conventions about hierarchy information that are json still not very useful compared to the support hierarchy itself.

Of course, if the API itself is simple, then using the URL format input is fine. But for complex APIs you should use json . Or simply use it uniformly json .

Note json when using the transfer, the request header is added: Content-Type:application/json ., otherwise throws a 415 exception (unsupported media type).

20. Paging

The paging data can be put into "envelopes", but with the improvement of the standard, I now recommend putting paging information link header inside: http://tools.ietf.org/html/rfc5988#page-6.

link headerthe API used should return a series of well-assembled URLs instead of letting the user spell it out for themselves. This is especially important in cursor-based paging. For example, a document from GitHub

Link: 
21. Automatic loading of related resources

Many times, it is very useful to automatically load related resources, which can greatly improve the efficiency. But this is contrary to the principle of restful. To do so, we can add parameters to the URL: embed (or expend ). embedcan be a comma-separated string, for example:

GET /ticket/12embed=customer.name,assigned_user

The corresponding API return values are as follows:

{  "id" : 12,  "subject" : "I have a question!",  "summary" : "Hi, ....",  "customer" : {    "name" : "Bob"  },  assigned_user: {   "id" : 42,   "name" : "Jim",  }}

It is worth reminding that this feature can sometimes be complex and can cause N+1 SELECT problems.

22. Overriding the HTTP method

Some clients can only issue simple GET and POST request. In order to take care of them, we can rewrite the HTTP request. There is no standard here, but a common way is to accept the X-HTTP-Method-Override request header.

23. Speed Limit

To avoid flooding requests, it is important to set speed limits on the API. RFC 6585The HTTP status code is introduced for this purpose 429(too many requests) . After adding the speed setting, the user should be prompted, as to how the standard is not indicated, but the popular method is to use the HTTP return header.

Here are a few of the required return headers (according to Twitter's naming conventions):

    • X-rate-limit-limit: Number of concurrent requests allowed for the current time period
    • X-rate-limit-remaining: The number of requests reserved for the current time period.
    • X-rate-limit-reset: Number of seconds remaining in the current time period
24. Why use the remaining seconds of the current time period instead of the timestamp?

Timestamps save a lot of information, but also contain a lot of unnecessary information, users only need to know that there are only a few seconds left to send the request again so that also avoids the clock skew problem.

Some APIs use UNIX format timestamps, and I don't recommend doing that. Why? HTTP already specifies the use RFC 1123 time format

25. Authentication Authentication

restful APIIs stateless , which means that the user's request for authentication is irrelevant to the cookie and the session, and each request should contain a verification certificate.

By using ssl we can not provide the user name and password every time: we can give the user back a randomly generated token . This makes it extremely convenient for users who use the browser to access the API. This method is applicable to the user can first pass the user name-password authentication and get token , and can copy the returned token to a later request. If inconvenient, can be used OAuth 2 to carry out token the safe transfer.

jsonpthe supported API requires an additional authentication method because the jsonp request cannot be sent as normal credential . In this case, you can add parameters to the query URL: access_token . Note the problem with the URL parameter is that most of the network servers currently have query parameters saved to the server log, which can be a major security risk.

Note that the above mentioned is only three transmission token的 methods, the actual transmission token may be the same.

26. Caching

HTTP provides a self-signed cache framework. What you need to do is add some return header information when you return and add input validation when you accept the input. There are two basic methods:

ETag: When a request is generated, it is added in the HTTP header ETag , which contains the checksum and hash value of the request, and this value should change as the input changes. If the input HTTP request contains IF-NONE-MATCH a header and a ETag value, then the API should return the 304 not modified status code instead of the regular output.

last-modified: And the etag same, just one more time stamp. Returned to the head Last-Modified : contains the timestamp RFC 1123 , and it is IF-MODIFIED-SINCE consistent. There are three kinds of date formats in the HTTP specification, and the server should be able to handle them.

27. Error Handling

Just as the HTML error page can display an error message, the API should also return a readable error message – It should be consistent with the general resource format. The API should always return the appropriate status code to reflect the status of the server or request. API error codes can be divided into two parts, 400 series and 500 series, and400 series indicate client error : such as bad Request format. The 500 series represents a server error . The API should return at least all of the 400 series errors in the json form. This should be true if the 500 series errors are possible. Errors in JSON format should contain the following information: A useful error message, a unique error code, and any possible detailed error description. As follows:

{  "code" : 1234,  "message" : "Something bad happened :-(",  "description" : "More details about the error here"}

Yes PUT , POST PATCH The input checksum should also return the corresponding error message, for example:

{  "code" : 1024,  "message" : "Validation Failed",  "errors" : [    {      "code" : 5432,      "field" : "first_name",      "message" : "First name cannot have fancy characters"    },    {       "code" : 5622,       "field" : "password",       "message" : "Password cannot be blank"    }  ]}
HTTP Status Code
 200 ok  - 成功返回状态,对应,GET,PUT,PATCH,DELETE. 201 created  - 成功创建。 304 not modified   - HTTP缓存有效。 400 bad request   - 请求格式错误。 401 unauthorized   - 未授权。 403 forbidden   - 鉴权成功,但是该用户没有权限。 404 not found - 请求的资源不存在 405 method not allowed - 该http方法不被允许。 410 gone - 这个url对应的资源现在不可用。 415 unsupported media type - 请求类型错误。 422 unprocessable entity - 校验错误时用。 429 too many request - 请求过多。

Finish

RESTful API Design Best Practices

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.