Deploying Api REST Using Spring

One of the best ways to write a RESTFul api application is to add version control. eg:

http://my-server/api/v1/getData http://my-server/api/v2/getData 

Our application provides REST api using the Spring framework. We mark the class as a controller, use the RequestMapping annotation to map the URL of the function, and add some objects that were translated to / from json objects.

For instance:

 @RequestMapping(method = RequestMethod.POST, value = "/api/v1/getData") public @ResponseBody ResponseDataDTO getData(@RequestBody OperationsDetailsTDO details) {...} 

Now we want to provide the second version of the API. About 2/3 of the functions remain unchanged, and 1/3 change. Changes occur in both logical and JSON objects.

I wonder how to create code. I find this kind of code difficult to handle:

 @RequestMapping(method = RequestMethod.POST, value = "/api/{version-var}/getData") public @ResponseBody ResponseDataDTO createReleaseFromTemplate(@PathVariable("version-var") Integer version, @RequestBody OperationsDetailsTDO details) { if (version == 1) { doForVersion1(); } else if (version == 2) { doForVersion2(); } } 

This will be difficult, since each function will have a different branch. To demonstrate the problem, if I have an automatic tool that generates documentation, it will not be able to understand what the API is.

Secondly, I am wondering what should I do with classes bound to a JSON object. Do all these classes need to be duplicated for minor changes?

thanks.

+6
source share
2 answers

I agree with you in passing the version as a parameter, as

 @RequestMapping(method = RequestMethod.POST, value = "/api/{version-var}/getData") 

But I don’t think it’s a good idea to add many branches. We need to extract all the methods in the resource class into the business interface, for example

 private IDataRetrieve dataRetriever; @RequestMapping(method = RequestMethod.POST, value = "/api/{version-var}/getData") public @ResponseBody ResponseDataDTO createReleaseFromTemplate(@PathVariable("version-var") Integer version, @RequestBody OperationsDetailsTDO details) { dataRetiever = DataRetrieverFactory.getDataTrieverByVersion(version); //TODO, create a factory to get DataRetriever return dataRetiever.getData(); } 

And then you need two classes to implement IDataRetriver (one for V1, the other for v2); reasons to avoid code duplication, you can add an abstract class for V1 and V2 and use Template Patern to remove duplicate code.

+1
source

You can use regular expressions in your RequestMapping if you use the path variable for the version ( see here, for example, ). Or you can create a new method that just calls the old one but has a new RequestMapping for v2. Or create a generic method that captures the version and calls the correct method that actually processes this version of the request. Bonus for the last method: you can grab the version and send a specific error to the user if the version they are sending is not supported, for example, if they send / app / v10 / whatever.

0
source

Source: https://habr.com/ru/post/945589/


All Articles