In the distributed, micro-service prevailing today, the vast majority of projects have adopted the micro-service framework, front and back end separation. Aside: The responsibilities of the front end are becoming more and more clear. The front end is now called the big front end, and the technology stack and ecosystem are very mature. The back end people looked down on the front end people, but now the back end people have to rethink the front end, the front end is very systematic.

The overall architecture of the general system is shown below:



To be clear, some people will reply that the architecture is too simple, too low, no gateway, cache, messaging middleware, ah, ah, ah. Since this article is mainly about the API, we will focus on it, and the other modules will supplement it.

The interface interaction

The front end requests the URL path and passes in relevant parameters according to the convention. The back-end server receives the request, processes the service, and returns the data to the front end.

For the restful style of THE URL path, as well as the requirements of the public request header (such as: app_version,api_version,device, etc.), we will not introduce here, friends can learn by themselves, also relatively simple.

How does the back-end server return data to the front end?

Returns the format

The back end returns to the front end in a JSON body, defined as follows:

{# Return status code code:integer, # Return information description message:string, # Return value data:object}Copy the code

CODE status CODE

Code returns the status code, which is usually added as needed during development. If the interface wants to return a user permission exception, let’s add a status code of 101. Next time we want to add a data parameter exception, let’s add a status code of 102. This can satisfy business as usual, but the status code is too messy

We should be able to refer to the status code returned by the HTTP request. Here are the common HTTP status codes:

200 - Request succeeded 301 - Resource (web page, etc.) was permanently transferred to another URL 404 - Requested resource (web page, etc.) does not exist 500 - Internal server errorCopy the code



We can refer to this design, the benefit of which is to classify the error type into some interval, if the interval is not enough, you can design it into 4 digits.

#1000 to 1999 indicates a parameter error. #2000 to 2999 indicates a user error. #3000 to 3999 indicates an interface exceptionCopy the code

In this way, the front-end developer can know what the error is based on the status code after getting the return value, and can quickly locate the error based on the description of the message.

Message

This field is relatively simple to understand, is the error occurred, how to friendly prompt. A common design is to design with a code status code, such as



And then define the status code in the enumeration



The status code corresponds to the information one by one, which is easier to maintain.

Data

Return data body, JSON format, according to the different business and different JSON body.

We’re going to design a return body class, Result



Control layer Controller

We process the business request at the Controller layer and return it to the front end, for example an order



We see that after we get the Order object, we use the Result constructor to wrap the assignment and then return it. If you find that the packaging of the constructor is not very troublesome, we can optimize it.

Beautiful and optimization

We can add static methods to the Result class, just to make sense



So let’s change the Controller



Code is not more concise, but also beautiful.

Elegant optimization

Above we saw the addition of static methods to the Result class, making the business process code cleaner. But have you noticed that there are several problems with this:

1. Each method returns a Result wrapper object with no business meaning

2, in the business code, we call result. success when success, exception error call result. failure. Student: Is there a lot of remainder

If the id is null, you can use Hibernate Validate to check whether the id is null. There is no need to do so in the method body.

Our best bet is to return the real business object directly, preferably without changing the way the business was done, as shown below



This is the same code that we normally use, very intuitive, directly return the order object, so it’s not perfect. So what’s the implementation?

Implementation scheme

Friends how to achieve is not a little idea, in this process, we need to do a few things

1. Define an annotation @responseresult to indicate that the value returned by the interface needs to be wrapped

2, intercept the request and determine if the request needs to be annotated by @responseresult

3. The core step is to implement the ResponseBodyAdvice and @controllerAdvice interfaces, determine whether the return value needs to be wrapped, and if so, override the return value of the Controller interface.

Annotation class

Used to mark whether the return value of a method needs wrapping



The interceptor

Intercepting a request, whether or not the value returned by the request needs to be wrapped, is a matter of parsing the @responseresult annotation at run time



The core idea of this code is to get the request, whether it needs to return a value wrapper, and set an attribute tag.

Override return body



The above code simply determines if return value wrapping is needed, and if so, wraps it directly. Here we are only dealing with the normally successful wrapper. What if the method body reports an exception? Handling exceptions is also simple, as long as you determine whether the body is an exception class.



How to do the global exception handling, space reasons, old gu here do not do the introduction, as long as the thinking is clear, their own transformation on the line.

Rewrite the Controller



Put the @responseresult annotation on the controller class or on the body of the method, and that’s ok. Easy. To return to this design idea, is not simple, elegant.

conclusion

Is there any other room for optimization? Of course there is. For example: each request to reflect, to get the request method needs to wrap, in fact can do a cache, do not need to be resolved every time.

Source | r6d. Cn/tEvn