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

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.

Related

#ApiImplicitParams ... #Example(value) is ignored

I am trying to provide custom JSON example to the body of my request.
I am writing
#ApiImplicitParams({
#ApiImplicitParam(
paramType = "body",
//dataType = "com. ... .MyClass",
dataType = "java.lang.String",
name="payload",
examples = #Example(value = {
#ExampleProperty(value = "[\"haha\"]", mediaType = MediaType.APPLICATION_JSON_VALUE)
})
)
})
public OperationResponse createEntity(#RequestBody MyClass payload ...
If #ApiImplicitParams annotation is absent, Swagger draws deserialization of MyClass which is incorrect. I am trying to provide predefined example (haha string). When I am adding #ApiImplicitParams only
string
appears in the body, hot haha.
Why and how to fix?

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

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.

How to solve org.springframework.web.bind.MissingServletRequestParameterException in Spring MVC when I sunmit a json string that is larger than 1M?

I use Spring MVC #RequestParam to accept a form.
I am sumbit a form that contains a json string, and when the json string is larger than 1M , It is
{
"timestamp":1556663224346,
"status":400,
"error":"Bad Request",
"exception":"org.springframework.web.bind.MissingServletRequestParameterException",
"message":"Required String parameter 'corpId' is not present",
"path":"/api/test"
}
#RequestMapping(value = "/test", method = RequestMethod.POST, produces = { "application/json;charset=UTF-8" })
#ResponseBody
public String test(
#ApiParam(required = true, value = "json string") #RequestParam(required = true) String content)
I think it is because of the HttpMessageConvert can not convert it or it is has a limit for Json Serializing.
You exceed the default http-header-size(8kb), you could configure your server.max-http-header-size with a suitable number

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(...) {}

Pass multiple parameters to rest API - Spring

I am trying to figure out if it is possible to pass a JSON object to rest API, Or pass a multiple parameters to that API ? And how to read these parameters in Spring ? Lets assume that the url looks like the below examples :
Ex.1 http://localhost:8080/api/v1/mno/objectKey?id=1&name=saif
Is it valid to pass a JSON object like in the url below ?
Ex.2 http://localhost:8080/api/v1/mno/objectKey/{"id":1, "name":"Saif"}
Questions:
1) Is it possible to pass a JSON object to the url like in Ex.2?
2) How can we pass and parse the parameters in Ex.1?
I tried to write some methods to achieve my goal, but could not find the right solution?
I tried to pass JSON object as #RequestParam
http://localhost:8080/api/v1/mno/objectKey?id=1 There was an unexpected error (type=Unsupported Media Type, status=415). Content type 'null' not supported
http://localhost:8080/api/v1/mno/objectKey/id=1 There was an unexpected error (type=Not Found, status=404). No message available
http://localhost:8080/api/v1/mno/objectKey/%7B%22id%22:1%7D There was an unexpected error (type=Not Found, status=404). No message available
#RequestMapping(value="mno/{objectKey}",
method = RequestMethod.GET,
consumes="application/json")
public List<Book> getBook4(#RequestParam ObjectKey objectKey) {
...
}
I tried to pass the JSON object as #PathVariable
#RequestMapping(value="ghi/{objectKey}",method = RequestMethod.GET)
public List<Book> getBook2(#PathVariable ObjectKey objectKey) {
...
}
I created this object to hold the id parameter and other parameters like name , etc ....
class ObjectKey{
long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
}
(1) Is it possible to pass a JSON object to the url like in Ex.2?
No, because http://localhost:8080/api/v1/mno/objectKey/{"id":1, "name":"Saif"} is not a valid URL.
If you want to do it the RESTful way, use http://localhost:8080/api/v1/mno/objectKey/1/Saif, and defined your method like this:
#RequestMapping(path = "/mno/objectKey/{id}/{name}", method = RequestMethod.GET)
public Book getBook(#PathVariable int id, #PathVariable String name) {
// code here
}
(2) How can we pass and parse the parameters in Ex.1?
Just add two request parameters, and give the correct path.
#RequestMapping(path = "/mno/objectKey", method = RequestMethod.GET)
public Book getBook(#RequestParam int id, #RequestParam String name) {
// code here
}
UPDATE (from comment)
What if we have a complicated parameter structure ?
"A": [ {
"B": 37181,
"timestamp": 1160100436,
"categories": [ {
"categoryID": 2653,
"timestamp": 1158555774
}, {
"categoryID": 4453,
"timestamp": 1158555774
} ]
} ]
Send that as a POST with the JSON data in the request body, not in the URL, and specify a content type of application/json.
#RequestMapping(path = "/mno/objectKey", method = RequestMethod.POST, consumes = "application/json")
public Book getBook(#RequestBody ObjectKey objectKey) {
// code here
}
you can pass multiple params in url like
http://localhost:2000/custom?brand=dell&limit=20&price=20000&sort=asc
and in order to get this query fields , you can use map like
#RequestMapping(method = RequestMethod.GET, value = "/custom")
public String controllerMethod(#RequestParam Map<String, String> customQuery) {
System.out.println("customQuery = brand " + customQuery.containsKey("brand"));
System.out.println("customQuery = limit " + customQuery.containsKey("limit"));
System.out.println("customQuery = price " + customQuery.containsKey("price"));
System.out.println("customQuery = other " + customQuery.containsKey("other"));
System.out.println("customQuery = sort " + customQuery.containsKey("sort"));
return customQuery.toString();
}
Multiple parameters can be given like below,
#RequestMapping(value = "/mno/{objectKey}", method = RequestMethod.GET, produces = "application/json")
public List<String> getBook(HttpServletRequest httpServletRequest, #PathVariable(name = "objectKey") String objectKey
, #RequestParam(value = "id", defaultValue = "false")String id,#RequestParam(value = "name", defaultValue = "false") String name) throws Exception {
//logic
}
Yes its possible to pass JSON object in URL
queryString = "{\"left\":\"" + params.get("left") + "}";
httpRestTemplate.exchange(
Endpoint + "/A/B?query={queryString}",
HttpMethod.GET, entity, z.class, queryString);

Categories

Resources