Microservice guide to the North (3): Restful API design

Time:2020-10-27

The definition of API depends on the selected IPC communication mode. If it is a message mechanism (such as AMQP or stomp), the API consists of the message channel and message type; if the HTTP mechanism is used, it is based on request / response (calling the URL of HTTP). Here, we will briefly describe the definition of restful API.

Design principles

domain name

The API should be deployed under the private domain name as much as possible, such as:

https://api.example.com

It can also be placed under the primary domain name:

https://example.org/api/

edition

Put it in the accept of header information
It is a great challenge to design and maintain a set of APIs by developing versions and smoothly transiting between them. Therefore, it is better to use some methods at the beginning of design to prevent possible problems.
In order to avoid unexpected results or call failure caused by changes in the API, it is better to force all accesses to specify the version number. Please avoid providing the default version number, once provided, it will be very difficult to modify it in the future.
The most suitable location to place the version number in the URL, or in the header information (HTTP headers), use the custom type in the accept section to submit with other metadata.

https://api.example.com/v1/
or
Accept: application/vnd.heroku+json; version=3

Provide request ID

Include a request ID field for each request response, and use UUID as the value. By logging this value on the client, server, or any supporting service, it can provide a mechanism to track, diagnose, and debug requests.

route

Resource name

In addition, there can only be one name for resource in the database. Generally speaking, the tables in the database are “collections” of the same kind of records, so nouns in the API should also be plural.
For example, if there is an API that provides zoo information, as well as information about various animals and employees, its path should be designed as follows.

https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees

Actions

Good endings don’t need to specify special behaviors for resources, but in special cases, it is necessary to specify behaviors for some resources. For clarity, add a standard action before the action:

/resources/:resource/actions/:action

For example:

/runs/{run_id}/actions/stop

Path and property name

In order to be consistent with the naming rules of domain names, use lowercase letters and use – to separate path names, for example:

service-api.com/users
service-api.com/app-setups

Attributes are also lowercase, but the property name is underlined_ Split to omit quotation marks in JavaScript. For example:

service_class: "first"

Support convenient indirect reference without ID

In some cases, it is not convenient for users to provide ID to locate resources. For example, a user wants to get information about his app on heroku platform, but the unique ID of the app is UUID. In this case, you should support the interface to be accessible by name and ID, for example:

$ curl https://service.com/apps/{app_id_or_name}
$ curl https://service.com/apps/97addcf0-c182
$ curl https://service.com/apps/www-prod

Don’t just accept names and give up IDs.

Minimize path nesting

In some resource data modules with parent / child path nesting relationships, paths may have very deep nesting relationships, such as:

/orgs/{org_id}/apps/{app_id}/dynos/{dyno_id}

It is recommended to specify resources under the root path to limit the nesting depth of paths. Use nested resources of the specified scope. In the above example, dyno belongs to app and app belongs to org, which can be expressed as follows:

/orgs/{org_id}
/orgs/{org_id}/apps
/apps/{app_id}
/apps/{app_id}/dynos
/dynos/{dyno_id}

HTTP verbs

The specific operation type of a resource is represented by an HTTP verb.
There are five commonly used HTTP verbs (the corresponding SQL command is shown in brackets)

Get (select): retrieve a resource (one or more items) from the server.
Post (create): create a new resource on the server.
Put (update): updates the resource on the server (the client provides the complete resource after the change).
Patch (update): updates resources on the server (client provides changed properties).
Delete (delete): delete a resource from the server.

Some examples:

Get / zoos: list all zoos
Post / zoos: build a new zoo
Get / zoos / ID: get the information of a designated zoo
Put / zoos / ID: update the information of a designated Zoo (provide all information of the zoo)
Patch / zoos / ID: update the information of a designated Zoo (provide some information about the zoo)
Delete / zoos / ID: delete a zoo
Get / zoos / ID / animals: lists all animals in a given zoo
Delete / zoos / ID / animals / ID: delete the specified animals of a designated zoo

Filtering information

If the number of records is large, the server cannot return them all to the user. The API should provide parameters to filter the returned results.
Here are some common parameters:

? limit = 10: Specifies the number of records to be returned
? offset = 10: Specifies the start position of the return record.
?page=2&per_ Page = 100: Specifies the page number and the number of records per page.
? sortby = name & order = ASC: specifies which attribute to sort the returned results by, and the sort order.
?animal_ type_ Id = 1: specify filter criteria

The design of the parameters allows for redundancy, that is, occasionally duplicate API path and URL parameters. For example, get / Zoo / ID / animals and get / animals? Zoo_ The meaning of id = ID is the same.

Responses

Status code

The status code and prompt information returned by the server to the user are as follows (the HTTP verb corresponding to the status code is shown in square brackets)

200 OK - [get]: the server successfully returns the data requested by the user. The operation is idempotent.
201 created - [post / put / patch]: user created or modified data successfully.
202 accepted - [*]: indicates that a request has entered the background queue (asynchronous task)
204 no content - [delete]: user deleted data successfully.
400 invalid request - [post / put / patch]: there is an error in the request sent by the user. The server does not create or modify data. This operation is idempotent.
401 unauthorized - [*]: indicates that the user does not have permission (wrong token, user name and password).
403 Forbidden - [*] indicates that the user is authorized (as opposed to 401 error), but access is prohibited.
404 Not Found - [*]: the request sent by the user is aimed at the nonexistent record. The server does not operate, and the operation is idempotent.
406 not acceptable - [get]: the format of the user request is not available (for example, the user requests JSON format, but only XML format).
410 gone - [get]: the resource requested by the user is permanently deleted and will not be obtained again.
422 unprocessable entity - [post / put / patch] a validation error occurred while creating an object.
500 Internal Server Error - [*]: server error, the user will not be able to determine whether the request is successful.

Provide the (Uu) ID of the resource

By default, each resource is given an ID attribute. Use UUID unless you have a better reason. Don’t use IDs that are not globally unique on the server or in resources, especially automatically growing IDs.
Generate lower case UUID format 8-4-4-4-12, for example:

"id": "01234567-89ab-cdef-0123-456789abcdef"

Provide standard timestamps

Provides a default creation time for the resource created_ At and update time updated_ At, for example:

{
  ...
  "created_at": "2012-01-01T12:00:00Z",
  "updated_at": "2012-01-01T13:00:00Z",
  ...
}

Use UTC time and format it with iso8601

Only use UTC format (data in iso8601 format) or timestamp when receiving and returning. For example:

"finished_at": "2012-01-01T12:00:00Z"

or

"timestamp": "1472486035"

error handling

If the status code is 4xx, an error message should be returned to the user. Generally speaking, the returned information takes error as the key name and the error information as the key value.

{
    error: "Invalid API key"
}

Return results

For different operations, the results returned by the server to the user should meet the following specifications.

Get / collection: returns a list (array) of resource objects
Get / collection / resource: returns a single resource object
Post / collection: returns the newly generated resource object
Put / collection / resource: returns the complete resource object
Patch / collection / resource: returns the complete resource object
Delete / collection / resource: returns an empty document

Ensure response JSON and minimize

At present, in order to minimize the response, the JSON string is generally used, and the extra space in the request will increase the response size. Now, many HTTP clients will output JSON in readable format. Therefore, it is better to minimize the response JSON, for example:

{"beta":false,"email":"[email protected]","id":"01234567-89ab-cdef-0123-456789abcdef","last_login":"2012-01-01T12:00:00Z","created_at":"2012-01-01T12:00:00Z","updated_at":"2012-01-01T12:00:00Z"}

Instead of this:

{
  "beta": false,
  "email": "[email protected]",
  "id": "01234567-89ab-cdef-0123-456789abcdef",
  "last_login": "2012-01-01T12:00:00Z",
  "created_at": "2012-01-01T12:00:00Z",
  "updated_at": "2012-01-01T12:00:00Z"
}

Hypermedia API

The restful API is best to do hypermedia, that is, to provide links in the returned results and connect to other API methods, so that users do not check the documents and know what to do next.
For example, when users send api.example.com A request is made from the root directory of the.

{"link": {
  "rel":   "collection https://www.example.com/zoos",
  "href":  "https://api.example.com/zoos",
  "title": "List of zoos",
  "type":  "application/vnd.yourformat+json"
}}

The above code indicates that there is a link attribute in the document. After reading this attribute, the user will know what API to call next. Rel represents the relationship between the API and the current web address (collection relationship, and gives the URL of the collection); the path of the API, title, and type are the return types.
The design of the hypermedia API is called HATEOAS. GitHub’s API is this kind of design api.github.com You will get a list of all available APIs.

{
  "current_user_url": "https://api.github.com/user",
  "authorizations_url": "https://api.github.com/authorizations",
  // ...
}

As can be seen from the above, if you want to obtain the information of the current user, you should visit api.github.com/user And then you get the following result.

{
  "message": "Requires authentication",
  "documentation_url": "https://developer.github.com/v3"
}

The code above indicates that the server gives the prompt information and the web address of the document.

Reference articles

  • Restful interface of GitHub

  • Design principles and case revision of restful API analysis

  • http-api-design


By Liu Yingguang @ firefly studio
OpenBI communication group: 495266201
Microservice microservice communication group: 217722918
mail: liuyg#liuyingguang.cn
Blog homepage (= = prevent crawler = =): http://blog.liuyingguang.cn
OpenBI Q & a community: http://www.openbi.tk

Recommended Today

PHP 12th week function learning record

sha1() effect sha1()Function to evaluate the value of a stringSHA-1Hash. usage sha1(string,raw) case <?php $str = “Hello”; echo sha1($str); ?> result f7ff9e8b7bb2e09b70935a5d785e0cc5d9d0abf0 sha1_file() effect sha1_file()Function calculation fileSHA-1Hash. usage sha1_file(file,raw) case <?php $filename = “test.txt”; $sha1file = sha1_file($filename); echo $sha1file; ?> result aaf4c61ddcc5e8a2dabede0f3b482cd9aea9434d similar_text() effect similar_text()Function to calculate the similarity between two strings. usage similar_text(string1,string2,percent) case […]