Best way how to describe "ModelAttribute" with Swagger - spring

I am trying to integrate Swagger2 to my Spring Boot based application. The issue is that swagger does not consider model attributes.
#GetMapping(value = "/events", produces = MediaType.APPLICATION_JSON_VALUE)
public PagedResources<EventResource> getEvents(
#Valid SearchCriteria searchQuery,
BindingResult result,
PageableResourcesAssembler<EventResource> assembler){
// code
}
As you can see SearchCriteria is a class which gets automatically binded by Spring.
public class SearchCriteria {
private List<EventType> eventTypes;
private LocalDateTime from;
// getters setters
}
But what swagger generates is following:
which is not expected. The desired result might be generated by annotation getEvents method by
#ApiImplicitParams({
#ApiImplicitParam(name = "eventTypes", paramType = "query"),
#ApiImplicitParam(name = "from", paramType = "query")
})
PagedResources<EventResource> getEvents(#ApiParam(hidden = true ) #Valid SearchCriteria searchQuery
but the #ApiParam(hidden = true ) does not work, because in the Swagger UI is the searchQuery parameter still present.
What is the proper way how to describe request parameters contained in a POJO using swagger? To me the best way would by annotation SearchCriteria class with #ApiModel but it does not work.

This bug was fixed in Springfox v2.7.0.
Original Answer:
The #Valid-annotation actually does that the param will be seen as body-param.
As this shouldn't do this I've opened an issue on the springfox github page.
but the #ApiParam(hidden = true ) does not work
Springfox provides for that the springfox.documentation.annotations.ApiIgnore-annotation which should work.
Like written in this issue using the annotation from springfox is the right way.

Related

Populate query parameters from DTO

Is there a way to let Spring populate RestTemplate query parameters automatically from a DTO, similarly to how it instantiates the response DTO automatically?
I wish to write something like:
RequestDto request = new RequestDto();
request.setFoo("foo");
request.setBar("bar");
ResponseDto response = restTemplate.getForObject(
"http://example.com/api",
ResponseDto.class,
request
);
Instead of:
ResponseDto response = restTemplate.getForObject(
"http://example.com/api?foo={foo}&bar={bar}",
ResponseDto.class,
"foo",
"bar"
);
Because there are many large DTOs, requiring tons of boilerplate code, which must be kept in sync with any DTO changes.
Spring 4.3.25
I don't think that is directly possible. The following is not exactly using the DTO, but it does let you build the request without having to form the URL string manually. You can use Spring's UriComponentsBuilder class.
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://example.com/api")
.queryParam("foo", "bar")
// etc. ...
.queryParam("bar", "foo");
String result = restTemplate.getForObject(builder.toString(), String.class);
You could loop over the DTO and build the query as above. Or without the DTO, you could use a Map<String, String> and loop over it.
Map<String, String> params = new HashMap<>();
params.put("foo", "bar");
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl("http://example.com/api");
for (Map.Entry<String, String> entry : params.entrySet()) {
builder.queryParam(entry.getKey(), entry.getValue());
}
String result = restTemplate.getForObject(builder.toString(), String.class);
Edit:
As crizzis suggested below, you can use Spring Cloud OpenFeign's REST Client (from Feign #QueryMap support):
The OpenFeign #QueryMap annotation provides support for POJOs to be used as GET parameter maps. Unfortunately, the default OpenFeign QueryMap annotation is incompatible with Spring because it lacks a value property.
and
Spring Cloud OpenFeign provides an equivalent #SpringQueryMap annotation, which is used to annotate a POJO or Map parameter as a query parameter map.
From your question's example:
public class RequestDto {
private string foo;
private string bar;
}
#FeignClient(name = "client", url = "http://example.com")
public interface FooTemplate {
#GetMapping(path = "/api")
String endpoint(#SpringQueryMap RequestDto requestDto);
}
You can do something like this-
UriComponentsBuilder builder = UriComponentsBuilder.fromUriString("http://example.com/api")
.queryParam("foo", "foo")
.queryParam("bar", "bar");
ResponseDto response = restTemplate.getForObject(
builder.buildAndExpand(builder).toUriString(),
ResponseDto.class);
A more detailed answer can be found here- RestTemplate: How to send URL and query parameters together
How about using Feign? It allows you to describe the remote endpoint just like a Spring Controller. This includes support for query parameter DTOs.
See an example here

Spring RESTful application - POST method request body mandatory attributes

I am building a RESTful app in Spring Boot and i want to make few attributes in my POST method's request body mandatory.
In swagger yaml, i mark them as required "true", but when i generate the classes using swagger editor, i dont see that impacting in any way, i.e i can't see even a #NotNull annotation or anything of that sort.
How do i mark them as mandatory in my java model class ? Is #NotNull the way to go?
If yes, should i do that in my request body class, or in the jpa document class or both ?
Thanks !
Yes, #NotNull is a way to go.
But also You need to use #Valid annotation.
check example:
#RequestMapping(value = "/appointments", method = RequestMethod.POST)
public String add(#Valid AppointmentForm form, BindingResult result) {
....
}
static class AppointmentForm {
#NotNull
private Date date;
}

how to map two same URLs with different params in springfox with springboot rest controller?

Below are the 2 RequestMapping handler methods in my rest controller with the same value but different param.
#ApiOperation(value = "Query with name", nickname = "queryWithNameParam")
#RequestMapping(value = "/query", params = "name",
method = RequestMethod.GET)
public void queryWithNameParam()
#ApiOperation(value = "Query with code", nickname = "queryWithCodeParam")
#RequestMapping(value = "/query", params = "code",
method = RequestMethod.GET)
public void queryWithCodeParam()
I am able to invoke both the methods using resttemplate, but the API is not being shown on the browser when accessing swagger-ui.html
I am using springboot 2.0.3.RELEASE and springfox 2.9.2
Now there is only one option to fix this:
Add springfox-swagger-ui-rfc6570 instead of springfox-swagger-ui as a dependency.
Set enableUrlTemplating(true) in your docket configuration.
Source:
http://springfox.github.io/springfox/docs/current/#springfox-rfc6570-support-strong-incubating-strong
Open issues in springfox Github project:
https://github.com/springfox/springfox/issues/2354
https://github.com/springfox/springfox/issues/2042
Closed issues:
https://github.com/springfox/springfox/issues/2541
https://github.com/springfox/springfox/issues/1874

Spring fox swagger ui version 2.8.0 Example Value

I am using springfox-swagger2 and springfox-swagger-ui version 2.8.0 which was not exists in previous version 2.5.0. I am seeing in this version there is an Example Value added in the request however, the example shows default as application/xml as default .
#RequestMapping(value = "/",
produces = {"application/xml","application/json"},
consumes = {"application/xml", "application/json"}, method = RequestMethod.POST)
public ResponseEntity<?> addEmp(
#ApiParam(name = "request", value = "Payment Adding a new Employee Payload", required = true)
#Valid #RequestBody Employee request)
This Example Value is getting derived from the the Object Employee and converting to either xml, json etc. My question is, is there any way the default value for Example Value can be defined in the drop down of from the multiple consuming object types defined in #RequestMapping'sconsumes` array.
Screenshot
To fix this issue set the validatorUrl(String str) as empty string in the UiConfiguration configuration bean, passing null wouldn't work. Hope this help whomever referring this thread in future.
#Bean
public UiConfiguration uiConfig() {
return UiConfigurationBuilder.builder()
.
.
.validatorUrl(StringUtils.EMPTY)
.build();
}

Customizing Request Header description in Swagger UI using Springfox-Swagger2

I am using Springfox Swagger2 version 2.4.0, Springfox Swagger UI version 2.4.0 and Swagger Annotations version 1.5.0 in my Spring Boot application.
The question here is, I am able to generate swagger UI for my controller's API and I am able to test the same. But I am not able to specify request header description for my request header. I m using #RequestHeader annotation for the same.
The code snippet in my controller API is follows:
#RequestHeader(name = "Api-Key") String apiKey
The Swagger UI for the request header is as follows:
The highlighted rectangular area in the image represents the description of the request header.
Currently it just picks up the data mentioned in the name attribute and shows it. But i wanna give a different description for the same. i.e. "Value of license key"
How can i achieve this in Swagger UI as #RequestHeader annotation only have value, defaultValue, name and required attributes? Any help would be really appreciated.
Update: Looking for a solution out of the box without any custom annotation of my own
Maybe my answer will help somebody.
As mentioned Dilip Krishnan in his answer you could use io.swagger.annotations.ApiParam or io.swagger.annotations.ApiImplicitParam Swagger annotations for fine-tuned custom documentation.
#ApiParam could be used for registered method parameters.
#ApiImplicitParam could be used if API parameter wasn't registered explicitly.
#RestController
#RequestMapping(value = "/v1/test", produces = "application/json")
#Api(value = "/v1/test")
public class TestController {
#ApiOperation(value = "Do Something method", tags = "Test method")
#RequestMapping(value = "/doSomeThing", method = RequestMethod.GET)
public Foo doSomeThing(
#ApiParam(value = "Param1 Description", required = true)
#RequestParam String param) {
throw new UnsupportedOperationException("do Some Things");
}
#ApiOperation(value = "Do Something Another method", tags = "Test method")
#ApiImplicitParams({
#ApiImplicitParam(name = "anotherParam1", value = "Another Param1 Description", paramType = "header"),
#ApiImplicitParam(name = "anotherParam1", value = "Another Param1 Description", paramType = "header")
})
#RequestMapping(value = "/doSomeThingAnother", method = RequestMethod.GET)
public Foo doSomeThingAnother(Bar bar) {
throw new UnsupportedOperationException("do Some Thing Another");
}
}
And in the end you could see following picture
TL;DR is that you would have to build your own plugin to do it.
Basically the only out-of-the-box annotations to augment the description in this case are #ApiParam and to be more accurate #ApiImplicitParam. Unfortunately neither of those annotations support descriptions.
So my suggestion would be to:
Create your own annotation that would look like this
#RequestHeader(name = "Api-Key")
#Description("Value of license key") String apiKey
NOTE: There is already an annotation in spring that is suitable for this.
Create your own ParameterBuilderPlugin
Implement the plugin as shown below
public class Test implements ParameterBuilderPlugin {
#Override
public void apply(ParameterContext parameterContext) {
ResolvedMethodParameter methodParameter =parameterContext.resolvedMethodParameter();
Optional<Description> requestParam = methodParameter.findAnnotation(Description.class);
if (requestParam.isPresent()) {
parameterContext.parameterBuilder()
.description(requestParam.get().value());
}
}
#Override
public boolean supports(DocumentationType documentationType) {
return false;
}
}
Pick a value of the order that is is applied after swagger annotations have been processed.
Also please upgrade your springfox library to the latest version.
We had the same issue, and resolved the problem in the following way:
.. #RequestHeader(value = "..") #ApiParam(value = "Description") String param ..
The idea is to add "description" field into generated swagger. It could look hacky, but it's a quick simple solution which can be useful in your personal case.
Quick, easy valid solution is to use an enum, for example:
#RequestHeader(value = "someval") ALLOWED_VALUES input
private enum ALLOWED_VALUES {A, B, C};
The following will show in swagger:
Available values : A, B, C

Resources