RESTful API based

This specification follows the REST architecture style in API design. This section explains how to implement RESTful apis

Introduction to the

REST, which stands for Representational State Transfer, was developed by Roy Thomas Fielding in his doctoral thesis in 2000 and is a widely used API architectural style.

Resources in the Resource

In the design of REST apis, you first need to model for resources, where each node is a “simple resource” or a “collection resource.” For convenience, they are often referred to as resources and collections, respectively.

  1. A collection contains a list of resources of the same type. For example, a user has a list of contacts.
  2. A resource has state and zero or more child resources. Each subresource can be a simple resource or a collection resource.

Method

Each resource has a set of operation methods. Users can perform corresponding operations using THE API (HTTP Method). The common operation methods are as follows:

Operation type HTTP mapping For example,
Getting a collection of resources GET curl -X GET Foo.bar.com/api/v1/cust…
Obtaining a single resource GET curl -X GET Foo.bar.com/api/v1/cust…
Create a resource POST curl -X POST Foo.bar.com/api/v1/cust…
Update the resource PUT curl -X PUT Foo.bar.com/api/v1/cust…
Local update resource PATCH curl -X PATCH Foo.bar.com/api/v1/cust…
Delete the resource DELETE curl -X DELETE Foo.bar.com/api/v1/cust…

The difference between POST/PUT and PATCH is that all information is updated or partial information is updated. POST/PUT indicates that all fields of the resource are updated or overwritten.

RESTful API design specifications

Design urls for resources

User Oriented modeling

A resource is not a data model or a domain model, and its semantics should be consumer-oriented.

Example:

/customers/123/baseinfo /customers/123/tagsCopy the code

Is:

# User-oriented design, you can define the resource as: customer archives/ customers_archives/123Copy the code

Resources are related to roles

Different roles can use different resources. For example:

The administrator accesses a customer’s order:

GET /customers/123/podcasts
Copy the code

Customers access their own orders:

GET /my_podcasts
Copy the code

Two urls for one class of resources

Each resource should have only two base urls (endpoints), one for the collection and one for a specific element in the collection.

/customers # customer set/Customers /1 # Customer setCopy the code

Use consistent plural nouns

Avoid mixing plural and singular forms, and use only consistent plural nouns for resources.

Example:

GET /story
GET /story/1
Copy the code

Is:

GET /stories
GET /stories/1 
Copy the code

Complex query logic uses query strings

Keep urls simple and short, and move complex or optional parameters to the query string.

GET /customers? country=usa&state=ca&city=sfoCopy the code

Express associations between resources

Construct the URL with this form when you need to operate on resource 2 associated with resource 1:

resources/:resource_id/sub_resources/:sub_resource_id

Example:

GET /cusomters/podcasts/123 GET /getCustomerPodcasts? customer_id=123Copy the code

Is:

GET/cusomters / # 5678 / podcasts to GET all the podcast a customer GET/cusomters / 5678 / podcasts / 123 # for a customer a podcast POST/cusomters / 5678 / podcasts Create a new podcast for a customerCopy the code

Use HTTP Method to represent actions

Urls should contain no verbs, and instead use methods for all actions.

Example:

GET /getCusomters
GET /getAllMaleCusomters
POST /createCusomter
POST /updateCustomer
POST /customer/create_for_management/
Copy the code

Is:

GET /cusomters? POST/Cusomters # Create new customers PUT/Cusomters /5 # update existing customers 5 (full field) PATCH /cusomters/5 # DELETE /cusomters/5 # DELETE client 12Copy the code

The use of bases

HATEOAS stands for Hypermedia As The Engine Of Application State, The highest form Of REST in Richardson Maturity Model, Hypermedia’s API returns an additional set of links in addition to the resource itself. This set of links describes what the client can do next for the resource and how to do it, for example:

{

    "tracking_id": "123456",
    "status": "WAIT_PAYMENT",
    "items": [
        {
            "name": "potato",
            "quantity": 1
        }
    ],
    "_links": {
        "self": {
            "href": "http://localhost:57900/orders/123456"
        },
        "cancel": {
            "href": "http://localhost:57900/orders/123456"
        },
        "payment": {
            "href": "http://localhost:57900/orders/123456/payments"
        }
    }
}
Copy the code

The benefits of using HATEOAS include but are not limited to:

  1. The front end no longer hardcodes most of the Back-End API urls, but returns them in response, and the back end can make the front end unaware of the API renaming.
  2. Convergence of business rules to the back end, such as the visibility of some functionality to a user (permissions)

Custom methods

As a matter of practice, using strict RESTful can have some semantics that are difficult to express (or awkward to express), so based on that, and referring to the Google Clould API – Custom Methods, allow some custom methods to be used for expression. These methods should only be used for functions that are not easily expressed by standard methods. In general, use of standard methods should be preferred over custom methods whenever possible, as follows:

  • In order to be expressed differently from resources, custom methods are expressed using verbs that represent custom actions for resources
  • Custom methods use only GET and POST methods.
POST /cusomters/5/cancel POST/Cusomters /5/undelete POST/Cusomters /5/search Using GET may result in exceeding the length GET /cusomters/batch_getCopy the code

API format conventions

The URL prefix

Build the URL using the following rules:

https://foo.bar.com/api/ + + version number + resource collection business domain + resource ID such as: https://foo.bar.com/api/mall/v1/customers/1Copy the code

The Response Body structure

Using the same HTTP response structure, the following structure is recommended:

{"code": 0, # error "MSG ": "success", # error message "success", "data": "Id ": 1, "name":" ABC "}, "extra": {# data should be null if the error code is not 0}}Copy the code

The version number

  • When API upgrades are compatible, there is no need to upgrade the version number.
  • Use simple ordered numbers instead of periods (e.g., V1.2) for version numbers.
  • When a new version goes online, ensure that the API of the old version is still available. You can go offline only when there are no more requests for the old version.

URI Specifies the version number in the Path

If the URI Path contains the version number, it indicates the overall API version. If the API of the service domain is upgraded significantly, the version number needs to be upgraded, as shown in the following figure:

https://foo.bar.com/api/mall/v1
Copy the code

The HTTP status code

Express the semantics of the response using the appropriate HTTP Status Code

HTTP describe
200 No error.
400 Client specified an invalid argument. Check error message and error details for more information. Request can not be specified Be executed in the current system state
401 Request not authenticated due to missing, invalid, or expired token.
403 Client does not have sufficient permission.
404 A specified resource is not found, or the request is rejected by undisclosed reasons, such as whitelisting.
405 The HTTP method in The request is not allowed on The resource.
409 Concurrency conflict, such as read-modify-write conflict.
409 The resource that a client tried to create already exists.
429 Either out of resource quota or reaching rate limiting.
500 第 一 句 : The task must be returned to task number 1.
503 Parameter Description Value Error code: Service unavailable. Typically, exceptions can be restored and retry after a short period.
504 Request deadline exceeded. This will happen only if the caller sets a deadline that is shorter than the method’s default deadline (i.e. requested deadline is not enough for the server to process the request) and the request did not finish Within the deadline.

Error code

In addition to using HTTP Status Code, you also need a business error Code, which is returned by the Code field. Error codes are agreed by each service party and are divided into different segments within the service.

paging

Paging based on page and page_size

curl https://foo.bar.com/api/mall/v1/customers?page=1&page_size=10

{

  "code": 0,
  "message": "success",
  "data": {
    "pagination": {
      "total": 3465
    },
    "customers": [
      {
        "id": 123,
        "job_id": 456
      }
    ]
  }
}
Copy the code

Offset – and limit-based paging

curl https://foo.bar.com/api/mall/v1/customers?offset=20&limit=10
{
  "code": 0,
  "message": "success",
  "data": {
    "pagination": {
      "total": 3465
    },
    "customers": [
      {
        "id": 123,
        "job_id": 456
      }
    ]
  }
}
Copy the code

Page_token-based paging

curl https://foo.bar.com/api/mall/v1/customers?page_token=xxxxxxx&page_size=10
{
  "code": 0,
  "message": "success",
  "data": {
    "pagination": {
      "page_token": "yyyyyyyyyy",
      "has_more": true
    },
    "customers": [
      {
        "id": 123,
        "job_id": 456
      }
    ]
  }
}
Copy the code

API Metrics

API implementors need to pay close attention to the following basic monitoring metrics in order to:

  1. Detect system emergencies in a timely manner, for example, interface QPS/time surge and dependent RPC interface time surge.
  2. Provides the basis for interface optimization

The request quantity

  • Request volume of each interface, available caliber: QPS/request volume in recent 7 days/request volume in recent 1 day.
  • Optimization direction: Minimize the number of requests without affecting the user experience

The interface takes

  • Latency AVG, P50, P95, or P99
  • Optimization direction: On the premise of meeting user needs, as little time as possible

I/O Diffusion volume (internal I/O visits & Elapsed time & Errors)

  • QPS, time, and errors of I/ OS of a single interface, such as RPC, Mysql, Redis, Mongo, and ES. When dependent infrastructure is faulty, you can quickly locate the cause.
  • Optimization direction: reduce the QPS and time consuming of each IO in an API request as much as possible.

API development best practices

The following sections provide specific specifications and requirements for some scenarios and functions

API-First

In the process of server and client development, apis are defined in advance, and multiple parties develop in parallel according to contract.

  • The API needs to be defined and registered with the interface platform before each requirement is coded
  • And the API interface needs to be reviewed when the back-end technical solution is reviewed

User oriented design

Define “Resources” carefully

An important prerequisite when designing an API is to properly define the Resource itself. The internal storage model of the server should not simply be viewed as a “resource”, but should be customer-oriented. For example, the talent detail page is also a combination of various models of the talent, and should be viewed as one resource (not multiple).

Avoid trivial apis

Try to avoid “trivial” Web apis that expose a large number of small resources, which may require the client (front end) to send multiple requests to assemble all the data it needs. Wherever possible, consolidate related information into a single, larger resource for direct use by users.

According to the need to return

You should pay attention to the specific fields that the user relies on and how they are used, returning only the smallest set of data that the user relies on, and ensuring that the fields returned are functional.

CQRS

CQRS stands for Command Query Responsibility Segregation, which divides an application into two parts:

  • Command: Processes requests to create, update, and delete, and issues events when data changes.
  • Query side: Processes queries by executing queries and is kept up to date by subscribing to a stream of events emitted when data changes.

CQRS uses a separate interface to separate the data query operation from the data modification operation, which also means that the data model used in the query and update process is different, thus isolating the read and write logic.

Compared with read and write separation of database, CQRS can be understood as read and write separation of application layer. A separate read model is constructed for read scenarios to improve query performance and overall system maintainability.

Read more:

CQRS – Martin Fowler

Simple and usable CQRS coding practices

Compatibility

API changes must be backward compatible, that is, API updates do not cause front-end/client errors.

Do not perform incompatible upgrades even if both the front and back ends are released at the same time. The reasons are as follows:

  • We often don’t know all API users
  • The release process takes time and there is no real “simultaneous release”
  • The coupling of publishing links, once the front end needs to roll back, then the back end also needs to roll back, resulting in a complicated online scheme

Common incompatible upgrades are as follows:

  • Removes or renames fields, methods, enumerated values
  • Changing the field type
  • Modify the behavior and semantics of fields

Idempotency

Making the API idempotent makes it easier to implement complex processes by allowing clients to retry more safely.

Idempotent of the Create type

A common way to create a type of API for idempotent deduplication is to use a client-side generated Deduplication token. The same token is used for repeated retries so that the server can identify duplications. Should return as created successfully.

Idempotent of the Update type

Update-type apis, usually with a unique ID to identify the resource that needs to be updated, ensure idempotent.

For operations with “Delta” semantics, there are several ways to ensure idempotency:

  1. IncrementBy: Increases based on a number
  2. SetNewTotal: Sets the new total
  3. Use a Deduplication Token to ensure idempotency

Each of these methods has its advantages and disadvantages, and you need to choose an appropriate method based on the scenario.

Idempotent of the Delete type

The idempotent problem of Delete is that after an object has been deleted, attempts to Delete it again may cause errors because the data cannot be found. This behavior is generally fine, though not strictly idempotent, but it has no side effects.

Asynchronize long-duration requests

If an API method takes a long time to complete, you can use:

  1. Asynchronously start a task on the server and return a resource with a GUID labeled “Long-running operation”
  2. The client uses scheduled pollingPolling / {guid},Gets the status of the ongoing task.
  3. When a task is complete or fails, the client can obtain the processing result or failure cause.

Appendix I: Richardson Maturity Model

Richardson Maturity Model – steps toward the glory of REST

Richardson Maturity Model – Steps to true REST