3

I have a spring (boot) server and want to generate the openapi spec from the annotations with springdoc.

I have a request with two parameters in the request body. I want the first to be required and the second to be optional

@RequestBody(required = {true|false}) seems to only set all parameters in the body to (not) required. The Javadoc for @Parameter on the other hand say to use io.swagger.v3.oas.annotations.parameters.RequestBody

This is my code that I would expect to generate a spec where the first Parameter is required and the second one is optional:

    @GetMapping("/fstVector")
    public ResponseEntity<Vector> fstV(@RequestBody final Vector v1, @RequestBody(required = false) final Vector v2) {
        return new ResponseEntity<>(v1, HttpStatus.OK);
    }
    
    @PostMapping("/fstVector")
    public ResponseEntity<Vector> fstVPost(@RequestBody(required = true) final Vector v1, @RequestBody(required = false) final Vector v2) {
        return new ResponseEntity<>(v1, HttpStatus.OK);
    }

The generated spec however has both parameters required:

  /pond/fstVector:
    get:
      tags:
      - circle-escape-controller
      operationId: fstV
      parameters:
      - name: v1
        in: query
        required: true
        schema:
          $ref: '#/components/schemas/Vector'
      - name: v2
        in: query
        required: true
        schema:
          $ref: '#/components/schemas/Vector'
      responses:
        "200":
          description: OK
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/Vector'
    post:
      tags:
      - circle-escape-controller
      operationId: fstVPost
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                v1:
                  $ref: '#/components/schemas/Vector'
                v2:
                  $ref: '#/components/schemas/Vector'
        required: true
      responses:
        "200":
          description: OK
          content:
            '*/*':
              schema:
                $ref: '#/components/schemas/Vector'

How can I require only a specific parameter for all four request types?

peer
  • 4,171
  • 8
  • 42
  • 73

3 Answers3

10

Important

  • There should not be more than 1 Request Body to a given endpoint!
  • Request Body is mostly a JSON object. Thus to make some attribute in the body mandatory it's suggested to use the validation api.
  • There are 2 @RequestBody annotations. One from the Spring framework org.springframework.web.bind.annotation.RequestBody and another from io.swagger.v3.oas.annotations.parameters.RequestBody

Importantly, even when you use the io.swagger.v3.oas.annotations.parameters.RequestBody from the Swagger library, you'll still need to use the org.springframework.web.bind.annotation.RequestBody to receive the actual object.

Refactoring the code as below should be helpful in your case

Controller Class

@GetMapping("/fstVector")
public ResponseEntity<Vector> fstV(
    // we generally use @RequestParam for query parameters. Query parameters are generally optional and thus the "required" attribute of @Parameter defaults to "false"
    @Parameter @RequestParam final Vector v1, 
    // set @Parameter to TRUE if the parameter must be passed.
    @Parameter(required = true) @RequestParam final Vector v2 
) {
    return new ResponseEntity<>(v1, HttpStatus.OK);
}
    
@PostMapping("/fstVector")
public ResponseEntity<Vector> fstVPost(
    // RequestBody objects are "required" by default. To make them optional, add "(required = false)"
    @org.springframework.web.bind.annotation.RequestBody   // Spring
    @io.swagger.v3.oas.annotations.parameters.RequestBody  // Swagger
    @Valid // Bean validation to ensure if the incoming object is valid
    final Vector v1
) {
    return new ResponseEntity<>(v1, HttpStatus.OK);
}

For domain object, refactor the DTO as below

DTO

@Schema(description = "My DTO")
class Vector {
   // The below attribute is required
   @NotNull
   @Parameter(description = "my first attribute", required = true)
   String attribute1;

   // The below attribute is optional
   @Parameter(description = "my second attribute", required  = false)
   String attribute2;
}
Debargha Roy
  • 2,320
  • 1
  • 15
  • 34
0

It is not recommended to add request body to GET request, even though you can... Look here.

Controller class methods:

@GetMapping("/fstVector")
public ResponseEntity<Vector> fstV(
        @RequestParam final Vector v1,
        @RequestParam(required = false) final Vector v2) {
    return new ResponseEntity<>(v1, HttpStatus.OK);
}

@PostMapping("/fstVector")
public ResponseEntity<Vector> fstVPost(
        @Valid
        @org.springframework.web.bind.annotation.RequestBody
        @io.swagger.v3.oas.annotations.parameters.RequestBody
        final VectorRequest vectorRequest) {
    return new ResponseEntity<>(vectorRequest.getV1(), HttpStatus.OK);
}

DTO object:

public class VectorRequest {
    @NotNull
    Vector v1;
    Vector v2;

    public Vector getV1() {
        return v1;
    }

    public void setV1(Vector v1) {
        this.v1 = v1;
    }

    public Vector getV2() {
        return v2;
    }

    public void setV2(Vector v2) {
        this.v2 = v2;
    }
}

Parameter v1 is required, v2 is optional.

enter image description here

enter image description here

ognjenkl
  • 1,407
  • 15
  • 11
0

You can describe request body parameter by @Schema annotation.

z0mb1ek
  • 899
  • 9
  • 16