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"
}
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;
}}