He estado buscando cómo administrar las versiones de una API REST usando Spring 3.2.x, pero no he encontrado nada que sea fácil de mantener. Explicaré primero el problema que tengo y luego una solución ... pero me pregunto si estoy reinventando la rueda aquí.
Quiero administrar la versión según el encabezado Accept y, por ejemplo, si una solicitud tiene el encabezado Accept application/vnd.company.app-1.1+json
, quiero que Spring MVC reenvíe esto al método que maneja esta versión. Y dado que no todos los métodos en una API cambian en la misma versión, no quiero ir a cada uno de mis controladores y cambiar nada por un controlador que no ha cambiado entre versiones. Tampoco quiero tener la lógica para averiguar qué versión usar en el controlador (usando localizadores de servicio) ya que Spring ya está descubriendo qué método llamar.
Entonces, tomando una API con las versiones 1.0, a 1.8, donde se introdujo un controlador en la versión 1.0 y se modificó en la v1.7, me gustaría manejar esto de la siguiente manera. Imagina que el código está dentro de un controlador y que hay algún código que puede extraer la versión del encabezado. (Lo siguiente no es válido en Spring)
@RequestMapping(...)
@VersionRange(1.0,1.6)
@ResponseBody
public Object method1() {
// so something
return object;
}
@RequestMapping(...) //same Request mapping annotation
@VersionRange(1.7)
@ResponseBody
public Object method2() {
// so something
return object;
}
Esto no es posible en Spring ya que los 2 métodos tienen la misma RequestMapping
anotación y Spring no se carga. La idea es que la VersionRange
anotación pueda definir un rango de versiones abierto o cerrado. El primer método es válido desde las versiones 1.0 a 1.6, mientras que el segundo para la versión 1.7 en adelante (incluida la última versión 1.8). Sé que este enfoque se rompe si alguien decide pasar la versión 99.99, pero eso es algo con lo que estoy bien para vivir.
Ahora, dado que lo anterior no es posible sin una reelaboración seria de cómo funciona la primavera, estaba pensando en modificar la forma en que los controladores coincidían con las solicitudes, en particular para escribir la mía propia ProducesRequestCondition
, y tener el rango de versiones allí. Por ejemplo
Código:
@RequestMapping(..., produces = "application/vnd.company.app-[1.0-1.6]+json)
@ResponseBody
public Object method1() {
// so something
return object;
}
@RequestMapping(..., produces = "application/vnd.company.app-[1.7-]+json)
@ResponseBody
public Object method2() {
// so something
return object;
}
De esta manera, puedo tener rangos de versiones cerrados o abiertos definidos en la parte de producción de la anotación. Estoy trabajando en esta solución ahora, con el problema de que todavía tenía que reemplazar algunas clases principales de Spring MVC ( RequestMappingInfoHandlerMapping
, RequestMappingHandlerMapping
y RequestMappingInfo
), que no me gustan, porque significa trabajo adicional cada vez que decido actualizar a una versión más nueva de primavera.
Agradecería cualquier comentario ... y especialmente, cualquier sugerencia para hacer esto de una manera más simple y fácil de mantener.
Editar
Añadiendo una recompensa. Para obtener la recompensa, responda la pregunta anterior sin sugerir tener esta lógica en el controlador. Spring ya tiene mucha lógica para seleccionar a qué método de controlador llamar, y quiero aprovechar eso.
Editar 2
Compartí el POC original (con algunas mejoras) en github: https://github.com/augusto/restVersioning
produces={"application/json-1.0", "application/json-1.1"}