Search code examples
spring-bootrestmavenswagger-uispringdoc-openapi-ui

Spring boot REST API remove duplicated response body


So I'm using springdoc-openapi-ui and I am able to produce the API which is accessible with swagger UI.

However, I've noticed that all response codes in the swagger UI copy the response code from the one returned by 200 response code, something which I am not doing and is quite dangerously misleading.

How can I disable this behavior? Using Swagger2 does not produce this behavior. My methods are using ResponseEntity to return responses. Could this be an issue?

OpenApi30Config.java -- Open-doc Configuration file

@Configuration
@OpenAPIDefinition(
        info = @Info(
                title = "${spring.application.name}",
                description = "${spring.application.name}'s official API documentation",
                version = "${spring.application.version}",
                contact = @Contact(name = "John Does Live", email = "does.john.live@stackoverflow.com"),
                license = @License(name = "Apache 2.0")
        ),
        security = @SecurityRequirement(name = AppConstants.API_SECURITY_REQUIREMENT_NAME)
)
@SecuritySchemes({
        @SecurityScheme(
                name = AppConstants.API_SECURITY_REQUIREMENT_NAME,
                in = SecuritySchemeIn.HEADER,
                type = SecuritySchemeType.APIKEY,
                description = "Provisioned API key",
                paramName = AppConstants.API_KEY_HEADER_NAME
        ),
        @SecurityScheme(
                name = "bearerToken",
                in = SecuritySchemeIn.HEADER,
                type = SecuritySchemeType.APIKEY,
                paramName = AppConstants.JWT_HEADER_NAME,
                description = "JWT token obtained after user authenticated with the server"
        )
})
@Profile("dev")
public class OpenApi30Config {
}

GeneralAPIResponses.java -- Annotation to be applied to all controller methods. Documents all the general response codes.

@Documented
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@ApiResponses({
        @ApiResponse(responseCode = "200", description = "Operation was successful"),
        @ApiResponse(responseCode = "401", description = "Invalid API key"),
        @ApiResponse(responseCode = "403", description = "Invalid JWT", content),
        @ApiResponse(responseCode = "500", description = "Internal server error")
})
public @interface GeneralAPIResponses {
}

SecuredRestAPIController.java -- Indicates that an endpoint is secured.

@SecurityRequirement(name = AppConstants.API_SECURITY_REQUIREMENT_NAME)
public interface SecuredRestAPIController {
}

BaseController.java -- Extensible controller

@Validated
public abstract class BaseController {
    protected final Logger LOG;

    protected BaseController() {
        LOG = LoggerFactory.getLogger(getClass());
    }

    protected String format(String format, Object... args) {
        return String.format(Locale.US, format, args);
    }
}

Foo.java

@RestController
@RequestMapping("/foo")
@Tag(name = "Foo", description = "Endpoint for handling all foo related operations.")
public class FooController extends BaseController implements SecuredRestAPIController {

    @PostMapping
    @Operation(
            description = "Add foo.",
            responses = {
                    @ApiResponse(responseCode = "409", description = "Foo with same phone number already exists.")
            })
    @GeneralAPIResponses
    ResponseEntity<FooActionResponse> addFoo(@Valid @RequestBody FooActionRequest request) {
        // ... logic
        return ResponseEntity.ok(new FooActionResponse(UUID.randomUUID(), LocalDateTime.now()));
    }

}

After all of this, this is what I'm getting:

enter image description here

And this. (Notice FooActionResponse response is copied to all the responses) I do not want to have this because it will mislead other developers reading the documentation. It seems as though all the status codes return the same content when the API does not.

enter image description here


Solution

  • This issue happens because you haven't specified @Content for each additional response. The SpringDoc assumes that the response body is the same as for your annotated method.

    If you have a generic error model for error responses, you can specify it in the content section:

        @ApiResponses({
            @ApiResponse(responseCode = "401", description = "Invalid API key", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ErrorModel.class))),
            @ApiResponse(responseCode = "403", description = "Invalid JWT", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ErrorModel.class))),
            @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content(mediaType = MediaType.APPLICATION_JSON_VALUE, schema = @Schema(implementation = ErrorModel.class))),
        })
    

    If you just want a description for the error, without any schema, you need to specify an empty @Content for the response:

        @ApiResponses({
            @ApiResponse(responseCode = "401", description = "Invalid API key", content = @Content),
            @ApiResponse(responseCode = "403", description = "Invalid JWT", content = @Content),
            @ApiResponse(responseCode = "500", description = "Internal server error", content = @Content),
        })
    

    enter image description here