Search code examples
springspring-bootresponsespringdoc

How to describe standard Spring error response in springdoc Schema?


The default server response of a SpringBoot app in case of unhandled errors is

{
    "timestamp": 1594232435849,
    "path": "/my/path",
    "status": 500,
    "error": "Internal Server Error",
    "message": "this request is failed because of ...",
    "requestId": "ba5058f3-4"
}

I want to describe it in a Springdoc annotation for routes of an application.

Assuming that there is a standard class DefaultErrorResponse (just a mock name), it could look like the following:

@Operation(
  // ... other details
  responses = {
    // ... other possible responses
    @ApiResponse(
      responseCode = "500",
      content = @Content(schema = @Schema(implementation = DefaultErrorResponse.class)))
  }
)

In a worse case scenario such class does not exists and Spring uses just a Map under the hood for this response creation. Then this annotation will be more verbose, including explicit mention of every field contained in the response.

Obviously for most of the routes this part @ApiResponse(responseCode="500",... is the same, and it would be good to reduce duplication.

What is the proper way to introduce description of the default error response in the documentation?


Solution

  • You are almost correct. Spring uses org.springframework.boot.web.servlet.error.DefaultErrorAttributes for its default error handling, which is a wrapper for a map.

    However the content of that map highly depends on your configuration. I resorted to just create my own DTO that reflects my Spring configuration like this:

    public class ErrorResponse {
      private Instant timestamp;
      private int status;
      private String error;
      private String path;
      public Instant getTimestamp() {
        return timestamp;
      }
      public void setTimestamp(Instant timestamp) {
        this.timestamp = timestamp;
      }
      public int getStatus() {
        return status;
      }
      public void setStatus(int status) {
        this.status = status;
      }
      public String getError() {
        return error;
      }
      public void setError(String error) {
        this.error = error;
      }
      public String getPath() {
        return path;
      }
      public void setPath(String path) {
        this.path = path;
      }
    }
    

    and use it like this, as you already explained in your question:

    @RestController
    @ApiResponses({ //
        @ApiResponse( //
            responseCode = "500", //
            description = "Internal failure", content = @Content( //
                mediaType = "application/json", //
                schema = @Schema(implementation = ErrorResponse.class))) //
    })
    class MyController { ...