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

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

I. Security

Security is the specification of an interface that must be guaranteed. If the interface is not secure, then your interface is exposed to the public network.

1.1 Prerequisites for invoking an interface – Token

Obtaining a token usually involves several parameters: appID, appkey, timestamp, nonce, and sign. We use the above parameters to get the credentials of the calling system.

The appID and AppKey can be directly applied online through the platform, or issued offline. Appids are globally unique. Each APPID corresponds to a customer. Appkeys need to be highly confidential.

Timestamp is a timestamp, using the current Unix timestamp of the system. The purpose of time stamps is to mitigate DOS attacks. Prevents requests from being intercepted after attempting to request the interface. The server side sets a timestamp threshold, and if the request timestamp and server time exceed the threshold, the response fails.

Nonce is a random value. The random value is mainly to increase the variability of sign and protect the idempotent of the interface. The nonce of two adjacent requests is not allowed to be repeated. If the nonce is repeated, it is considered to be repeated submission and the response fails.

Sign is the parameter signature, appkey, timestamp, nonce splicing together for MD5 encryption (of course, there is no problem to use other methods for irreversible encryption).

Token, use parameters appID, timestamp, nonce, sign to obtain the token, as the unique credential of the system call. The token can be set to be valid once (which is more secure), and it can also be set to be time-sensitive, which is recommended here. The frequency of requests for this interface may be high if it is valid once. The token is recommended to be added to the request header so that it is completely distinguishable from the service parameter.

1.2 Using POST as the Interface Request Mode

The two most common ways to call an interface are GET and POST. The difference between the two is also clear: GET requests expose parameters to the browser URL and are limited in length. For higher security, all interfaces make requests in POST mode.

1.3 Client IP Address Whitelist

IP whitelist means that the access permission of an interface is open to some IP addresses. This will prevent other IP addresses from accessing the IP addresses. One of the difficulties of setting IP whitelists is that after your client migrates, you need to contact the service provider again to add a new IP whitelist. There are many ways to set IP whitelist. In addition to traditional firewalls, Sentinel, a component provided by Spring Cloud Alibaba, also supports whitelist setting. To reduce the COMPLEXITY of the API, you are advised to use firewall rules to set the whitelist.

1.4 IP traffic limiting for a Single Interface

Current limiting is to better maintain system stability. Use Redis to make statistics on the number of interface calls, IP + interface address as key, access times as value, each request value+1, and set the expiration time to limit the call frequency of the interface.

1.5 Recording Interface request Logs

Using AOP to record the global request log, quickly locate the abnormal request location, troubleshooting the problem cause.

1.6 Desensitization of sensitive data

In the process of interface invocation, sensitive data such as order number may be involved. Such data usually needs to be desensitized, and the most commonly used method is encryption. The encryption mode is RSA asymmetric encryption with high security. Asymmetric encryption algorithms have two keys that are completely different but exactly matching. Encryption and decryption of the plaintext can be accomplished only with a matching pair of public and private keys.

Idempotence problem

Idempotentiality means that the result of execution of any number of requests has the same impact as the result of execution of a single request. To put it bluntly, the query operation does not affect the data itself no matter how many times it is queried, so the query operation itself is idempotent. However, the database changes every time a new operation is performed, so it is non-idempotent.

There are many ways to solve idempotent problems, but here is a more rigorous one. Provides an interface for generating random numbers, which are globally unique. Put a random number in the interface call. For the first call, after successful service processing, the random number is stored in Redis as key and the operation result as value. At the same time, the expiration time is set. The second call, the query redis, if the key exists, it is proved to be double commit, directly return error.

Three data specification problems

3.1 Version Control

A mature SET of API documentation, once published is not allowed to modify the interface. 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 carries the version number, http://ip:port//v1/list.

3.2 Response Status Code Specifications

A good API also needs to provide a simple response value, based on the status code to get a general idea of the problem. We use the status code of HTTP to encapsulate data. For example, 200 indicates that the request is successful, 4xx indicates that the client has an error, and 5xx indicates that the server has an internal error. The status code design reference is as follows:

classification describe
1xx The server receives the request and requires the requester to continue the operation
2xx successful
3xx Redirection, which requires further action to complete the request
4xx Client error, request contains syntax error or cannot complete request
5xx Server error

Status code enumeration class:

public enum CodeEnum {

    // Add according to business requirements
    SUCCESS(200."Handled successfully"),
    ERROR_PATH(404."Error requesting address"),
    ERROR_SERVER(505."An internal server error occurred");
    
    private int code;
    private String message;
    
    CodeEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public int getCode(a) {
        return code;
    }

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

    public String getMessage(a) {
        return message;
    }

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

3.3 Unified Response Data Format

In order to facilitate the response to the client, the response data will contain three properties: code, Message, and response data. According to the status code and information description, the client can quickly know the interface. If the status code is successful, the client starts 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(a) {
        return code;
    }
    public void setCode(int code) {
        this.code = code;
    }

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

    public Object getData(a) {
        return data;
    }

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

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

    /** * Processing succeeded, put the custom business data set */
    public R fillData(Object data) {
        this.setCode(CodeEnum.SUCCESS.getCode());
        this.setMessage(CodeEnum.SUCCESS.getMessage());
        this.data = data;
        return this; }}Copy the code

conclusion

This article discusses API design specifications in terms of security, idempotentiality, data specification, and more. In addition, a good API also requires a good interface documentation. The readability of interface documentation is important, even though many programmers don’t like to write documentation and don’t like it when others don’t. To avoid adding stress to programmers, swagger or another interface management tool is recommended. With simple configuration, you can test interface connectivity in development and generate offline documentation for managing the API once online.

Pay attention, don’t get lost

If you think the article is good, welcome to follow, like and collect, your support is the motivation of my creation, thank you all.

If there is a problem with the article, please do not be stingy, welcome to leave a message to point out, I will check and modify in time.

If you want to know more about me, you can search “Java Journey” on wechat. Reply to “1024” and you can get learning videos and exquisite e-books. Every day at 7:30 on time push technical articles, so that your way to work is not lonely, and there are monthly book activity, help you improve hard strength!