es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Swagger 2 con Spring boot e interceptor.

Estoy utilizando Spring Boot 2.5.6, Swagger2 y Java 17.

Tengo un punto de conexión que recibe un json con un JWT en el cuerpo como esto:

{"signedPayload":"encodedJWTstring"}

Dado que este JWT necesita ser decodificado, validado y su carga interna mapeada a un DTO, hemos decidido crear un interceptor de Spring que haga esto antes de llegar al controlador.
Esta parte funciona muy bien, mi único problema es con Swagger.

@Log4j2
@Component
public class CallbackInterceptor implements HandlerInterceptor {

@Override
public boolean preHandle(
  HttpServletRequest request, HttpServletResponse response, Object handler) {
 // ...aquí ocurre la magia...
 request.setAttribute(
    "decodedRequestDTO",
    CallbackRequestDTO.builder().build(); //y los campos se establecen aquí también
  }
}

Y el método del controlador se ve así:

public ResponseEntity<httpstatus> eventsCallback(
  @NotNull
  @Valid
  @RequestAttribute("decodedRequestDTO")
  CallbackRequestDTO callbackRequestDTO) {

}

El problema que tengo es que no puedo encontrar una forma de cambiar la definición de esquema de Swagger al json que debería recibir y no el CallbackRequestDTO.
Aparentemente, el problema es que estoy utilizando @RequestAttribute y debido a eso Swagger no escaneará otras anotaciones como @Parameter.

He probado varias combinaciones y anotaciones sin suerte, realmente apreciaría algo de ayuda.

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    Problema de definición de Swagger con las anotaciones @RequestAttribute y @Parameter

    Problema

    Como experto en IT especializado en Java, Spring Boot, Swagger, OpenAPI y Swagger-2.0, tengo un endpoint que recibe un JSON con un JWT en el cuerpo. Este JWT necesita ser decodificado, validado y su carga interna mapeada a un DTO. Para lograr esto, he creado una clase interceptor de Spring que intercepta la solicitud antes de llegar al controlador, y mapea la carga interna a un DTO utilizando el método request.setAttribute.

    @Component
    public class CallbackInterceptor implements HandlerInterceptor {
      @Override
      public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // ...aquí ocurre la magia...
        request.setAttribute("decodedRequestDTO", CallbackRequestDTO.builder().build());
      }
    }
    

    El problema está en la documentación de la API de Swagger. La documentación de la API de Swagger muestra el esquema del DTO CallbackRequestDTO, mientras que el cuerpo de la solicitud real es diferente ya que contiene un JWT.

    public ResponseEntity<httpstatus> eventsCallback(
        @NotNull
        @Valid
        @RequestAttribute("decodedRequestDTO")
        CallbackRequestDTO callbackRequestDTO) {
    }
    

    Solución

    Para resolver este problema, necesitamos anular el esquema predeterminado de Swagger utilizando las anotaciones @ApiImplicitParam o @Parameter. Sin embargo, Swagger no admite la anotación @RequestAttribute. Para superar esto, debemos usar la anotación @ModelAttribute y pasar los atributos como parámetros de consulta. Modifica la clase CallbackInterceptor para establecer el atributo CallbackRequestDTO como un parámetro de solicitud, como se menciona a continuación.

    @Component
    public class CallbackInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
            // ...aquí ocurre la magia...
            request.setAttribute("signedPayload", "encodedJWTstring");
            // se establece como parámetro de solicitud
            request.getParameterMap().put("signedPayload", new String[] {"encodedJWTstring"});
            return true;
        }
    }
    

    Ahora podemos recibir la cadena JWT en el método del controlador y validarla.

    public ResponseEntity<httpstatus> eventsCallback(
        @NotNull
        @Valid  
        @Parameter(description = "cadena JWT codificada", required = true, example = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c")
        CallbackRequestDTO callbackRequestDTO) {
    }
    

    De esta manera, Swagger mostrará el esquema correcto basado en el cuerpo de la solicitud.

    Resumen

    En resumen, al utilizar @RequestAttribute para mapear el atributo de la solicitud al DTO, la documentación de la API de Swagger no muestra el esquema correcto y sólo muestra el esquema del DTO. Para superar este problema, debemos utilizar @ModelAttribute en la clase interceptor, y pasar el atributo como un parámetro de solicitud. Luego, utilizar la anotación @Parameter para describir la cadena JWT en el método del controlador. De esta manera, Swagger mostrará el esquema correcto basado en el cuerpo de la solicitud.

Comments are closed.