A brief analysis of the Open API design specifications

Recently due to business needs, the cloud product CSB I participated in research and development needs to open the Open API to the outside world, which is not a difficult thing, because the Open API open mechanism inside Alibaba Cloud is very mature, and I don’t need to design it at all, but this time the demand is mainly for some independent deployment scenarios, and you need to design a set of specifications, which means that you need to make some specifications and constraints on the Open API, so there is this article.

Open API, like the front-end page, has always been the face of the product, and the Open API is not standardized, which will reduce the professionalism of the product. In the cloud scenario, many users will choose to build their own portals to dock the Open API of cloud products, which puts forward an appeal to us to build a mature Open API mechanism.

From a business perspective, there are some guiding principles that guide us to improve the Open API mechanism:

  • The interface used by the front-end page and the interface provided by the Open API are the same set of interfaces
  • Any front-end page interface should have a corresponding Open API

From a technical point of view, there are many OPEN API standards for our reference, and the Open API documentation for some open source products is also very complete. On the one hand, I will take its essence, on the other hand, I must consider the particularity of the output form of my own product. This article will focus on a number of factors to try to explore a suitable open API specification.

 

Open API design considerations

What exactly should a well-established Open API specification regulate?

From the design point of view, it is necessary to consider: naming specification, composition specification, path specification, access parameter specification, data type specification, unified return value specification, error code specification, pagination specification.

From the perspective of the team, whether the back-end primary and intermediate development and front-end research and development in the team have enough experience to understand and implement the API specifications formulated. At the same time, with the flow of people, this Open API specification can be well passed down.

From the perspective of the industry, it is necessary to consider whether the market where the product that provides Open API is mature, and the API style may already have corresponding specifications.

From a product perspective, each product fits a different API style, and this perspective will be highlighted below.

In short, the design of open APIs is a difficult thing to come to terms, and before I introduce the Open API specifications that my products eventually adopt, I will first talk about some familiar concepts, such as restful.

 

Restful norm battle

Where there are people, there will be rivers and lakes.

The same is true where there is code.

If you’re in the coding loop, you’ve heard of the restful specification:

  • Additions, deletions, and corrections should be declared as: POST, DELETE, PUT, PATCH, GET

  • Verbs should not appear, and verbs are uniformly represented by http methods

  • Embodies the abstraction of “resources”

  • Use pathVariable, queryParam, header, statusCode to express a lot of business semantics

The restful specification may seem beautiful, but if you’ve actually tried landing, you’re bound to encounter some similar problems:

  • Taking the user login interface as an example, such an interface is difficult to map to the addition, deletion, modification and modification of resources
  • Taking the interface request error rate in the last 7 hours of query as an example, derived from complex query scenarios such as graphQL, often requires a json structure, GET can not achieve this, only POST can be passed

Based on this, the restful specification gradually has an objection:

  • Forcing everything to be “resourced” is contrary to common sense of development, and the interface may not be able to be mapped by simple additions, deletions, and corrections
  • Complex query semantics may not be expressed in GET

Fans of the restful style have no shortage of criticism of these objections, and there are inevitably statements in the community that “the main people who reject the restful style are low-level unenterprising architects and front-end programmers, who will not design as a human problem, not a normative problem” and so on. At the same time, the restful is sublimated: the retrieval problem of complex parameters should be classified as post in the restful semantics, because the behavior is not the positioning of the resource (GET), but the retrieval of the resource (POST)

This apparently irritated the nerves of opponents of the restful style, dismissively: Oh, stupid restful fundamentalists.

Don’t know if you’re a supporter or an opponent of restful? Or, neutral.

The dispute over restful ends here for the time being, and this controversy is purely fictitious, and the officials need not worry about it. Whatever you think of restful, as I discuss below, you can be a neutral, otherwise the effect is halved.

 

ROA vs. RPC

API design is not only a restful specification, in the larger perspective, the mainstream API design style can actually be divided into

  • Resource-oriented design, known as ROA (Resource oriented architecture)
  • Process-oriented design, i.e. RPC (Remote Procedure Call)

Restful is a typical example of roA style, and RPC style is relatively less well known, but in fact most of the system interface is RPC style, but the concept of RPC style is less well known.

Take the CRUD of the user module as an example, compare the following two styles:

 

ROA style

Create User (POST)

Request:
POST /users{"name": "kirito", "age": 18}
Response:
HTTP 201 Created
{"id": 1, "name": "kirito", "age": 18}

 

Query User (GET)

Request:
GET /users/1
Response:
HTTP 200 OK
{"id": 1, "name": "kirito", "age": 18}

 

Query User List (GET)

Request:
GET /usersResponse:HTTP 200 OK{[{"id": 1, "name": "kirito", "age": 18}], "next": "/users?offset=1"}

 

Create/Modify User (PUT)

Request:
PUT /users/1
{"name": "kirito", "age": 19}
Response:
HTTP 200 OK
{"id": 1, "name": "kirito", "age": 19}

 

Modify User (PATCH)

Request:
PATCH /users/1
{"age": 20}
Response:
HTTP 200 OK
{"id": 1, "name": "kirito", "age": 20}

 

Delete User

Request:
DELETE /users/1
Response:HTTP 204 No Content

The ROA style and restful specifications illustrate the same thing, and to facilitate its comparison with the RPC-style interface, here are some of the noteworthy points of the example above:

  • Using HTTP response codes (200, 201, 204), the mapping of HTTP semantics and business semantics is completed, and the exception flow also appears 404, 401, etc. (for reasons of space, this article does not introduce the exception flow)
  • The PATCH section modifies the resource, and the request body is the content of the modified section; PUT creates/modifies a resource, and the request body is the entire content of the new resource
  • id is the resource locator, while age, name are attributes

 

RPC style

Create User (POST)

Request:
POST /user/createUser{"name": "kirito", "age": 18}
Response:
HTTP 200 OK
{"code": 0, "message": "", "data": {"id": 1, "name": "kirito", "age": 18}}

 

Query User (POST)

Request:
POST /user/getUser{"id": 1}
Response:
HTTP 200 OK
{"code": 0, "message": "", "data": {"id": 1, "name": "kirito", "age": 18}}

 

Query User List (POST)

Request:
POST /user/listUsersResponse:HTTP 200 OK{"code": 0, "message": "", "data": {"user": [{"id": 1, "name": "kirito", "age": 18}], "next": "/user/listUsers?offset=1"}}

 

Modify User (POST)

Request:
POST /user/modifyUser{"id": 1, "name": "kirito", "age": 19}
Response:
HTTP 200 OK
{"code": 0, "message": "", "data": {"id": 1, "name": "kirito", "age": 19}}

 

Modify User Name (POST)

Request:
POST /user/modifyUserAge{"id": 1, "age": 20}
Response:
HTTP 200 OK
{"code": 0, "message": "", "data": {"id": 1, "name": "kirito", "age": 20}}

 

Delete User

Request:
POST /user/deleteUser{"id": 1}
Response:
{"code": 0, "message": ""}

RPC style is not like the RESTFUL ROA style there are some conventional norms, each business system in the landing, there are differences, so here is only the author’s personal experience, I hope that readers can seek common ground while reserving differences:

  • user is the module name and does not need to be used in a plural form like ROA style
  • Instead of mapping CRUD to http methods, HTTP Methods use POST uniformly, and query scenarios can also use GET
  • The return value carries code, message and data to map the response status and response information, generally you can define the status code of the code yourself, this article uses 0 to identify the success of the request, the message is meaningful only when the business response fails, and the data represents the business response result

The choice of RPC and ROA requires decisions based on the business situation of the product itself. There are the following guidelines:

  • APIs with complex business logic, RPC style should be used when you cannot use simple additions, deletions, changes, and descriptions.
  • If your business is part of an industry standard that requires a restful style API or ROA to meet your business needs, you should use ROA style.

AWS mainly adopts RPC style, Azure and Google mainly use ROA (restful) style, and Alibaba Cloud OpenAPI supports both RPC and ROA, mainly RPC.

Although the norm is innocent, I have seen many “pits” in the ROA style in practice:

  • Require resources to go first, that is, design resources first, and then design interfaces, which requires higher requirements on the software development process
  • Incorrect ROA design case 1: When an application server such as tomcat processes an HTTP request for a DELETE method, it is not allowed to carry a request body by default, and it needs to be explicitly enabled, resulting in a deletion failure. (This case is the designer’s problem, the complex deletion scene should not be mapped to DELELE, but should be changed to POST, DELETE should not carry a request body)
  • Incorrect ROA design case 2: Parameters carried in the restful path may cause regular matching problems, such as mistakenly using mailbox as a path parameter, or a conflict problem with multi-level path matching (this case is the designer’s problem, complex query scenario, should not be mapped to GET, but should be changed to POST, the path should only appear in the resource locator, not the attribute)
  • With a response code of 404, it is difficult to distinguish whether a real path does not exist or a resource does not exist
  • It is not conducive to scenarios such as docking gateways that require configuration of route forwarding

CSB’s Open API specification wants to meet the following requirements:

  • When the back-end development design interface, there is a clear design idea, not because of whether an interface is implemented with POST or GET, and does not spend too much time on the abstraction of resources (this is not to say that resources do not need to be designed)
  • When the front-end develops the docking interface, it can cooperate with the back-end relatively quickly and is conducive to the encapsulation of the front-end interface
  • When users connect to the Open API, the overall style is consistent and the modules are clear

In summary, in terms of design style selection, I plan to adopt the design specifications of RPC. To summarize the advantages of the RPC style:

  • API design is less difficult and easy to land
  • Most of Alibaba Cloud’s mature IAAS layer products use the RPC specification
  • Suitable for complex business scenarios

 

A detailed example of RPC interface documentation

Create a service

Request parameters

UpstreamType=fixed is required, example: [{“host”: “1.1.1.1”,”port”: “80”,”weight”: “1”}]

 

The name in the registry, upstreamType=discovery is required

 

serial number The name Chinese the field The English name of the field data type Required illustrate
1 name name string be Display name
2 agreement protocol string be Enumeration value: http/grpc/webservice
3 Load balancing lb string be Enumeration value: random/roundrobin
4 Upstream type upstreamType string be Enumeration value: fixed/discovery
5 List of nodes nodes array not
6 Source id originId string not
7 The service name serviceName string not
8 Service description description string not
9 Gateway id gatewayId string be

 

Returns the parameter

 

serial number The name Chinese the field The English name of the field data type illustrate
1 Response code code int 0 Marked successful; 1 Identity failed
2 Response information message string
3 Response results data string Returns the service ID

 

Request an example

POST /service/createService
Request:{"name": "httpbin",
"protocol": "http",
"lb": "random",
"upstreamType": "fixed",
"nodes": [
{"host": "httpbin.org",
"port": "80",
"weight": "1"
}],"gatewayId": "gw-1qw2e3e4"
}Response:{"code": 0,
"message": "",
"serviceId": "s-1qw2e3e4"
}

 

API naming conventions

  • APIs should use spelled English and conform to grammatical specifications, including singular and plural, tense, and language conventions

  • You cannot have multiple APIs with similar meanings but no practical differences in functionality, such as /user/getUser and /user/describeUser

  • Language Habits: The use of pinyin is prohibited

  • The naming conventions for the following common scenarios are fixed

    • Parameters of the datetime type should be named xxxxTime. For example: CreateTime
  • Common operation name specification

    • create: Create
    • modify: Change
    • delete: Delete
    • get: Get the details of a single resource
    • list: Gets a list of resources
    • establishRelation: Establish resource relationships
    • destroyRelation: Destroy resource relationships

 

summary

Take a specification advocated in this article as an example: “All interfaces use POST”, which is not to accommodate low-level unenterprising architects and front-end programmers (I saw on the community forum), but to improve development efficiency, reduce communication costs, reduce O&M and mis-positioning costs, and invest the cost of blind tossing into other fields such as business architecture design, testing systems, online monitoring, disaster recovery and downgrading.

The interface specification is not what I summarized, only RPC and ROA, there are some remarks that classify GraphQL as a separate API design style for complex query scenarios, interested students can refer to es’s API documentation.

In summary, I plan to adopt the API design style of RPC.

Be the first to comment

Leave a Reply

Your email address will not be published.


*