This post first appeared on Gevin’s blog

A guide to RESTful API writing

Reproduced without permission from Gevin


Good RESTful apis can be developed quickly based on good RESTful development components, but if you don’t know the fundamentals of a well-regulated and robust RESTful API, even good RESTful development components in front of you can’t be well understood and used. Gevin summarized the core points of developing RESTful apis from scratch based on his practical experience. A complete RESTful development component will contain all or most of the points, and we can also write our own code to implement the points that are not well supported.

Outline

  • The Request and Response
  • Serialization and Deserialization
  • Validation
  • The Authentication and Permission
  • CORS
  • URL Rules

1. The Request and Response

The development and use of RESTful apis are nothing more than the client sends a request to the server and the server responds to the client’s request. The native RESTful architectural style features a unified interface, that is, different HTTP methods are used to express different behaviors:

  • GET (SELECT) : Fetch resources (one or more items) from the server
  • POST (CREATE) : Creates a resource on the server
  • PUT (UPDATE) : Updates resources on the server (clients provide full resource data)
  • PATCH (UPDATE) : Updates resources on the server (the client provides the resource data to be modified)
  • DELETE (DELETE) : deletes resources from the server

The client will send requests to the server to obtain data based on the GET method, and send requests to the server to update data based on the PUT or PATCH method, etc. When designing the API, the server should also handle the corresponding requests according to the corresponding specifications, which should become the consensus of all developers of RESTful API. In addition, the Request class and response class of each Web framework are very powerful, with reasonable default Settings and flexible customization. Gevin here only intends to emphasize the data and status code commonly used in response to these requests, and the incomplete content. Welcome to add:

  • whenGET.PUTandPATCHWhen the request succeeds, the corresponding data and status code are returned200That SUCCESS
  • whenPOSTIf data is successfully created, the created data and the status code are returned201That CREATED
  • whenDELETEIf data is deleted successfully, the status code is returned instead of data204, that is, NO CONTENT
  • whenGETIn the absence of data, the status code is returned404And that is NOT FOUND
  • Any time there is a problem with the request, such as an error found while validating the request data, a status code is returned400That BAD REQUEST
  • When an API request requires user authentication, a status code is returned if the authentication information in the request is incorrect401And that is NOT AUTHORIZED
  • If the current user does not have the corresponding permission, the status code is returned403That who

Finally, for Request and Response, don’t ignore the Content-type in the HTTP header. Take JSON as an example. If THE API requires the client to pass IN JSON data when sending a request, the server only needs to obtain and parse THE JSON data. However, if the server supports multiple types of data, such as JSON and form-data, Obtain and parse data of different types according to the content-Type in the header when the client sends a request. If the API needs to return JSON data after responding to a client request, add content-type = Application/JSON to the header.

2. The Serialization and Deserialization

Serialization and Deserialization are both Serialization and Deserialization. RESTful apis use standardized data formats, such as JSON or XML. For example, when a client sends a request to the server or a corresponding client sends a request to the client, the client transmits the text in JSON format. The most typical example is the instance of class, namely object. Json is only the format of data transmitted on the network when the server and client communicate. Inside the server and client, There are both requirements for converting JSON to native data and converting native data to JSON. Converting native data to JSON is serialization, and converting JSON to native data is deserialization. While some development languages, such as Python, can easily implement serialization and deserialization with their native data types list and dict, complex apis are implemented internally with objects as data carriers, so ensuring that serialization and deserialization methods are implemented is one of the most important steps in developing RESTful apis

As an aside, the convenience of serialization and deserialization makes RESTful apis cross-platform, making REST replace RPC as the mainstream of Web services

Serialization and deserialization are a hard requirement in RESTful API development, so almost every common development language has one or more excellent open source libraries for serialization and deserialization, so there is no need to create duplicate wheels when developing RESTful apis. Just pick a good library. For example, marshmallow in Python, serializer in Django REST Framework is required if Django is used for development.

3. Validation

Validation, or data Validation, is another important part of developing a robust RESTful API. Using JSON as an example, when a client sends a POST, PUT, or patch request to the server, it usually sends relevant data in JSON format to the server at the same time. The server performs data verification before data processing, which is the most reasonable and secure front-end and back-end interaction. If the data sent by the client is incorrect or unreasonable, the server returns an error of 400 and the corresponding data error message to the client after verification. Common data verification includes:

  • Data type validation, such as assigning a string value to an int field
  • Data format verification, such as email or password, must meet the corresponding regular expression to correct input data
  • Logical data verification. For example, data contains two fields: date of birth and age. If the two fields are inconsistent, data verification fails

Data logic verification is the most complex of the above three types of verification. It usually involves the coordination of multiple fields, or the verification must be performed based on users and permissions. While Validation is optional in RESTful API writing, it is so important for API security, server overhead, and interactivity friendliness that Gevin recommends that its implementation be essential to developing a sound RESTful API.

4. The Authentication and Permission

Authentication refers to user Authentication, and Permission refers to the Permission mechanism. These two basic guarantees make RESTful apis powerful, flexible, and secure.

The commonly used authentication mechanisms are Basic Auth and OAuth. In RESTful API development, unless the API is very simple and has no potential security problems, authentication mechanisms must be implemented and applied to the API. Basic Auth is very simple, many frameworks have integrated Basic Auth implementation, write one can also be quickly done, OAuth has become standard enterprise services, its related open source implementation is very rich (more).

I describe the authentication mechanism in more detail in The RESTful Architecture Style Overview, which you may want to read.

The permission mechanism is a further restriction on API requests, and only authenticated users who meet the permission requirements can access the API. Generally speaking, commonly used permission mechanisms mainly include global and object permissions, which mainly refer to granting permissions to users, assigning roles to users, or assigning users to user groups. The object type permission mechanism mainly refers to the granularity of the permission control. When users access, modify, delete or act on a specific object, relevant permissions should be granted to users on the object to realize the permission control.

The global permission mechanism is easy to understand and easy to implement. There are many open source libraries for alternative solutions, and many perfect Web development frameworks also integrate related permission logic. Object Permission is relatively difficult and complicated, but there are also many typical application scenarios, such as multi-person blog system. The author’s edit permission to his own article is called object permission, and there are many open source libraries corresponding to it.

Note: I wrote an article on implementing Django’s Permission mechanism for Django developers to read further.

To develop a complete set of RESTful APIS, the permission mechanism must be taken into account. Although the specific implementation of the permission mechanism depends on the business, the permission mechanism itself has a typical pattern, and developers need to master the basic permission mechanism implementation scheme, so as to apply it to the API at any time.

5. CORS

CORS is cross-Origin Resource Sharing. In the development of RESTful API, IT mainly serves FOR JS to solve the cross-domain problem when javascript calls RESTful API.

Due to the inherent security mechanism, js cross-domain requests cannot be successfully responded by the server. Now front end separation becomes mainstream web development way, under the trend of background gradually tends to refer to the API service, provide data and relevant operation for each client, and the development all over to the front of the site, site and API service seldom deployed on the same server and use the same port, js cross-domain request, When developing RESTful apis, it is usually necessary to consider the implementation of CORS functions, so that JS can use the API normally.

At present, various mainstream Web development languages have many excellent open source libraries to realize CORS. When we develop RESTful apis, we should pay attention to the realization of CORS functions and directly use the existing wheels.

For more information about CORS, please check Mr. Ruan Yifeng’s websiteCross-domain resource sharing (CORS

6. URL Rules

RESTful apis are written for developers to consume, and their naming and structure need to make sense. Therefore, there are some conventions to follow when designing and writing urls. Url rules can be explained in a separate blog post, but this article only lists the key points.

Version 6.1 your API

A canonical API should contain version information. In RESTful apis, the easiest way to include version information is to put it in a URL, such as:

/api/v1/posts/
/api/v1/drafts/

/api/v2/posts/
/api/v2/drafts/Copy the code

Another elegant way to do this is to use accept in the HTTP header to pass version information, which is the strategy adopted by the GitHub API.

C. Use nouns, not verbs

Urls in RESTful apis point to resources, not describe behavior, so use nouns instead of verbs to describe semantics when designing apis. Otherwise, confusion and semantic ambiguity can occur. That is:

# Bad APIs
/api/getArticle/1/
/api/updateArticle/1/
/api/deleteArticle/1/Copy the code

The above four urls all point to the same resource. Although a resource allows multiple urls to point to it, different urls should express different semantics. The above API can be optimized as:

# Good APIs
/api/Article/1/Copy the code

Article resources are obtained, updated, and deleted by requesting the API through the GET, PUT, and DELETE methods, respectively. Imagine how uncomfortable it would be to call/API /deleteArticle/1/ with the PUT method if the URL was described as a verb.

6.3 GET and HEAD should always be safe

RFC2616 makes it clear that the GET and HEAD methods must always be secure. For example, there is a non-standard API like this:

# The following api is used to delete articles # [GET] /api/deleteArticle? id=1Copy the code

What if a search engine visited the url above?

6.4 Nested resources routing

It is an elegant way to obtain a subset of resources by, for example, listing all articles written by Gevin:

# List Gevin's articles
/api/authors/gevin/articles/Copy the code

Another way to get a subset of resources is based on filters (see section below), both of which conform to the specification but have different semantics: The use of nested routing feels more appropriate if the subset of resources is semantically treated as an independent set of resources, and filter is more appropriate if the subset of resources is obtained for filtering purposes.

Which approach to take when writing RESTful apis is a matter of opinion, and it makes sense semantically.

6.5 the Filter

For resource sets, resources can be filtered by URL parameters, such as:

# List Gevin's articles/api/articles? author=gevinCopy the code

Paging is one of the most typical forms of resource filtering.

6.6 Pagination

For resource collection, paging is a more reasonable way. If you are using a development Framework (such as Django REST Framework), you can simply use the pagination mechanism in the development Framework. If you are implementing your own pagination mechanism, Gevin’s strategy is:

The return resource collection is, containing paging-related data as follows:

{
  "page": 1,            What page is the current page
  "pages": 3.# How many pages in total
  "per_page": 10,       # How much data per page
  "has_next": true.Is there any data on the next page
  "has_prev": false.Is there any data on the previous page
  "total"27:# How much data in total
}Copy the code

When you want the API to request a collection of resources, the optional paging parameters are:

parameter meaning
page The current page is 1 by default
per_page Number of records per page. The default value is the default value

In addition, a per_page_max field is set in the system to mark the maximum number of records allowed per page. When the per_page value is greater than the per_page_max value, the number of records per page is per_page_max.

6.7 the Url design tricks

(1) Url is case sensitive, which is often ignored, namely:

  • /Posts
  • /posts

These two urls are two different urls that can point to different resources

(2) Back Slash (/)

Currently popular API design schemes usually suggest that the URL end with /. If the URL does not end with/in THE API GET request, it will be redirected to the API end with/(this is basically supported by the current Web framework), because there are also two urls with /, namely:

  • /posts/
  • /posts

These are also two different urls that can correspond to different behaviors and resources

(3) hyphen – and underscore _

RESTful apis should be readable. When a segment in a URL consists of multiple words, use – instead of _ to separate words.

# Good
/api/featured-post/

# Bad
/api/featured_post/Copy the code

This is mainly because hyperlinks in browsers default to text with underscores, and if the API separates words with underscores, the two will overlap, affecting readability.

conclusion

The purpose of this article was to put together a set of basic ideas for writing a standard, secure RESTful API from scratch. This article introduces the basic contents to consider when developing RESTful apis. For a Web framework like Flask that naturally supports RESTful style and does not rely on other RESTful third-party libraries to develop RESTful services, you can start from this article. There are many powerful RESTful libraries, although their related interfaces basically cover all or most of the content of this article, but the summary of this article, I believe that the understanding and use of these libraries is also helpful.

Finally, welcome to talk with me about how to develop RESTful apis