Using #RequestParam annotated method with swagger ui - spring-boot

I am using Springfox libraries to generate documentation for REST service and display it in Swagger UI. I followed the directions in Springfox documentation.
I have one controller, which uses parameters from query string and the method is mapped as following:
#ApiOperation(value = "")
#RequestMapping(method = GET, value = "/customcollection/{id}/data")
public Iterable<CustomeType> getData(#ApiParam(value = "The identifier of the time series.")
#PathVariable String id,
#ApiParam(name = "startDate", value = "start date", defaultValue = "")
#RequestParam("startDate") String startDate,
#ApiParam(name = "endDate", value = "end date", defaultValue = "")
#RequestParam("endDate") String endDate)
The resulting mapper in swagger-ui then displayed as:
GET /customcollection/{id}/data{?startDate,endDate}
Parameters are displayed correctly in the UI:
But when I click on Try it Out, the request URL is misformed:
http://localhost:8080/customcollection/1/data{?startDate,endDate}?startDate=1&endDate=2
How can it be fixed?

This was caused by the line
enableUrlTemplating(true)
in Docket configuration which I copied from example and forgot to remove.
After removing this line everything is working as expected.

Related

OpenApi not picking up 'example' from #Schema

In my request model, I have a field like
#NotNull
#Schema(description = "blahblah", example = "19680228", type = "Date", format = "String", pattern = "([0-9]{4})(?:[0-9]{2})([0-9]{2})", required = true, nullable = false)
#JsonDeserialize(using = CustomDateDeserializer.class)
private OffsetDateTime birthDate;
As you can see, I have example = "19680228" in #Schema.
When I go to https://editor.swagger.io/ and paste my .yaml file into it, I would expect that it would pick the example up and show the birthDate in example section of my endpoint and in my model schema as 19680228. I would else expect that example was generated in yaml when I hit the /api-docs.yaml endpoint but it is not:
Here is how it shows in my model:
And here is how Example value of my controller looks:
As you can see, the format is still getting the format for OffsetDateTime and there is no example at all.
However, if I modify yaml in https://editor.swagger.io/ and add example as below:
, then my schema model shows it
, and also example in controller shows it as 19680210:
So, it looks like OpenApi is not processing #Schema properly.
i had the same problem, and i didn't find proper solution for it, the only solution was using String type with pattern.
like this
#Schema(type = "String" , example = "2022-10-10 00:00:00", pattern = "yyyy-MM-dd HH:mm:ss").

#PathVariable of GetMapping in Spring throws an error when the input is #

I have made an autosuggest input field that automatically searches the database on every keypress. It works fine when i insert regular characters like letters and numbers but it gets spooky when you try start the search request with the character #. Doing that throws the error org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'long'; nested exception is java.lang.NumberFormatException: For input string: "get"
When i add some letters before the # (for example des#) it will throw an 404 page not found error and if i use the % character it will throw an 400 'unauthorized' error.
This strange behavior has probably something to do that i'm expecting a GetRequest instead of a PostRequest. If i turn it into a PostMapping i'm sure the errors will dissapear. But my question is; why is this happening? Does # have a special meaning? Why does spring seemingly try to convert # to a long value even though the pathvariable is typed as String? And why has the input string become "get" according to the error? I know that in an url # has a special meaning in that it signifies an href anchor but why should it be a special character for spring?
Heres the code of my getMapping
#GetMapping("/get/varietynames/{searchString}/{languageCode}")
public List<CropVarietyNameSelectionDTO> getCropVarietySelectionDTOBySearchString(#PathVariable("searchString") #NotBlank #Pattern(regexp = "^[A-Za-z0-9]+$", message = "Search input only allows for letters and numbers")
#Size(min = 1, max = 40, message = "Search input cannot exceed 40 characters") String searchString, #PathVariable("languageCode") String languageCode){
return seedService.getCropVarietySelectionDTOBySearchString(searchString,languageCode);
}
Edit
Request on the frontend side is:
private basePath:string = this.apiUrl + "/seed";
getCropVarietySelectionDTOBySearchString(searchString: string):Observable<CropVarietyNameSelectionDTO[]>{
return (searchString && (searchString.trim().length > 0)) ? this.http.post<CropVarietyNameSelectionDTO[]>(this.basePath + "/get/varietynames/" + this.languageService.getCodeOfPreferredLanguage(), searchString) : Observable.of([]);
}
this.apiUrl = localhost:4200
That is not the correct way or option to use #PathVariable annotation which indicates that a method parameter should be bound to a URI template variable. You need to use #RequestParam annotation which indicates that a method parameter should be bound to a web request parameter. You can see this answer that is a #RequestParam vs #PathVariable
#GetMapping("/get/varietynames")
public List<CropXXXDTO> getXXXXXhString(#RequestParam #NotBlank
#Pattern(regexp = "^xx+$", message = "xxxxx")
#Size(min = 1, max = 40, message = "xxxxx") String searchString,
#RequestParam(required = false, defaultValue = "EN") String languageCode){
return seedService.getXXXXtring(searchString, languageCode);
}
Then you can check the URL by following way:
/get/varietynames?searchString=XXXXX&languageCode=EN

Automatically adding #ImplicitParams with specific type of method argument of Spring Controller

Previously, I had Spring controller as below.
#RequestMapping(method = GET)
public List<TheResponse> getResponses(
#RequestParam(defaultValue = "1") int offset,
#RequestParam(defaultValue = "10") int limit) {
Pagination pagination = new Pagination(offset, limit);
...
return someResponse;
}
Swagger was generating document of this method with correct parameters information.
Later I created PaginationArgResolver by implementing HandlerMethodArgumentResolver. After that, I have to update the method as below, and apply #ApiImplicitParams to make it work with Swagger.
#ApiImplicitParams({
#ApiImplicitParam(name = "offset", dataType = "int", defaultValue = "1"),
#ApiImplicitParam(name = "limit", dataType = "int", defaultValue = "10")
})
#RequestMapping(method = GET)
public List<TheResponse> getResponses(#ApiIgnore Pagination pagination) {
...
}
Is there anyway #ImplicitParams is applied automatically whenever Pagination type argument is found?
OR
If I expose #PaginationSupported annotation, can I process it to achieve same results?
I am currently using springfox v2.4.0.
PS. I can edit source of Pagination class, in case some swagger annotation is needed there.
Why adding #ApiIgnore springfox will resolve these attributes inside the class automatically. When you want to add default values and other stuff you can add the #ApiParam annotation to the class attributes as well.
class Pagination {
#ApiParam(defaultValue = "1")
private int offset;
// [..]
}

How to give a swagger parameter default value?

I want somes params on swagger have its own default value. Is there anyway to give a default value ?
like this
this note has to be filled automatically with "stackoverflow"
You have to annotate your note parameter with defaultValue="stackoverflow".
You method signature should look like this:
public ResponseEntity<?> yourMethod(#ApiParam(value = "Default value for note", required = true, defaultValue = "stackoverflow") #Valid #RequestParam final String note) { }

Why am I getting "400 Bad Request" for this URL in Spring MVC?

The following URL results in a "400 Bad Request":
http://localhost:8080/springdata_web/rest/errors/test?from=2014-05-25T00:00:00.000Z&to=2014-05-27T00:00:00.000Z
The matching #RequestMapping is below. I can see I am definitely hitting this method because I see the Sysout line in the console using the following URL for example:
http://localhost:8080/springdata_web/rest/errors/test?from=&to=
So I guess it's to do with the Date type and Spring not accepting the format I'm passing in the request params but I don't see why.
#RequestMapping(value = "/test",
method = RequestMethod.GET,
produces = "application/json")
#ResponseBody
public Resource<List<ErrorsDTOEntity>> getAllErrors(
#RequestParam(value = "from", required = true) #DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Date from,
#RequestParam(value = "to", required = true) #DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) Date to) {
System.out.println("getAllErrors(Date, Date);");
List<ErrorsDTOEntity> services = errorsDAO.getAllErrors(from, to);
Resource<List<ErrorsDTOEntity>> toReturn = new Resource<List<ErrorsDTOEntity>>(services);
toReturn.add(linkTo(methodOn(ErrorsController.class).getAllErrors(from, to)).withSelfRel());
return toReturn;
}
It was the format of the date in the URL. This URL-encoded request works:
http://localhost:8080/springdata_web/rest/errors/test?from=2014-05-25T00%3A00%3A00.000%2B0000&to=2014-05-27T00%3A00%3A00.000%2B0000
The date pattern you are passing for ( from / to) is not matching. Underltying pattern for is DateTimeFormat.ISO DATE_TIME:
yyyy-MM-dd'T'hh:mm:ss.SSSZ
so example time is as below :
2000-10-31T01:30:00.000-05:00
try whether following request work:
test?from=2000-10-31T01:30:00.000-05:00&to=2000-10-31T01:30:00.000-05:00
Spring Docs says :

Resources