Is it possible to use #Parameter in a REST controller? - java

I'm trying to use #Parameter for a path parameter in a #RestController, but it ignores the parameter.
Note: All works well if I use #PathVariable instead (commented). However, #PathVariable does not produce the OpenAPI yaml file with all properties like "description", "references", etc, that the springdoc-openapi-maven-plugin produces automatically.
Is it possible to use #Parameter in a REST controller?
Here's my code:
#RequestMapping("/channels")
#RestController
public class ChannelRESTController {
#PostMapping("{channelId}/connect")
#Operation(summary = "Initiates a session to a channel", tags = { "session" })
#ResponseBody
ResponseEntity<?> connect( //
#Parameter(name = "channelId", in = ParameterIn.PATH,
required = true, description = "The channel id") String channelId,
// #PathVariable(required = true) String channelId,
#Parameter(description = "Credentials' username") String username,
#Parameter(description = "Credentials' password") String password
) {
System.out.println(
"Starting channel #" + channelId); // displays null :(
return ...
}

In order to automate the OpenAPI YAML file generation it's possible to add both annotations to the parameters.
In short, the parameter channelId above can be annotated as:
#PathVariable(required = true)
#Parameter(name = "channelId", in = ParameterIn.PATH,
required = true, description = "The channel id")
String channelId,
In this case:
the first annotation #PathVariable allows Spring to retrieve the parameter from the URL.
the second annnotation #Parameter produces the correct description in OpenAPI (YAML) file generated by the springdoc-openapi-maven-plugin plugin.
This solution is not ideal, but does the trick. I wish in the future the plugin will recognize the second one by itself, to avoid typing them both.

Related

Incomplete Swagger documentation for SpringBoot endpoint with MultipartFile parameter

I am using Swagger with SprintBoot to generate the endpoints documentation, it is working great with one exception: I have a POST endpoint with a MultipartFile parameter. In this case Swagger generates the documentation but not the Example Value (it is empty).
public String create(#ApiParam(value = "Record to be created", required = true, type = "json", format = "json")
#RequestPart(name = "candidate") MyDto record,
#ApiParam(value = "File associated to the record", required = false)
#RequestPart(value = "file", required = false) MultipartFile file) throws Exception
Without the MultipartFile the Example Value shows the JSON example which can be used. I would like to have the same when an additional (optional) MultipartFile parameter is included.
Can this be addressed somehow?
as i know swagger docs can be placed when adding annotations something like this:
#ApiModel(value="MyFile")
public class MyFile{
#ApiModelProperty(value = "originalFileName", example="The original filename")
private String getOriginalFilename;
[...]
}
I would suggest to extend the MultipartFile Object and add this Annotations. So you can add documentation to the params and your optional params too.
P.S. MultipartFile is an Interface so you have to extend one of the Implementations e.g. CommonsMultipartFile. Than you have to include the org.apache.commons.fileupload dependency to your project (for FileItem).

Swagger #ApiParam annotation makes parameter annotated with #PathVariable non-required in Swagger UI

I have the following code, that is the art of the API of my
import org.springframework.web.bind.annotation.PathVariable;
import io.swagger.annotations.*;
#GetMapping(value = "/{userId}")
public String getUserHistory(ApiParam(value = "The user id")
#PathVariable("userId") Integer userId, Model model) throws NotFoundException {
// fetch user info
model.addAttribute("userInfo", userInfo);
return "userHistory";
}
If I have the #ApiParam annotation, the #PathVariable becomes non-required, so if I do not enter the userId and make the request through Swagger UI, the request still goes to the server, which causes unneeded server errors. The parameter "required" of #PathVariable is true by default (so, the default is #PathVariable(name="userId", required = true)) and works fine without #ApiParam on that very parameter. These annotations should not change each other's behaviour, as far as I am concerned. Is that a Swagger bug or just a misuse?
The parameter "required" of #ApiParam is false by default so you just have to change that to true for it to be required through the Swagger UI.
#ApiParam(value = "The user id", required = true) #PathVariable("userId") Integer userId

Can we use swagger annotation values in our java code

I am new to java. Trying to develop a application to schedule http api calls in a cron job. Only the method name will be the input. All the apis are configured with swagger annotations. Can I use these annotations to determine whether the api is post or get or delete etc. For example
public class ABC {
#ApiOperation(
httpMethod = "GET",
value = "value",
notes = "notes",
response = ABC.class)
ABC getValue()
{
}
}
only getValue is the input to my application. Can I get the #ApiOperation values to determine the http method type.
You can, but it is in the RequestMapping annotation (the one where you specify which URL should be linked to the method):
For example, this method will be called when someone navigates to myBaseURl/persons in GET. It will return JSON.
#ApiOperation( value = "List of persons",
notes = "List all my base's persons. ",
response = Person.class,
responseContainer = "List",
tags = { "Persons", })
#RequestMapping(value = "/persons",
produces = { "application/json" },
method = RequestMethod.GET)
public PagedResources<PersonResource> persons(...) {}

How to Swagger Annotate a Spring GET #RequestMapping having a complex Object

The issue is that I have a complex Object as Request Param for a GET-Request and after I place the Swagger Annotations inside the Object. The Swagger UI shows that the entry param is a body in which i have to place the Params.
body: {
"modelId": 0,
"makeId": 0
}
My REST controller looks like this
#RequestMapping(method = RequestMethod.GET, value = "/model")
public SearchModelsResponse searchModels(
#ApiParam(value = "Search for something",
required = true) final ModelSearch search) {...}
And the Request object
public class ModelSearch {
#ApiParam(value = "Something important)", required = true)
private Long modelId;
#ApiParam(value = "Something else important)", required = false)
#Nullable
private Long makeId;
....
}
Is there a Way to Annotate it correctly so Swagger shows it as correctly as Request Parameters and not as a body construct ?
OK the solution in this kind of scenario is to manually define the Parameters, this is possible with the #ApiImplicitParam annotation.
So as result this looks like this.
#ApiImplicitParams({
#ApiImplicitParam(name = "modelId", value = "this is modelId", required = true, dataType = "string", paramType = "query"),
#ApiImplicitParam(name = "makeId", value = "this is makeId", required = true, dataType = "string", paramType = "query")
})
#RequestMapping(method = RequestMethod.GET, value = "/model")
public SearchModelsResponse searchModels(
final ModelSearch search) {...}
It's not a beautifull solution since I actually want swagger to interprete my code but the result gives the option to show it as request parameters not as a body construct.

Multiple route with the same pattern url

I m actually creating a simple application and I need to have routing pattern identical in multiple case :
/*
* Returns a list of all the root directories accepting query string on name
*/
#RequestMapping(value = "/directories", method = RequestMethod.GET)
public List<DirectoryEntity> find() {
return directoryService.findAll();
}
/*
* Returns a list of all the root directories accepting query string on name
* #param name Name of the ressources to search. Query string at format : *name*
*/
#RequestMapping(value = "/directories", method = RequestMethod.GET)
public List<DirectoryEntity> findByCriteria(#RequestParam(value = "name", required = true) String name) {
return directoryService.findByName(name);
}
In fact, I dont want to manage criteria request in the same function as findAll one. Is there anyway to handle this case without be forced to manage everything inside the same function ?
Thanks for advance
Try changing the second method #RequestMapping annotation adding params:
#RequestMapping(value = "/directories", method = RequestMethod.GET, params = "name")
public List<DirectoryEntity> findByCriteria(#RequestParam(value = "name", required = true) String name) {
return directoryService.findByName(name);
}
See also the Spring Documentation for more details.
I'm not quite sure what you are asking, but assuming the decision as to which method to call is based on request parameters (it must be since they're both the same URL and HTTP method), then something like this might help:
#RequestMapping(method=RequestMethod.GET, params={"name"})
public #ResponseBody List<DirectoryEntity> findByCriteria(#RequestParam(value = "name", required = true) String name) {
//do your stuff
}
The inclusion of the params attribute in the #RequestMapping annotation removes the ambiguity in which method to call.
I've also added #ResponseBody to the return type, just in case you want Spring to return the list in the HTTP response.

Categories

Resources