Practical combat - Restful API format specification

RESTful is an API design style. It is similar to GraphQL, JSON-RPC, and WebService. It is used to define exposed server interfaces under CS and BS architectures. This design docking specification will use RESTful as the standard.

1. Characteristics

The characteristics of RESTful style are:

① URI resource utilization:

That is, URI represents a resource and does not contain an action. For example, there are many students in a class, we can express it like this: /class/students

② The action is determined by the method in the HTTP header:

For example, if we want to add a new student, we can use the POST method:

POST /class/students
{
    
    
    "name": "Jake",
    "age" : 18
}

If we want to see which students are currently there, we can use the GET method:

GET /class/students

If we want to view the specific information of a student, we can use the path to specify an ID:

GET /class/students/1

If we want to expel the student with ID 1, we can use the DELETE method:

DELETE /class/students/1

After the method in the HTTP header determines the action, the back-end implementation should also be strictly based on the action. For example, a GET request should not cause any changes to the data. In this way, it is very convenient for us to control permissions. For example, if it is a visitor, we can Only the GET method is open, but for ADMIN, we can open GET, POST, DELETE and other methods.

Most of them just do CRUD and use HTTP header actions, which is very satisfying.

③ The performance of resources is determined by Content-Type:

The Accept and Content-Type fields in the header information of the HTTP request are performance descriptions of the resource. For example, specify whether it is JSON format or HTML format.

④ Stateless:

Stateless means client-side statelessness, for example, you should not use similar logic on the client-side:

if (hasStudent("Jake")) {
    
    
    getStudentInfo("Jake");
}

Because, between the calls of hasStudent and getStudentInfo, someone else may have deleted Jake, and your status maintenance may not be accurate. You can directly getStudentInfo("Jake"), otherwise it will return failure. The server can maintain some status, but it is best not to maintain too much. For example, the HTTP login status should be maintained. However, the design is to record and force user A to request a certain URL before requesting another URL. It shouldn't be.

⑤ Data security:

Use HTTPS protocol to encrypt data.

We uniformly use RESTful HTTPS (for encryption) requests, and the content is in JSON format. For constraints such as security, idempotence, and statelessness, the product line must be designed strictly in accordance with Restful regulations.

2. Advantages

① Reduce communication costs:

The API is open for others to use. Due to the existing agreement, communication costs will be greatly reduced. This is what API providers should consider most.

② Able to accept a variety of clients (applicable to most CS BS architecture programs):

Not only web programs, but also basic CS architecture programs can use RESTful to provide APIs. In this way, whether it is WEB Client, Windows APP or Mobile APP, you can easily use the server-side API.

③ Change the way of thinking to resource-centered:

The traditional way is operation-centric, such as create_user, query_students.

Similar to object-oriented, which is object-centered, RESTful advocates being resource-centered, which is not absolutely good, but it does guide everyone to consider the resource itself, pay attention to cohesion, pay attention to permissions, and pay attention to the relationship between resources.

④ Easy to expand:

Stateless design is very convenient for horizontal expansion because APIs are better decoupled and resources are also better decoupled. There is also something called hypertext-driven, which is similar to self-description, but is inconvenient to use. The API provided by the CodeReview tool is this way. The advantage is that the server can change the URL at will, but the disadvantage is that it needs to be queried before requesting. Let’s find out what path to request. For example, github reference https://api.github.com/

⑤ Based on HTTP protocol:

There are many things specified in the HTTP protocol, such as caching, compression, proxy, encryption, penetration, etc., all of which have been completed by HTTP, reducing the burden on many implementations.

3. Action

1. GET to obtain resources

Example: Get information about student Jake.

GET /class/students?name="Jake"

2. POST to create resources

When creating a resource, the resource ID will not be specified, but after the creation is completed, the resource ID will usually be returned, so that the resource can be operated through the resource ID later.

Example: Create students.

POST /class/students
{
    
    "name": "Jake", "age" : 18, "score": 0}

3. PUT overall replacement

In order to locate a resource, a unique ID of the resource is required on the path.

Example: Replace the information of the student with ID 2 with the following new information.

PUT /class/students/2 
{
    
    "name": "Jim","age": 19}

# 此操作将原本ID2的学生的所有属性冲掉了,替换后,ID2的学生整体内部数据结构变为:
{
    
    "id": 2, "name": "Jim","age": 19}

abnormal:

① If Playload is empty, return failure.

② If Playload is {}, it is correct, indicating clearing (resetting). For example, the internal data structure of the above example will become: {"id": 2}

4. PATCH partial replacement

In order to locate a resource, a unique ID of the resource is required on the path.

Example: Update the age of the student with ID 2 from the previous 18 years old to 20 years old.

PATCH /class/students/2 
{
    
    "age": 20}

# 这里,ID2的学生的其他属性保留,整体内部数据结构变成:
{
    
    "id": 2, "name": "Jake", "age" : 20, "score": 0}

abnormal:

① If Playload is empty or {}, failure is returned.

② For nested structures, if it is written normally, it means whole replacement; if it is a dotted structure, it means partial update.

for example:

{
    
    "id": 2, "name": "Jake", "age" : 20, "score": {
    
    "English": 86, "Chinese":88, "math":99}}

Substructure update:

PATCH /class/students/2
{
    
    "score": {
    
    "math":100}}

# 替换后为:
{
    
    "id": 2, "name": "Jake", "age" : 20, "score": {
    
    "math":100}}

Substructure update:

PATCH /class/students/2
{
    
    "score.math": 100}

# 替换后为:
{
    
    "id": 2, "name": "Jake", "age" : 20, "score": {
    
    "English": 86, "Chinese":88, "math":100}}

③ For arrays, the standard usage is to indicate overall replacement, not addition or deletion.

for example:

{
    
    "id": 2, "name":"Jake", "friends": ["Jim", "Marry", "Jake"]}

Perform a whole replacement:

PATCH /class/students/2
{
    
    "friends": ["Bob"]}

# 替换后为:
{
    
    "id": 2, "name":"Jake", "friends": ["Bob"]}

In order to support the add and delete functions, we add _arrayop=[add,remove] to the URL parameters to represent adding and deleting arrays.

For example:

{
    
    "id": 2, "name":"Jake", "friends": ["Jim", "Marry", "Jake"]}
PATCH /class/students/2?_arrayop=add
{
    
    "friends": ["Bob"]}

# 增加后为:
{
    
    "id": 2, "name":"Jake", "friends": ["Jim", "Marry", "Jake", "Bob"]}
PATCH /class/students/2?_arrayop=remove
{
    
    "friends": ["Jim"]}

# 删除后为:
{
    
    "id": 2, "name":"Jake", "friends": ["Marry", "Jake"]}

The disadvantage of this approach is that one _arrayop controls the array action of the entire Playload. Therefore, if the same Playload requires multiple actions, please split it into multiple requests.

5. DELETE deletes resources

Whether payload can be included in DELETE, RFC 7231 "Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content" stipulates this: A payload within a DELETE request message has no defined semantics; sending a payload body on a DELETE request might cause some existing implementations to reject the request.

Therefore, there is no prohibition. Whether it is supported depends on the server implementation. For example, some versions of Tomcat or Jetty will ignore the payload.

The OpenAPI3.0 definition is described as:

The request body applicable for this operation. The requestBody is only supported in HTTP methods where the HTTP 1.1 specification RFC7231 has explicitly defined semantics for request bodies. In other cases where the HTTP spec is vague, requestBody SHALL be ignored by consumers.

Note that for the OpenAPI specification, this ambiguous description is clearly ignored.

After our practice, we found that there are many demands for DELETE with payload. Therefore, we make it clear that DELETE with payload is supported. If the implementation does not support it, please use DELETE Over POST.

Example:

Delete the student with ID 2.

DELETE /class/students/2

Delete all students who have Jim as a friend.

DELETE /class/students
{"friends": ["Jim"]}

Or expressed as DELETE Over POST:

POST /class/students?_method=DELETE
{"friends": ["Jim"]}

4. Example

@AllArgsConstructor
@Data
public class Person {
    
    
    private String id;
    private String name;
    private int age;
}
@RequestMapping("/api/v1/user")
@RestController
public class UserController {
    
    

    @PostMapping
    public String insertUser( @Validated @RequestBody Person person){
    
    
        System.out.println(person);
        return "person";
    }

    @DeleteMapping
    public String deleteUser(@Validated @RequestBody Person person){
    
    
        System.out.println(person);
        return "person";
    }
}

Insert image description here

@RequestMapping("/api/v1/user")
@RestController
public class UserController {
    
    
    
    @PatchMapping
    public String updateUser(@Validated @RequestBody List<String> ids){
    
    
        System.out.println(ids);
        return "person";
    }

    @DeleteMapping
    public String deleteUser(@Validated @RequestBody List<String> ids){
    
    
        System.out.println(ids);
        return "person";
    }
}

Insert image description here

Guess you like

Origin blog.csdn.net/qq_42764468/article/details/132718182