This accessory is a slide that I recently shared with the team about designing the HTTP API, combining this and some of the mistakes of our team history to summarize some of the best internal experiences.
Brief introduction.
This share focuses on the following sections:
- Best practices for HTTP + JSON API
- More focused on API usage and conceptual consistency
- The experience of these uses is not the ultimate and only solution
- And you can't handle all the problems you encounter in any environment.
There will also be some badcase, these badcase are generally I am responsible for or development of the service encountered problems.
Background knowledge.
In the HTTP API practice, the following background knowledge is involved, and you may need to understand
- HTTP attempt
- JSON specification
- It's best to write a few service APIs.
- Restful
Agenda.
This slide will be communicated and discussed from the following three aspects, in achieving a reasonable, easy-to-use API to focus on.
- API Basics
- Send Request
- return results
API Basics
- Resource isolation (separate concerns)
- Secure connection
- Service-side version number
- Etags & Cache
- Request IDs
- Ranges
Separate concerns
When planning an API, you should distribute different "resources" under different URIs, instead of placing different resources under the same URI.
Here's a good example:
/v1.0/gossip/mine
/v1.0/gossip/user/uid
/v1.0/gossip/detail/gossip_id
/v1.0/user/invite
I also encountered some bad APIs in my work:
Host:prot/?qt=cd2
Host:port/?qt=s
The bad example is that all the operations on the resource are put into the get parameters, so the most immediate disadvantage is that it will affect the online lookup log (because you cannot ensure that QT will appear in the? Back, and then if there are multiple fields that need grep, then the bash has to be shot, and the online grep log is simply ' Pain-in-the-ass '.
In addition, in the code, the latter way can also cause a little confusion. In this case, for example, the former entry is written like this:
1App = Flask (__name__)2 App.register_blueprint (User_api,3url_prefix='/v1.0/user')4 App.register_blueprint (Gossip_api,5url_prefix='/v1.0/gossip')6 App.register_blueprint (Bigbro_api,7url_prefix='/V1.0/DD')8 App.register_blueprint (Util_api,9url_prefix='/')TenApp.run (host='0.0.0.0', Port=port, Debug=true)
The latter, in general, is written like this:
1 $QT $_request [' Qt ']; 2 if ($qt = = ' CD2 ') {3 // XXX 4 Else if ($qt = = ' s ') {5 // XXX 6 }
Secure connection
An API, in terms of security, should do the following:
- Use all TLS
- Close the 80 port of Web Server
- Return ' 403 Forbidden ' for non-TLS requests
Similarly, try to avoid using ' redirect ' because the library that the client uses may not handle redirection properly, RD may ignore redirection, and multiple redirects will increase the pressure on the service.
Service-side version number
service, the compatibility before and after the client upgrade, has been a human black hole for service development. So starting with the first version of the service, we need to take the issue of versioning into account.
The workaround is to increase the version number of the current usage protocol in each request. A simple method is to increase the version number in the Header, which can reduce the interference of the version information to the API interface.
such as this:
Accept:application/vnd.heroku+json; Version=3
If you do not, then after a period of time in your service operations, especially when the client has been released but later found a bug, your code is likely to be this:
1 if (isset($_request[' Cduss ']) &&2 ($result[' cdstat '] = = 0) &&3 (substr($param[' OS '], 0, 6) = = ' iphone ') &&4 ($param[' sv '] = = ' 2.1.0 '))5 { 6 $rst[' errorno '] =-1; 7 }
Etags, Cache
Reasonable use of etags, with the Cache, can simultaneously alleviate the service side, the client pressure. This requires the client and server mates:
- The Server sets the corresponding etags for each returned resource
- Client needs reasonable use of etags (' If-none-match ')
- Server side needs to respond to etags information in the request header
About the Etags, If-none-match, you let the dog search yourself.
Request ID
For services that involve a lot of upstream and downstream, and require cross-team APIs, the request ID is a magic weapon for you: it passes a uniform rule that adds a unique ID for the request to the HTTP header and delivers it to the downstream service, like a line, that connects the entire service flow online, This ID can be used later to analyze the execution of the request.
At the same time the Server side should also add the Request ID in the returned results, so that the client can get it, will provide great help for debugging.
Range
Never use Pg=x&num=y&order=uid for pagination, sorting, and putting all of these fields in the range:
- Client sends a Range Header
- Server return, need to add ' next-range ' Header
- "Default-page-size" and "max-page-size" need to be agreed.
You see, all using Range, the client does not need to make a piece of the request at all, just put the last Server back "Next-range" back to the request header, you can complete the "next page" operation.
Like this:
Curl-i-n-x GET https://api.heroku.com/apps \
-h ' ' Accept:application/vnd.heroku+json; Version=3 ' \
-H ' range:name ... order=desc,max=10, ""
Accept:application/vnd.heroku+json; Version=3
Http-api-design How to design a reasonable HTTP API (i)