Search code examples
javaspringspring-bootspringfoxspringdoc

OpenApi documentation with spring-doc in combination with ResponseBodyAdvice


I have a simple rest API and I am testing springdoc swagger documentation. The rest controller:

@RestController
public class UserController {

    private final UserService userService;

    public UserController(final UserService userService) {
        this.userService = userService;
    }

    @PostMapping("/users")
    @PreAuthorize("hasAuthority('create:user')")
    public ResponseEntity<UserDto> create(final @RequestBody @Valid CreateUserCommand command) {
        return ResponseEntity
                .status(HttpStatus.CREATED)
                .body(userService.create(command));
    }
}

Then I wrap all the API response objects in a ResponseControllerAdvice:

@RestControllerAdvice
public class CustomResponseBodyAdvice implements ResponseBodyAdvice<Object> {
    @Override
    public boolean supports(final @NotNull MethodParameter returnType,
                            final @NotNull Class<? extends HttpMessageConverter<?>> converterType) {
        return true;
    }

    @Override
    public Object beforeBodyWrite(final Object body,
                                  final @NotNull MethodParameter returnType,
                                  final @NotNull MediaType selectedContentType,
                                  final @NotNull Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  final @NotNull ServerHttpRequest request,
                                  final @NotNull ServerHttpResponse response) {
        if (body instanceof ResponseEnvelope || body instanceof Resource) {
            return body;
        }
        if (body instanceof final ResponseEntity<?> responseEntity) {
            response.setStatusCode(responseEntity.getStatusCode());
        }
        return ResponseEnvelope.builder().success(true).result(body).build();
    }

But I am struggling to find a way to make Springdoc take into consideration this ResponseEnvelope wrapper object. Any ideas?

using Spring boot 2.6.2 + Java 17:

            <dependency>
                <groupId>org.springdoc</groupId>
                <artifactId>springdoc-openapi-ui</artifactId>
                <version>1.6.4</version>
            </dependency>

What I want:

{
 "status": "OK",
 "result": {
   "username": "johndoe"
   }
 }

What I get:

{
   "username":  "johndoe"
}

Solution

  • Fixed it by using the OperationCustomizer interface:

    @Configuration
    class ApiDocsOperationCustomizer implements OperationCustomizer {
    
    @Override
    public Operation customize(Operation operation,
                               HandlerMethod handlerMethod) {
        final Content content = operation.getResponses().get("200").getContent();
        content.keySet().forEach(mediaTypeKey -> {
            final MediaType mediaType = content.get(mediaTypeKey);
            mediaType.schema(this.customizeSchema(mediaType.getSchema()));
        });
        return operation;
    }
    
    private Schema<?> customizeSchema(final Schema<?> objSchema) {
        final Schema<?> wrapperSchema = new Schema<>();
        wrapperSchema.addProperties("success", new BooleanSchema()._default(true));
        wrapperSchema.addProperties("result", objSchema);
        return wrapperSchema;
    }}