In the iteration of technology, the front end and rear end separated development has become the dominant mode of modern development.The core of connecting the back end and front end is a series of APIs provided by the back end to the front end for interaction.
In actual development, a set of interfaces provided by back-end services may be used for different front-end applications such as the Web, mobile APP, desktop, and even for other programs (for example, different modules of microservices call each other).
If the interface provided by the back-end service can haveEasy to understand, clear standards, and extension friendlyIts features will be conducive to subsequent development and reduce costs.andInterface designed according to REST styleIt just has these characteristics, so it becomes popular in modern Web development.
Although there are a lot of REST materials on the Internet, few are comprehensive, accurate, easy to read, and relevant to practice, which is of limited help to some problems encountered in actual development.So in the process of learning and development, I reorganized and wrote this article, including definition and explanation, comparison with traditional APIs, actual development problems, etc., and summarized it as comprehensively as possible from the perspective of developers, hoping to help readers better understand and use REST.
Note: If you already know about REST, you can go directly fromIn depth RESTful APIThis chapter begins to read.The article comes with some demo codes written in Java's SpringMVC/Boot and JS's Axios, which can be selectively read or skipped as needed.
What are REST and RESTful APIs
Start from definition for preciseness: full name of RESTRepresentational State Transfer, literally translated as:Expressive state transition, provides a set of design principles.(Refer to Baidu Encyclopedia)
This name is confusing because REST omits a subject: "resource".Wherein, "representational" refers to the performance of resources.
In that case, the core of REST is:resources、performance、state transition These three parts.Let's understand it in a more popular way.
resources(Resource): The content that the client wants to request.Pages, pictures, files on the server, and even data processed by the server (such as data queried from the database) are resources.In REST, the concept of resource includes two parts: one is the resource itself, and the other is an identifier that can describe such resources.
The description of the original paper is that resources are conceptual mappings to a group of entities, not mapped entities corresponding to any specific point in time.(A resource is a conceptual mapping to a set of entities, not the entity that corresponds to the mapping at any particular point in time.)
performance(Representation): refers to how resources are displayed.A resource can have multiple "representations". For example, an interface can return data queried from a database, either in JSON or XML, which is the same resource'sDifferent performance。It generally includes two parts:dataandmetadata。Corresponding to the HTTP response, it is the field describing data in the response body and header (for exampleContent-Type)。
state transition : It may be difficult to find a precise definition of this.But it can be basically understood as: when the content of a resource changes, it is transferred from one state to another.In the case of the client server model of the network, the client sends different requests to push the resources on the server to change.
One understanding of REST simplification is that resources are displayed in a certain way and can be driven to change by the client.
Referring to IBM's documentation, REST proposes sixDesign principles(also known as schema constraints):
Unified interface.No matter where the request comes from, all API requests made to the same resource should look the same.The API should ensure that the same piece of data (such as a user's name or e-mail address) belongs to only one Uniform Resource Identifier (URI).Resources should not be too large, but should include every piece of information that customers may need.
No status.The API is stateless, which means that every request needs to contain all the information needed to process it.In other words, the API does not require any server-side sessions.The server application is not allowed to store any data related to the client request.
Cacheability.If possible, resources should be cacheable on the client or server side.The server response also needs to contain information about whether caching of delivered resources is allowed.The goal is to improve the performance of the client and enhance the scalability of the server.
Client/server decoupling.In API design, client and server applications must be completely independent of each other.The client application only needs to know the URI of the requested resource;It cannot interact with server applications in any other way.Similarly, the server application should not modify the client application other than passing it to the requested data via HTTP.
Layered system architecture.In the API, calls and responses go through multiple different layers.Similar to the current microservice architecture, the request will go through the forwarding (proxy) server, API gateway and other levels before entering the real server program.
Encoding on demand (optional).The API usually sends static resources, but in some cases, the response can also contain executable code (such as Java applets).In these cases, the code should only run on demand.
according toREST styleThe designed API is calledRESTful API(Also called REST API directly in some places).The first three principles should be the main focus of API design. 4 and 5 have been met in the current software architecture.
Transition from traditional API to RESTful API
So far, we have all talked about REST at the definition and theoretical level.Now let's ignore the details of the implementation and look at an example of traditional API design, so that we can link REST with API design.
Suppose we want to develop aLibrary management system, one of which is aimed atBook dataDo "Add, Delete, Modify, Query".After the design is handed over to different people, the following interfaces may be obtained (ignore the request and response data first):
Book management API developed by Party AQuery the specified book GET/which?id=1Query multiple books GET/allNew book POST/create bookModify book POST/update bookDelete book POST/del book
Book management API developed by BQuery the specified book POST/MyBook?id=1Query multiple books POST/AllBookNew Book PUT/book/addBookPUT/book/modifyDelete book POST/removeBook
Look, for example, for the same modified interface, A and B use different request methods and path structures.This exposes a defect in the traditional API design: there is no standard or rule for URLs and usage methods (HTTP request methods) of different interfaces.
Single person development projects may not matter.However, there is no unified design specification for API in large-scale systems and multi person cooperation projectsThe interface is difficult to understand and use, or even increase the difficulty of maintenance.
Another problem is that we have no clear specification for the HTTP request mode supported by the interface.For example, we can choose to design aDELETE /getMyUser/id=1And then return the response data in binary form.This is certainly a feasible solution, but it is somewhat strange.
If it is in a team, we can try to agree on some "hard specifications" in order to better develop. For example:
URL structures areVerb abbreviation+noun, multi-level is not allowed
Force query togetStart with, New withaddStart with, delete withdelstart
GET request for query and POST for others
We can design similar APIs for the "Add, Delete, Modify, Query" interfaces of different functions.For example:
Query user GET/getUserNew user POST/addUserDelete user POST/delUser
It looks better than before. It can be formulated as a specification (or style) of interface design.
But can it be further refined?For example, can you continue to refine the path hierarchy of the URL?Even unified singular and plural?
Of course.withAddition, deletion, modification and query of booksInterface as an example, assume that the identifier (i.e. URI) is/books, one way is:
Query books POST/books/getNew Book POST/books/addDelete Books POST/books/del
Or, simply omit actions in the URL and directly use HTTP request methods to express different operations on resources.For example:
Query books GET/booksNew Book POST/booksDelete Books
The last two design ideas have begun to move towards RESTful APIs.
In depth RESTful API
If you try toresourcesFrom the point of view of adding, deleting, modifying and querying APIs, we can get a way of understanding: the goals of these interface operations areresources, different interfaces pair resourcesDifferent operations were performed。
For example, in the above example, the resources for interface operations arebook, different interfaces onlybookDifferent operations were performed.(In other words, the book resource has undergone a state transition)
The core of RESTful API is to useHTTP request methodAs an operation type (behavior), you can use theidentifier (URI) Determine the resources to be operated (i.e. the unified interface in REST principles), and at the same time meet the design principles of REST.
HTTP request method as behavior (core content)
All the request methods defined in HTTP can be found on this page:HTTP request method
In RESTful API, different HTTP request methods express clear meanings:
method
Function description
Idempotent or not
Corresponding back-end operations
GET
Returns the value of an object
True
query
POST
Create a new object, or submit a command
False
increase
DELETE
Delete an object
True
delete
PUT
Update an object (full replacement), or create an object with an identifier
True
Full update
PATCH
Update an object (partial update)
False
Partial update
OPTIONS
Get the information of a request, that is, get the request method supported by a URL
True
nothing
HEAD
Returns the metadata in an object GET response, which is equivalent to a GET without a response body
True
Query/None
amongOPTIONSandHEADRelatively few are used.Other HTTP request methods rarely appear in RESTful APIs, so we will not discuss them.
An interface does not need to support all methods.But for supported methods, interfacesMust conform to the corresponding usage。
In addition, if conditions permit, it is suggested to addOPTIONSTo facilitate the client to retrieve the information of this interface (instead of having to query the API document).Its response header should at least containAllow, recommended plusLinkThe URL of the documentation that points to this interface.For example:
The URL of the RESTful API should beEasy to read and spellOf.Referring to different tutorials and Github APIs, the structure of common URLs can be summarized as follows (brackets indicate optional):
Http (s)://Web address or IP (: port) (/subpath) (/version number)/resource name (/path parameter) (? Query parameter name=parameter value)
For example:
A well structured URL:https://api.contoso.com/v1.0/people/jdoe@contoso.com/inboxhttps://api.contoso.com/v1.0/items?url=https://resources.contoso.com/shoes/fancyUnfriendly URL (not recommended):https://api.contoso.com/EWS/OData/Users('jdoe@microsoft.com')/Folders('AAMkADdiYzI1MjUzLTk4MjQtNDQ1Yy05YjJkLWNlMzMzYmIzNTY0MwAuAAAAAACzMsPHYH6HQoSwfdpDx-2bAQCXhUk6PC1dS7AERFluCgBfAAABo58UAAA=')
commonlyPath parameterIt is used to specify the ID, name and other unique parameters in similar resources,Query parametersIt is used to transfer filter conditions.
Extension: query parameters and path parameters
Query parameters are also called filter parameters. As the name implies, they are generally used to pass parameters to the backend and filter some data.Write at the end of the URL to?Start with multiple parameters&connect.Common in GET and DELETE.
The path parameter is written in the URL path/separate.
Respectively correspond in SpringMVC@RequestParamAnd@PathVariable。
Yes forHierarchyData, whereResource nameandPath parameterMultiple can appear (the path parameter follows the resource name).
Github's API also has multiple levels. "OWNER" and "REPO" are the owner name and warehouse name respectively:https://api.github.com/repos/OWNER/REPO/interaction-limitshttps://api.github.com/repos/OWNER/REPO/actions/workflows/WORKFLOW_ID/disableFor example, the first item indicates the "interaction restriction" under the "REPO" warehouse owned by the "OWNER" user in the "Repos" resource
In addition, there are some piecemeal conventions:
URINoThe verb (action) appears. Because the RESTful API has used HTTP methods to represent the operations performed on resources, it is easy to cause ambiguity if the operations occur again in the URI.For example:GET /books/1Is appropriate,GET /book/get/1Is inappropriate
Resource nameshouldUse the plural form of nouns. Resource is a kind of resource, and the plural number expresses the meaning of the same kind of resource set.It is also OK to use singular numbers, but remember to keep the global consistency, and do not mix singular and plural numbers.
Letters in URLshouldIt is in lower case.Use hyphens for phrases-Segmentation, not hump nomenclature. To be exact, the URI is lowercase.However, if possible, other parts of the URL (such as path parameters) should also be kept in lower case.
In addition, whether the URI is availableabbreviationThere seems to be no clear consensus.For readability,proposalUse fewer abbreviations and only common abbreviations, such as:CPU,PC。
Several common misunderstandings about RESTful API:
Using JSON is RESTful API
URL query parameter cannot appear in URL(?Mode parameter transmission)
Note: The examples in this article are used for front end and back end interaction, but the application scenarios of RESTful API are not limited to this. REST can be considered as long as the API is developed.
Simple Spring MVC code example
For the convenience of back-end developers who are not familiar with HTTP, here is also a simplified Spring MVC code example. The client requested these addresses:
GET https://api.gameinfo.com/developers/mihoyo/games/genshin-impactGET https://api.gameinfo.com/games/1044620
Corresponding Controller definition:
@RestControllerpublic class GameProductController {@GetMapping("/developers/{developerName}/games/{gameName}")public Object getGameById(@PathVariable String developerName, @PathVariable String gameName) {//Query the gameName game developed by the manufacturer named developerName}@GetMapping("/games/{gid}")public Object getGameById(@PathVariable Integer gid) {//Query games with ID of gid}}
URLI.eUniform Resource Locator: calledUniform Resource Locator, indicating the address of an exact network resource.
URII.eUniform Resource Identifier: calledUniform Resource Identifier, used to identifyWebAny type of resources (HTML, video, audio, programs) that can be accessed on the.URI is relative, and its main function is to distinguish it from other resources.
From a level perspective, a URL is a subset of URIs, and URLs are more detailed than URIs.For example, for the server,https://api.example.com/books/1003?param=abcIs the URL where/books/1003Is a URI.
REST design criteria (from REST to RESTful API)
Now we have a preliminary understanding of REST and RESTful APIs.Let's pause for a moment and think about a question: What do we want to talk about REST when designing APIs?One word:design criteria(Designing Guideline)。
For us, using REST to design is more meaningful than just understanding REST.This requires a further refinement of the criteria (equivalent to project development specifications in some respects).
Please rememberREST is a style of design, not aClear implementation standards。
reference resourcesMicrosoft REST API Design GuidelinesA book (hereinafter referred to as the Design Guide), the criteria have at least the following two functions:
Refine implementation schemes and constraints
Keep the designed API consistent
Borrow hereDesign GuidelinesIn a sentence in, the guidelines are established to develop interfaces consistently.
This document establishes the guidelines Microsoft REST APIs SHOULD follow so RESTful interfaces are developed consistently.
Before the formal start of RESTful API design and development, it is recommended to refine a set of design guidelines based on REST, which is more important for team development.
Difference from traditional API
Consistency basics REST style provides a relatively complete design standard for API design, which is consistent and easy for human to read and understand.(Recommended readingDesign GuidelinesChapter 7)
Emphasize semantics The predicate verb (HTTP request method) corresponds to the action (add, delete, modify, query, etc.) executed one by one.
Idempotence Traditional APIs do not attach much importance to interface idempotence.The HTTP request method of RESTful API is also associated with idempotenceThis feature should also be guaranteed when implementing this interface。
Versioning When designing RESTful APIsrecommendAdd in URLVersion No(Note that the URL is not a URI).This is mandatory in some guidelines (e.gDesign GuidelinesChapter 12).The format of the version number is{majorVersion}.{minorVersion}, for example:
#Add at URL path:https://api.contoso.com/v1.0/products/users#As URL filter parameterhttps://api.contoso.com/products/users?api-version=1.0
in additionDesign GuidelinesServices MUST increase their version number in response to any breaking API change(When any destructive API change occurs, the server should add the version number in the response.)
Advantages and disadvantages
Adherence to REST style can bring us the following benefits:
More unified interface URL style to improve the readability of API(Human readable) This idea is equivalent to the development specifications of some companies that require a good name for variables and methods
Eliminate ambiguity caused by improper URL design and ensure idempotence
More elegant handling of new interfaces (interface definition changes) If you want to modify the API, one option is to update the version number of the API instead of doing it on the original basisBackward compatible.thisIt reduces the probability of defining URL conflicts, and also simplifies the naming of new and old interfaces
Possible benefits:
Stateless APIs are easier to develop than stateful APIs
Make full use of the characteristics of HTTP itself
But there are also disadvantages:
REST style is mainly aimed ataboutresourcesProcessing ofInstead of emphasizingaction, increasing the difficulty of API design
Developers need to have a certain understanding of HTTP protocol, front-end and back-end frameworks (such as Spring MVC, Axios)
You may need a little English vocabulary when designing names
Request and Response
In the HTTP protocol, the request and response both contain the header and payload.RESTful APIs also use headers to transfer some data, which should be noted during design.
In the request, the common and important headers are:
Response Header
type
describe
Authorization
character string
Requested authorization data
Date
date
The requested timestamp is based on the client time and uses RFC 5322 date and time format.The server should not rely on the accuracy of the client time.This header is optional, but if there is one, the client must use Greenwich Mean Time (GMT), for example: Wed, 24 Aug 2016 18:41:30 GMT.Here GMT and UTC are equivalent.
Accept
Content Type
The response body data type expected by the client, such as application/xml, application/json, text/javascript (for JSONP).For the server, this header is a hint, and the server can also return different content types.
Accept-Encoding
Gzip, deflate
When appropriate, the REST endpoint (API) should support GZIP and DEFLATE encoding
Accept-Language
"en", "es", etc.
Specifies the language in which the client expects the response.The server does not have to support it, but it needs this field to provide localization support.
Accept-Charset
Character set type, such as "UTF-8"
The default is UTF-8, but the server should also be able to handle ISO-8859-1
Content-Type
Content Type
Mime type of the request body (for example: application/json, PUT/POST/PATCH)
The response should at least include the following:
Response Header
describe
Content-Type
The content type of the response body (for example: application/json)
Content-Encoding
GZIP or DEFLATE, depending on the situation
Date
The time stamp for processing the response, which is based on the server time and uses RFC 5322 date and time format.The time standard is Greenwich Mean Time (GMT), for example: Wed, 24 Aug 2016 18:41:30 GMT.Here GMT and UTC are equivalent.
Some heads will appear in specific scenes (for examplePrefer、If-MatchEtc.), which is used to inform the customer/server of some information. It is only mentioned here but not expanded.
And remember,The HTTP response code is also semantic。In other words, the server needs to select and return the appropriate HTTP response code according to the specific situation.The common ones are as follows:
200: Success
201: The resource has been created (usually the POST method is added successfully, and there is no response body)
204: No content (generally the PUT method is successfully processed and there is no response body)
400: Incorrect requests that the server cannot process
404: Resource not found
Generally speaking, you can select directly according to the meaning of each status code specified in the HTTP protocol.More detailed examples can also be referred toMicrosoft REST API Design Guide。
In actual development, many people do not care about this section.Because in modern development, the technical framework can be used to automatically process the header, and the business layer does not need to handle it manually.
How to handle more actions?
The main body of RESTful API operations is resources, and the commonly used HTTP methods are very suitable for the requirements of "adding, deleting, modifying and querying".But for APIs that focus on expressing actions (operations) and operations other than "add, delete, modify, query", it seems difficult to design according to REST.
This requires us to further abstract the business.Two references are also given here.
One way is toResult of actionAs an abstract resourceresultOperate.Similar ideas can be found in GitHub's API, such as blocking and unblocking user interfaces(Block User - GitHub Docs):
Block a user from an organization:PUT/orgs/{org}/blocks/{username}
Unblock a user from an organization:DELETE/orgs/{org}/blocks/{username}
At this time, the operating resource is not the user, but theBlocked user listAs a resource.Blocking and unblocking users means putting and deleting the list contents.
Another way is to setreceiver of an actionThink of it as a resource and parameterize the operation or operation result.
Another example is to design aStart or stop executing the specified taskInterface.heretaskIt can be regarded as a resource to be operated;Because the task will be changed after starting and stopping the two actionsrunning state , we canrunning state Designed as a parameter.It is used as follows:
Such APIs generally only need to respond successfully, so after processing, they can only respond 204 without the response body.
In addition, please note that HTTP request modes such as PUT and DELETE are likely to be selected in such cases, and the idempotence of the interface needs to be properly handled during development.
Problems and difficulties in practical application
By now, we are familiar with REST itself and its basic usage.However, once the application is started, there are new problems.In this chapter, we will look at some common problems and difficulties.
HTTPS usage and implementation scheme
Do you want HTTPS?No, but HTTPS is highly recommended because:
More secure
The SSL connection is established between the TCP layer and the HTTP layer. The URL (path and parameters) is always encrypted
According to different security requirements, there are different implementation schemes for enabling HTTPS:
If it is a microservice architecture, it can consider that the application (API) level does not do encryption, the upper gateway does HTTPS, and then the gateway exposes the API externally.
Enable encryption on the CDN. The server only allows access to the CDN node.
Selection of response body form (use JSON?)
First, let's conclude that the response format specified by the client is preferred(AcceptHeader), if the server can choose JSON first.
REST andDo not force resources to return(That is, the representation of resources is diverse). Theoretically, the interface forces the return of XML or other formats to conform to REST, but this design results in a bad API.A better design is to let the API return the specified type in the request header first (respond if not supported415 Unsupported Media Type), rather than returning JSON anyway.
To simplify development, you can refer to the following two implementation ideas (take SpringMVC as an example):
Unified judgment at the framework levelAcceptAnd transform the response content (such as custom interceptors)
The controller (business layer) only returns JSON and intercepts allAcceptField is notapplication/json's request (lazy practice)
Use GET to transfer Body
In the HTTP protocol, bothThere is no explicit stipulation that GET cannot take the body, alsoDidn't say they could take the body。However, different programs have different processing methods. For example, Chrome will erase the Body part by default when it initiates a GET request, but curl will not.
Initiate the request in GET mode through curl, and join the request body at the same time
The backend (Spring MVC) can correctly extract the data in the request body and pass it into the method parameters.
So considering the compatibility issue,Not recommendedTake the body with you during GET.If you need to pass parameters, useFilter parameters (URL parameters),The same goes for DELETE.It is also recommended that the client escape the special characters in the parameters (do URL Encode once).
Spring MVC code example
For example, when the front-end requests an API, useGET /test?name=steve&age=2(No HTTP Body) The backend uses SpringBoot as an example, and the following two writing methods are feasible:
use@RequestParamor@PathVariableReceiving parameters (suitable for simple parameters)
Note that the parameters are assembled by Spring in this case, and the annotation and processing of JSON in POJO will not take effect.If the field is an enumeration, you can use theorg.springframework.core.convert.converter.ConverterInterface custom wrapper type to enumeration conversion class.
In actual development, it is recommended to consider using the body in GET only when the following conditions are met:
API is only used between backend and backend
The URL parameter of API is difficult to construct or the URL is too long
Both API providers and users are familiar with HTTP and the network framework they use
There is no hierarchy between the API provider and the caller that will modify the transmission data (including gateway and proxy)
Length of URL
Streaming saving: suggestionsNo more than 2083 charactersOtherwise, you need to negotiate with the client.
HTTP 1.1 protocol (RFC 72303.1.1Chapter) does not specify the URL length limit.However, considering the restrictions between most clients (mainly browsers) and servers, pressInternet Explorer URL length is limited to 2083It is better as the upper limit of URL length.
Do you want to abandon GET?
When designing GET's query API, you may encounter situations that violate the above two principles (for example, using GET requests and using URLs to pass parameters leads to too long).At this time, it is necessary to consider whether the API parameter design is appropriate.
Another solution is that the client still uses POST to initiate requests, and at the same timeX-HTTP-Method-OverrideThe header tells the server which verb to use.Or give up designing according to RESTful API.
PUT or PATCH?
The main differences between the two are:
PUT means full update, idempotent
PATCH means local update, non idempotent
PATCH was added to the HTTP method in 2010. The main purpose is to solve the problem that the full transmission data is too large for each update.A small number of frameworks or tools do not support PATCH by default.
In addition, when PATCH is used, the JSON structure passed may be very different from the POST/PUT structure.thereforeproposalThe API provider and user negotiate in advance.
Considering both the use and implementation of APIs, each has its own advantages.For example, when the front end uses Vue+Element UI to build editing pages, the PUT interface is easier to use.When the backend uses SpringMVC+MyBatisPlus, it is more consistent with the semantics of PATCH by default.
projectshouldSelect as required (usually one of two can be selected).
Can statelessness be "broken"?
No, statelessness is one of the design principles of REST.Moreover, statelessness can simplify the development difficulty for distributed applications.
Most "stateful" situations can be handled as follows:
Convert the status to the requested parameter to eliminate the status (that is, the API itself is still stateless, such as the page number in the paging query)
Save the status data on the client side instead of the server side by means of cookies
Response Data
In actual development, many teams will choose to design and use a unified response body to wrap the data returned by each API.For example, the following is a query response:
{"Code": 1,//Business status code (generally used to indicate success or failure)"Message": "Success",//Status message"Data": {//The actual data node"account": "steve","point": 100}}
The following three situations may be encountered during development:
Request processed successfully✅: The HTTP status code istwo hundred, the business status code is Success, and the data is the actual data
Business processing exception🔴: The HTTP status code istwo hundred, the business status code is failed, and data may have no meaning
Interface request exception❌: The HTTP status code is nottwo hundred, may not enter the business logic at all
Note: From the perspective of receiver semantics, in this case, the unified response body is regarded as a part of the response, rather than a layer of packaging.In other words, the above example is equivalent to:
{"Code": 1,//Business status code"Message": "Success",//Status message"account": "steve","point": 100}
The unified response body can be used to expressBusiness logicThe success status of does not violate the REST style.
However, in the RESTful API, the status code of the HTTP response can be clearly expressedCall (request)Success status of.So you can also directly use the HTTP status code to indicate the success status,Rather than unified responder。This is also a common usage (such as GitHub's API).
The API returns data directly when the response is successful;When the API response fails, the error code (business status code) and description are returned.
But there are also obvious disadvantages:
For browsers, non HTTP 2xx responses will be prompted in the developer tool's Network and Console
For some back-end tools (such as Spring'sFeignClient)Unable to flexibly handle non HTTP 2xx responses
Back end and front end sample code
The implementation of the back end (SpringBoot) and front end (Axios) is not complicated
//Controller@RestControllerpublic class TestController {@GetMapping("user-center/v1.1/user/{id}")public String queryUser(@PathVariable String id) {return "{\\"name\\":\\"Steve\\",\\"point\\":100}";}}//Global exception handling@RestControllerAdvicepublic class CommonExceptionHandler {@ExceptionHandler(value = BusinessException.class)public ResponseEntityhandleBusinessException(BusinessException e) {return ResponseEntity.status(HttpStatus.BAD_REQUEST). body (new Error (1001, "Unable to process the request"));}@ExceptionHandler(value = RuntimeException.class)public ResponseEntityhandleOtherException(RuntimeException e) {return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR). body (new error (1003, "server unknown exception"));}public static record Error(Integer errorCode, String description) {}}
axios.request({url: 'user-center/v1.1/user/10001',method: 'get',}).then(response => {const { name, point } = response.data//Get the data returned by the serverConsole. log (` User: ${name} shares ${point} points `)}).catch(error => {if (error.response) {//The status code that the request was sent successfully and the server also responded to is out of the range of 2xxconsole.log(`HTTP ${error.response.status} (${error.response.statusText})`);//Get error descriptionconst { errorCode, description } = response.dataConsole. log (` Error, reason: ${description}, error code: ${errorCode} `);} else {//There was a problem sending the request. It is usually a network exceptionconsole.log('Network Error', error.message)}});
Authentication (authority)
The authentication method needs to be friendly to the following aspects: cross domain, scaling/load balancing, so stateless authentication schemes such as JWT should be used instead of sessions.In fact, most RESTful APIs useOAuth 2.0Conduct identity authentication.
In addition, in modern architecture (such as microservices), authentication can also be considered at the gateway, and applications will not be authenticated.
CORS (request cross domain)
This is not a problem caused by REST itself, but there are some noteworthy points when designing APIs.stayMicrosoft REST API Design GuidelinesMiddle (Chapter 8), for complianceDesign GuidelinesThe developed service has the following sentence:
Services SHOULD support an allowed origin of CORS * and enforce authorization through valid OAuth tokens. Services SHOULD NOT support user credentials with origin validation.
Reference translation:
ServershouldAll cross site (CORS *) sources are supported, and authorization to use the OAuth token is mandatory.ServerShould notUser credentials with source authentication are supported.
Combined with the context of this chapter, this gives us two design inspirations:
Use stateless, cross domain authentication scheme
The server directly and completely opens CORS restrictions (the client does not need to handle CORS issues separately)
In addition, if the request requires cookies, the response header should be marked withAccess-Control-Allow-CredentialsAnd set totrue。
An example of SpringBoot
@Componentpublic class CorsFilter implements Filter {@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {HttpServletResponse res = (HttpServletResponse) response;//* indicates that cross domain access is allowed for all requestsres.addHeader("Access-Control-Allow-Credentials", "true");res.addHeader("Access-Control-Allow-Origin", "*");res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT");res.addHeader("Access-Control-Allow-Headers", "Content-Type,X-CAF-Authorization-Token,sessionToken,X-TOKEN");if (((HttpServletRequest) request).getMethod().equals(HttpMethod.OPTIONS.name())) {response.getWriter().println("Success");return;}chain.doFilter(request, response);}}
Handling CORS pre checks
CORS policy may lead toPreflight, the client may need to avoid this situation (for example, the client only sends simple HTTP requests).
Example
When visiting Zhihu page, the first time the browser initiatesPre inspection(Request via OPTIONS)
The second time is the actual GET request
In addition, the server needs toProperly process the pre inspection request。according toDesign GuidelinesContent in (Section 8.2)
If the request uses the OPTIONS method and contains the Access-Control-Request-Method header, then it is a preflight request intended to probe for access before the actual request. Otherwise, it is an actual request.
The following conditions can be regarded as pre inspection:
Appears in the request headerOrigin
Request using OPTIONS method
Appears in the headAccess-Control-Request-Method
For the pre check request, the server's response header needs to add the following:
Access-Control-Allow-HeadersHeader list allowed by the client (simple request headerAccept、Accept-LanguageCan be ignored).If there is no restriction, it can also be directly returned to the client requestAccess-Control-Request-HeadersThe value of the header.
Access-Control-Allow-MethodsHTTP request methods that users are allowed to use, such as GET, POST, OPTIONS, etc
Limited space here, but more discussionPre inspection、Simple requestandComplex request。
In actual development, if each API is individually configured for pre checking (that is, to achieve a smaller granularity), the code may become complex.OneAlternativesYes, do the same for all APIs when receiving the pre check.
For example, when developing with SpringBoot, you can configure aInterceptororFilterUnified processing. See the example in the previous section for the code.
Discard REST?
(Yes, I read the title correctly. This is a problem many developers are struggling with.)
It is not difficult to see from the previous content that it is sometimes difficult to design APIs in a REST style for various reasons.For example, the following situations are obviously not suitable for REST design:
The server must be compatible with some very old clients that only support GET/POST
The old back-end service API needs to be rebuilt on a large scale, or new APIs need to be developed for clients using the old technology
In this article, we will not discuss the content irrelevant to technology.As a service developer, sometimes you should consider some non-technical matters, such as development difficulty, efficiency, cost, etc.
Of course, in other cases, as long as there is no obvious contradiction with the REST style, you can consider developing as REST.In particular, it is beneficial to unify the style when developing large-scale projects.
Recommended reading
At the end of the article, some valuable materials are summarized for reference.
Microsoft REST API design guidelines (guidelines):api-guidelines/Guidelines.md(Recommended for readers who want to study in depth)
Unless otherwise specified, the content of this website isSalted fish pioneerOriginal, can be quoted freely, but please indicate the source and link. https://xyuxf.com/archives/2181 Welcome to followSalted fish pioneer(WeChat official account: xyuxf), get dry goods push