5

I have a controller with a @RequestBody DTO. I need to show the DTO's schema instead of the default string in the RequestBody Schema in Swagger.

By using @Operation above the API and @Parameter within, I've been able to describe the DTO in two places

image-description

and fill in the example (see code). I've tried @Schema in the @Operation (under requestBody) and @Parameter annotations. The former throws an NPE and the latter changes nothing, with a variety of tries regarding counterpart annotations in the DTO itself.

Sample Controller

@RequestMapping(value = "/{myPathVar}", method = RequestMethod.POST)
@Operation(summary = "Create something.", 
    parameters = { @Parameter(in = ParameterIn.PATH, name = "myPathVar", description = "Some path variable. Swagger uses this description.") },             
    requestBody = @io.swagger.v3.oas.annotations.parameters.RequestBody(
        description = "My description here.", 
        content = @Content(examples = @ExampleObject("{\"A\" : \"a\",\"B\" : \"{\"b\" : \"foo\", \"bb\" : \"bar\"}"))))
@ApiResponse(content = @Content(schema = @Schema(implementation = MyReturningType.class)))
public MyReturningType doSomethingCool(
    @Parameter(description = "Some description Swagger ignores.", example = "123") @PathVariable(value = "myPathVar") int myPathVar,
    @Parameter(description = "My other description here.", schema = @Schema(implementation = MyDto.class)) @RequestBody MyDto dto) {
    // do something cool
}

Sample DTO

// Do I need certain annotations here?
public class MyDto {
    // What annotation goes here? @Parameter, @JsonProperty, @Schema, something else?
    private int someInt;
    private String someString;
    private Object someObject;
}

What combination of annotations do I need to correctly label the DTO Schema within the DTO and then reference this Schema from the controller such that the Schema field is populated in SwaggerUI?

Debargha Roy
  • 2,320
  • 1
  • 15
  • 34
81n0n4b1bK
  • 51
  • 1
  • 1
  • 3

2 Answers2

3

The issue might have been caused by the fact that the fields in your DTO are of private visibility and from the code you shared, doesn't look like they have getters and setters available.

Refer to the below example for a working example of how it can be done

Controller

// Using the specific mapping annotation will keep the code clean
@PostMapping("/{myPathVar}")

// The below annotation describes the operation
@Operation(
    summary = "Brief description of the operation",
    description = "Detailed description of the operation")

// Describe the possible responses next. Prefer using @ApiResponses for multiple response
@ApiResponse(

    // specify the http response code
    responseCode = "201",

    // some description. Maybe use the corresponding http response code's description
    description = "Created",

    // describe the content that will be returned for this response code
    content = @Content(
        // optionally, specify the media type for the response here as shown in the below code
         mediaType = MediaType.APPLICATION_JSON_VALUE,
        // specify the implementation of the response DTO here
        schema = @Schema(implementation = Void.class)))

public Void doSomethingCool(

    // Use @Parameter for @PathVariable and @RequestVariable
    @Parameter(description = "Description for path/request-parameter here")
    @PathVariable(value = "myPathVar")
        int myPathVar,

    // Both these @RequestBody annotations are mandatory.
    @io.swagger.v3.oas.annotations.parameters.RequestBody(
        description = "Controller-level model description here")
    @org.springframework.web.bind.annotation.RequestBody
        TestDTO dto) {
  // ... do some cool stuff here
  return null;
}

DTO

@Schema(description = "Model-level description here")
public class TestDTO {

  @Schema(description = "Field-level description here")
  private int someInt;

  @Schema(description = "Another Field-level description here")
  private String someString;

  @Schema(description = "Yet another Field-level description here")
  private Object someObject;

  // all getters and setters here

}

This gives you the output as below

swagger-ui-sample

Debargha Roy
  • 2,320
  • 1
  • 15
  • 34
  • Your results are exactly what I'm looking for, but having copied over your solution I am not getting anything at all under request body, not even descriptions like I had before. My DTO fields are private, but I do have public getters and setters. However, the DTO and controller are in separate modules within the same project and the DTO needs to be imported. I thought this might be the issue, but tried using public DTO fields and putting the DTO on the same level as the controller and still getting an empty request body... – 81n0n4b1bK Sep 27 '21 at 16:19
  • Do you mind sharing a reproducible example on GitHub/Bitbucket etc.? – Debargha Roy Sep 27 '21 at 17:42
  • Nice one. Can you share an example for Enum types as params ? – rolling stone Sep 15 '22 at 20:13
0

Annotated your dto like the following . It works for me

@Schema(description = "User Dto")
@Data
public class UserDto {
  private int id;

  @JsonProperty
  private String email;

  @JsonProperty
  private String password;

  @JsonProperty
  private String firstName;

  @JsonProperty
  @Schema(description = "User Id")
  private String lastName;
}

Screenshot

amit ghosh
  • 81
  • 7
  • The question author wants to use a DTO in the request body. You show how to use it as a POST parameter. – tanius Dec 20 '22 at 02:17