Rest api parameters and content-type, apicontent-type

Source: Internet
Author: User

Rest api parameters and content-type, apicontent-type

When I recently provided rest APIs to the project team, I encountered a problem about interface parameter transfer, mainly because I did not fully consider the usage of third-party callers, we should try to be compatible with the interface call methods provided by the company before, which can reduce the learning cost of third-party callers, although the previous method is not so recommended, A good practice is to be compatible with old practices and also support recommended practices.

For the http post-based interface, I will first select application/json for Content-type, but the previously provided interface uses application/x-www-form-urlencoded, it is the default form submission type and is submitted to the server based on the key/value format. How does spring mvc receive the following two types of classic data? (For form-data, it can pass key-value pairs or upload files. The following two types of files are not involved here ):

  • Content-type = application/json: add the @ RequestBody annotation to the parameter, indicating that the parameter is obtained from the http requestbody.

Parameters in are in standard json format and are very friendly to front-end js.

  • Content-type = application/x-www-form-urlencoded. the annotation of @ RequestBody cannot be added to the parameter.

You can see the parameter format behind the URL in the parameter form and get request.


Why is the application/x-www-form-urlencoded type not recommended? It has the following problems:

  • If it is difficult to test, don't try to use tools such as postman: submitting to the server is actually a MultiValueMap. If the object in value is also an object, it is very difficult to construct this parameter, view its process
    • The key1 = value1 & key2 = value2 format is used to concatenate all parameters. To learn the meaning of each parameter from a long string of characters, you can't find it easy.
    • The value must be encoded. The encoded value is unfriendly to the caller.
    • Value is a complex object, which is worse. Generally, parameters can only be serialized by a program.
  • Complex client calls

You need to construct the List <NameValuePair>. Generally, parameters passed on the page are an object Model, and you need to convert the Model to a List <NameValuePair>. if the object is complex, building this Key/Value is annoying. Here is a comparison of java calls through apache httpclient to see which one is simple.

    • Application/x-www-form-urlencoded

You need to manually convert the model to NameValuePair.

    • Application/json

Here we only need the Model, and there is no need for secondary conversion, and the structure is very clear.

  • The key/value language does not have a strong json expression. Which of the following two do you prefer?
    • String

In tools like http requests such as post man, if the value corresponding to the key is an object, you need to get its serialized string through the tool and enter it in the field, it's annoying to think about it. If you say that I don't need to use these similar tools for testing, it's another thing.

    • Json

  • More complex data structures

If the objects to be submitted are complex and there are many attributes, the construction of the Map will be very complicated if all attributes are built into MultiValueMap. Imagine if the object has a multi-level nested object. To avoid this problem, we store the business objects to be submitted as a key. value is the serialized string of the object. Added some non-business parameters, such as security token and other parameters, effectively reducing the complexity of MultiValueMap construction. However, this method is more advanced than the json transmission method. For example, we have another layer of parameters, jsonParam.



What if the problem is solved?
We cannot help but be compatible with the existing mode, but want to support json. The focus is on receiving parameters so that they can be perfectly compatible with the two parameters mentioned above. Here we can start with HttpMessageConverter, this is used to map request parameters to entity parameters in spring mvc method. We can write a custom class that uses FormHttpMessageConverter internally to receive MultiValueMap. Even if the @ RequestBody annotation is added to the method parameter, the custom converter is used, you will have the opportunity to re-assign values to parameters.

One problem to be solved in this method is that each parameter is processed as a string during client transmission, which leads to the conversion from FormHtppMessageConverter to Map, the attribute of an object is recognized as a string instead of an object. The result is that an error occurs during deserialization. Fortunately, we wrapped the object to be submitted once and generated a common object parameter jsonParam, which only needs to process this special object. The method is to retrieve jsonParam from the Map, deserialize its content, update the Map value, and perform deserialization again.

Currently, the following problems exist:

  • Serialized fields are agreed upon and basically processed based on our post model. They are targeted converter.
  • The convertValue of jackon called at the end of the Code has requirements on the object types to be deserialized. It seems that generic types are not supported. For example, CommonParamInfoDto <SearchParamInfo <ProductSearchInfo>

The complete conveter code is as follows. In fact, the main code is the serialization of specific fields in the texture. Other methods are default.

public class ObjectHttpMessageConverter implements HttpMessageConverter<Object> {    private final FormHttpMessageConverter formHttpMessageConverter = new FormHttpMessageConverter();    private final ObjectMapper objectMapper = new ObjectMapper();    private static final LinkedMultiValueMap<String, ?> LINKED_MULTI_VALUE_MAP = new LinkedMultiValueMap<>();    private static final Class<? extends MultiValueMap<String, ?>> LINKED_MULTI_VALUE_MAP_CLASS            = (Class<? extends MultiValueMap<String, ?>>) LINKED_MULTI_VALUE_MAP.getClass();    @Override    public boolean canRead(Class clazz, MediaType mediaType) {        return objectMapper.canSerialize(clazz) && formHttpMessageConverter.canRead(MultiValueMap.class, mediaType);    }    @Override    public boolean canWrite(Class clazz, MediaType mediaType) {        return false;    }    @Override    public List<MediaType> getSupportedMediaTypes() {        return formHttpMessageConverter.getSupportedMediaTypes();    }    @Override    public Object read(Class clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {        Map input = formHttpMessageConverter.read(LINKED_MULTI_VALUE_MAP_CLASS, inputMessage).toSingleValueMap();        String jsonParamKey="jsonParam";        if(input.containsKey(jsonParamKey)) {            String jsonParam = input.get(jsonParamKey).toString();            SearchParamInfo<Object> searchParamInfo = new SearchParamInfo<Object>();            Object jsonParamObj = JsonHelper.json2Object(jsonParam, searchParamInfo.getClass());            input.put("jsonParam", jsonParamObj);        }        Object objResult= objectMapper.convertValue(input, clazz);        return objResult;    }    @Override    public void write(Object o, MediaType contentType, HttpOutputMessage outputMessage) throws UnsupportedOperationException {        throw new UnsupportedOperationException("");    }}

 

After the conveter has been written, it must be configured in the configuration file to take effect.

 

Finally, our method can be written in this way, that is, key/value pairs and json

My goal is that api parameters can support application/x-www-form-urlencoded and application/json. The above is a method that I can think of currently, if you have other better methods, give more advice.

 

I can use the post man test again happily. Third-party callers can also be recommended to use json first. I believe that the advantages of simplified programming and convenient debugging should be able to attract them.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.