I have a method signature for a rest method in a Spring-Boot RestController that looks like this:
#RequestMapping(
value = "/path",
method = RequestMethod.POST,
consumes = MediaType.APPLICATION_JSON_VALUE,
produces = MediaType.APPLICATION_JSON_VALUE
)
#ApiImplicitParams({
#ApiImplicitParam(
name = "message",
value = "Message that is sent to the method",
required = true,
dataType = "string",
paramType = "body"
)
})
public #ResponseBody String receiveMessage(#RequestBody String message) {
// ...
return "{\"success\": true}";
}
I would like to provide a "sample" value for the message parameter that is a JSON string (e.g. {"key" : "value"}). Does anybody know how I can do this using Swagger annotations? I tried
#ApiImplicitParams({
#ApiImplicitParam(
// ...
example = "...JSON value..."
)
})
but it didn't work. What I would like to have is a "sample value" in the documentation, that the reader can click on to have the parameter value field in the documentation filled with the given sample value. Is this possible?
Here is a screenshot of how it might look like:
Just to prevent "useless" answers: I cannot change the type of the parameter from String to some class type due to my business logic.
Unfortunately you cannot provide an sample or example value for atomic parametera (String, Number, ...).
You can only provide an example if the parameter is an object with a schema, you only have to add an example property to the property description:
properties:
firstName:
description: first name
type: string
example: John
As a last resort you could add an example value in the parameter's description (value in the ApiImplicitParam annotation).
#ApiImplicitParam(
name = "message",
value = "Message that is sent to the method. Example: value",
required = true,
dataType = "string",
paramType = "body"
)
For Spring Boot users, assuming you've a REST method, accepting json body, but for some reasons doesn't explicitly uses #RequestBody. Follow below steps to generate proper Swagger documentation
Update SpringFox configuration bean for additional model
#Bean
public Docket apiDocket() {
return new Docket(DocumentationType.SWAGGER_2)
// ...
.additionalModels(new TypeResolver().resolve(YourRequestModel.class));
}
Update controller API for #ApiImplicitParams
#PostMapping("/your-api")
#ApiOperation(value = "brief description", notes = "Greater details come here")
#ApiImplicitParams({
#ApiImplicitParam(paramType = "header", name = "x-locale", example = "en"),
#ApiImplicitParam(paramType = "body", dataType = "YourRequestModel")
})
public YourResponsetModel processRequest() {
// ...
return null;
}
This will generate us Swagger with an optional header x-locale, and body of type YourRequestModel.
You can try this:
public MyObject myController(#ApiParam(example = "examplestring") #RequestParam("name") String name,
#ApiParam(example = "1")#RequestParam("eventNo") int eventNo, #ApiParam(example = "2")#RequestParam("halRequestNo") int halRequestNo){
Related
I have an API endpoint that get a name and description parameters (both are mandatory)
createSomething(#RequestParam(value = "name") String name,#RequestParam(value = "description") String description)
If the client is not providing any of these he will get 400 Bad Request
Is there a way for me to tell the client which field is missing ? give more information for the "Bad Request" response
Update: Note that the parameters must be mandatory since I want that OpenAPI will detect that these parameters are mandatory. So solutions like making then "optional" and checking inside the body of the function is not what I am looking for
I see multiple answers but no one is specific enough.
1)
Spring by default has the capability of reporting in the error message what parameter was missing or other violations in the request.
However since spring boot version 2.3 the specific error messages are hidden, so that no sensitive information can be disclosed to the user.
You can use the property server.error.include-message: always which was the default mechanism before 2.3 version and allow spring to write error messages for you again.
2)
If you can't afford this because other sensitive info could be leaked from other exceptions, then you have to provide your own exception handler for this specific case
The following can be placed either in the same controller, or in another class marked with #ControllerAdvice
#ExceptionHandler(MissingServletRequestParameterException.class)
public ResponseEntity handleMissingParams(MissingServletRequestParameterException ex) {
return ResponseEntity.badRequest().body(String.format("Missing parameter with name:%s", ex.getParameterName()));
}
As #Shubam said, you can use the defaultValue attribute of #RequestParam annotation by setting the required attribute to true since both the parameters are mandatory.
Here is an example of how you could do it,
private final String DEFAULT_NAME = "Default Name";
private final String DEFAULT_DESC = "Default Desc";
#RequestMapping(value = "/get", method = RequestMethod.GET)
#ResponseStatus(HttpStatus.OK)
public ResponseEntity<String> createSomething(#RequestParam(required = true, name = "name", defaultValue = "Default Name") String name,
#RequestParam(required = true, name = "description", defaultValue = "Default Desc") String desc){
if(DEFAULT_NAME.equals(name)){
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Field Name is missing");
}
if(DEFAULT_DESC.equals(desc)){
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Field Desc is missing");
}
return ResponseEntity.ok(String.format("Hello, %s!",name));
}
You can use validation with a customised message :
#GetMapping("/name-for-month")
public String getNameOfMonthByNumber(#RequestParam #Min(1) #Max(value = 12, message = “month number has to be less than or equal to 12”) Integer month) {
// ...
}
There are many ways of handling errors for Rest find below a link of at least 5 solutions for your issue :
ExceptionHandler
HandlerExceptionResolver (ResponseStatusExceptionResolver this is the most adducate for your case or the 4th one if you use spring 5+)
ControllerAdvice
ResponseStatusException
Handle the Access Denied in Spring Security
https://www.baeldung.com/exception-handling-for-rest-with-spring
Since both parameters are mandatory you'll be getting 400 (bad request) if you try to send the request without paramters.
A workaround could be making request parameters non-mandatory(so that request can be sent without parameters) and provide a default value in case no parameter is provided
createSomething(#RequestParam(value = "name", required=false, defaultValue = null) String name,#RequestParam(value = "description", required=false, defaultValue = null) String description)
In the function, you can check for null like the following -
if (name == null) // name parameter is not provided
if (description == null) // description paramter is not provided
And, based on conditions you can also send error reponse if any one/more paramter not provided in the request.
I'm using swagger with spring boot in my project, and there are some API's that I need to use annotations for change some descriptions, parameters names, ou insert examples.
For do it, I need to change my controller, and insert some annotations, for example:
#ApiOperation(value = "Returns a person list")
#ApiImplicitParams({
#ApiImplicitParam(name = "Authorization", value = "Access Token", required = true, allowEmptyValue = false, paramType = "header", dataTypeClass = String.class, example = "Bearer access_token"),
#ApiImplicitParam(name = "X-Custom-Header", value = "A Custom Header", required = true, allowEmptyValue = false, paramType = "header", dataTypeClass = String.class, example = "my header example")
})
#RequestMapping(value = "/person", method = RequestMethod.GET, produces="application/json")
public List<Pessoa> get() {
return personRepository.findAll();
}
But in some cases, it make my Controller class with a lot of information just because swagger, my question is: There is a way instead of use annotations in my Controller class, use a properties file, or another Class just with the Swagger annotations, something like:
myController.myMethod.apiOperation=Returns a person list
I knew that i can insert only the value property in the file, but i would like to not use any annotation related to swagger/OpenApi in my controller.
I have a #RestController with such method
#RestController
public MyController {
#Operation(summary = "Some text", description = "Some text again"
#GetMapping("/route")
public MyClassResponse getSomething(
#Parameter(name = "My request", description = "My request") MyRequest request
) {
// to do smth
return response
}
where MyRequest is
public class MyRequest {
private int param1;
private String param2;
private MyClass param3;
}
and MyClass looks like
public class MyClass {
private int clazzParam1;
private int clazzParam2;
}
First of all, Swagger shows parameter MyRequest like body
{
"param1" : 0;
"param2" : "string",
"param3" : {
"clazzParam1" : 0,
"clazzParam2" : 0
}
}
but I would like to see every parameterlike this
Second when I try make request, I get this curl
http://localhost:8080/route?param1=0¶m2=string¶m3=clazzParam1,0,clazzParam2,0
instead
http://localhost:8080/route?param1=0¶m2=string¶m3.clazzParam1=0¶m3.clazzParam2=0
Therefore response contain next failure
Failed to convert property value of type 'java.lang.String' to required type 'MyClass' for property 'param3'.
How should I use annotations to get what I want?
For various reasons I can't use .yaml description. Thank you.
#ParameterObject is answer. It unpacking object to parameters in Swagger UI
I have created one rest API in spring-boot, the problem is that I am taking 4 parameters as a requestbody argument as a JSON object.
Now if I pass the JSON object with 5 parameters than my API still call, no assertion exception occurs while serializing the JSON object.
I have one dto class as below with constructor
public class testDto{
#NotNull(message = "fistName can not be null.")
private String fistName;
#NotNull(message = "lastName can not be null.")
private String lastName;
private String nickName;
public testDto() {
}
public testDto(#NotNull(message = "fistName can not be null.") final String fistName ,#NotNull(message = "lastName can not be null.") final String lastName , final String nickName){
super();
this.fistName = fistName;
this.lastName = lastName;
this.nickName = nickName;
}
}
My restapi as below,
#PostMapping(path ={ "/api/v1/user"}, produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> saveUser(
#Valid #RequestBody(required = true) final testDto dto) throws Exception {
}
Now while calling my API I am passing request body as below
{
"fistName" : "abc",
"lastName" : "xyz",
"nickName" : "pqr",
"age" : 25
}
Now here when I pass age parameter and call the API, my API still working instead of throwing an exception for No any constructor found as I have passed age which is not a member of my dto class.
Expected result: don't allow to call API
Actual result: Allow me to call API
I have also tried with assertion exception declaration and binding exception but not getting any success.
also set the property
spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false
Spring Boot uses Jackson to map the JSON payload to an instance of your testDto class. By default, Jackson is configured to ignore entries in the JSON that it cannot map to the DTO. This follows the robustness principle or Postel's law as it's also known.
You can configure Jackson to fail when it cannot map an entry in the JSON to a property on a DTO by adding the following line to your application's application.properties file in src/main/resources:
spring.jackson.deserialization.fail-on-unknown-properties=true
What to do when the request is invalid json but the values are correct ex:
{
"fistName" : "abc",
"lastName" : "xyz",
"nickName" : "pqr",
"nickName" : "pqrs"
}
Now in this case it is taking the last one and mapping it
I have spring rest controller and i want it documented via swagger. It looks like this:
#ApiOperation(value = "Returns comments list")
#RequestMapping(method = RequestMethod.GET)
public CollectionResponse<CommentDTO> getComments(CommentFilterDTO filterDTO) {
Page<CommentEntity> requisitionComments = commentService.getComments(filterDTO);
return Convert.convert(requisitionComments, COMMENT_ENTITY_2_COMMENT_DTO);
}
CommentsFilterDTO is
public class CommentFilterDTO {
private Long requisitionId;//get, set
private CommentType commentType;//get, set
// etc
}
This controller takes query string with pageable and filterDTO params like this:
my/comments?requisitionId=1&commentType=COMMENT
Now i'm trying to document it via swagger and i want all possible query parameters documented as well, but if i leave it like this i see only
I can document query params via #ApiImplicitParams like
#ApiImplicitParams({
#ApiImplicitParam(name = "requisitionId", value = "Requisition id", required = true, dataType = "long", paramType = "query"),
...
})
Is there any way to tell swagger what all CommentFilterDTO fields can be used as query parameters?