How to design an awesome API interface

Keywords: Java Interview Programmer architecture

In daily development, there are always various interfaces. Front and rear end data transmission interfaces, third-party service platform interfaces. The front and rear data transmission interfaces of a platform generally communicate in the Intranet environment and use the security framework, so the security can be well protected. This article focuses on how to design the business interface provided to the third-party platform? What should we consider?

Mainly from the above three aspects to design a secure API interface.

I. security issues

Security is a specification that an interface must guarantee. If the interface cannot guarantee security, then your interface is directly exposed to the public network environment.

1.1 precondition for calling interface - token

Obtaining a token usually involves several parameters appid, appkey, timestamp, nonce and sign. We use the above parameters to obtain the credentials for calling the system.

Appid and appkey can be applied online or issued offline. Appid is globally unique. Each appid will correspond to a customer. Appkey needs to be highly confidential.

Timestamp is a timestamp, which uses the current unix timestamp of the system. The purpose of timestamp is to mitigate DOS attacks. Prevent the request interface from being attempted after the request is intercepted. The server sets the timestamp threshold. If the request timestamp and server time exceed the threshold, the response fails.

Nonce is a random value. Random value is mainly used to increase the variability of sign and protect the idempotency of the interface. Two adjacent requests nonce are not allowed to be repeated. If they are repeated, it is considered as repeated submission and the response fails.

sign is a parameter signature, and appkey, timestamp and nonce are spliced together for md5 encryption (of course, it's OK to use other methods for irreversible encryption).

Token: use the parameters appid, timestamp, nonce and sign to obtain the token as the unique voucher for the system call. A token can be set to be valid once (which makes it safer) or time effective. It is recommended to set time effective here. If it is valid at one time, the request frequency of this interface may be very high. The token is recommended to be added to the request header, which can be completely distinguished from the business parameters.

1.2 use POST as the interface request mode

Generally, the two most commonly used methods of calling interfaces are GET and POST. The difference between the two is also obvious. The GET request will expose the parameters in the browser URL, and there are restrictions on the length. For higher security, all interfaces are requested by POST.

1.3 client IP whitelist

ip white list refers to opening the access rights of the interface to some ip addresses. In this way, you can avoid other ip access attacks. The trouble in setting the ip white list is that when your client migrates, you need to contact the service provider again to add a new ip white list. There are many ways to set the ip white list. In addition to the traditional firewall, sentinel, a component provided by spring cloud alibaba, also supports the white list setting. In order to reduce the complexity of the api, it is recommended to use firewall rules to set the white list.

1.4 single interface for ip current limiting

Current limiting is to better maintain system stability. redis is used to count the number of interface calls. The ip + interface address is used as the key, the number of accesses is used as the value, and each request is value+1. The expiration time is set to limit the frequency of interface calls.

1.5 record interface request log

Use aop to record the request log globally, quickly locate the abnormal request location, and troubleshoot the cause of the problem.

1.6 desensitization of sensitive data

In the process of interface call, sensitive data such as order number may be involved. This kind of data usually needs desensitization, and the most commonly used method is encryption. The encryption method uses RSA asymmetric encryption with high security. Asymmetric encryption algorithm has two keys, which are completely different but completely matched. The encryption and decryption of plaintext can only be completed by using a matching pair of public and private keys.

Idempotent problem

Idempotency means that the execution result of any multiple requests has the same impact as that of one request. To put it bluntly, the query operation will not affect the data itself no matter how many times, so the query operation itself is idempotent. However, the database will change every time the new operation is executed, so it is non idempotent.

There are many ideas for solving idempotent problems. Here is a more rigorous one. It provides an interface for generating random numbers, which are globally unique. Bring in random numbers when calling the interface. After the first call and successful business processing, store the random number as key and the operation result as value in redis, and set the expiration time. The second call is to query redis. If the key exists, it is proved that it is submitted repeatedly and an error is returned directly.

III. data specification

3.1 version control

A set of mature API documents, once released, are not allowed to modify the interface at will. At this time, if you want to add or modify an interface, you need to add version control. The version number can be an integer or a floating-point number. Generally, the interface address will be marked with the version number, http://ip:port//v1/list .

3.2 response status code specification

A powerful API also needs to provide simple and clear response values. You can roughly know the problem according to the status code. We use the http status code for data encapsulation. For example, 200 indicates that the request is successful, 4xx indicates a client error, and 5xx indicates an internal error in the server. The design reference of status code is as follows:

classificationdescribe
1xxThe server receives the request and needs the requester to continue the operation
2xxsuccess
3xxRedirection, further action is required to complete the request
4xxClient error, request contains syntax error or cannot complete request
5xxServer error

Status code enumeration class:

public enum CodeEnum {

    //  Add according to business requirements
    SUCCESS(200,"Processing succeeded"),
    ERROR_PATH(404,"Request address error"),
    ERROR_SERVER(505,"An internal error occurred on the server");
    
    private int code;
    private String message;
    
    CodeEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}

3.3 unified response data format

To facilitate the response to the client, the response data will contain three attributes, status code, message and data. The client can quickly know the interface according to the status code and information description. If the status code returns successfully, start processing data.

Definition of response results and common methods:

public class R implements Serializable {

    private static final long serialVersionUID = 793034041048451317L;

    private int code;
    private String message;
    private Object data = null;

    public int getCode() {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }
    public void setMessage(String message) {
        this.message = message;
    }

    public Object getData() {
        return data;
    }

    /**
     * Put response enumeration
     */
    public R fillCode(CodeEnum codeEnum){
        this.setCode(codeEnum.getCode());
        this.setMessage(codeEnum.getMessage());
        return this;
    }

    /**
     * Put in response code and information
     */
    public R fillCode(int code, String message){
        this.setCode(code);
        this.setMessage(message);
        return this;
    }

    /**
     * After successful processing, it is put into the user-defined business data collection
     */
    public R fillData(Object data) {
        this.setCode(CodeEnum.SUCCESS.getCode());
        this.setMessage(CodeEnum.SUCCESS.getMessage());
        this.data = data;
        return this;
    }
}

summary

This article discusses the API design specification from the aspects of security, idempotency and data specification. In addition, a good API needs an excellent interface document. The readability of interface documents is very important, although many programmers do not like to write documents, and do not like others not to write documents. In order not to increase the pressure of programmers, it is recommended to use swagger or other interface management tools. Through simple configuration, the connectivity of the interface can be tested during development, and offline documents can also be generated after online for API management.

 

Posted by RobbertvanOs on Sun, 28 Nov 2021 05:18:49 -0800