Tenho pesquisado como gerenciar versões da API REST usando Spring 3.2.x, mas não encontrei nada que seja fácil de manter. Vou explicar primeiro o problema que tenho e depois uma solução ... mas me pergunto se estou reinventando a roda aqui.
Quero gerenciar a versão com base no cabeçalho Aceitar e, por exemplo, se uma solicitação tiver o cabeçalho Aceitar application/vnd.company.app-1.1+json
, quero que o Spring MVC encaminhe isso para o método que lida com esta versão. E como nem todos os métodos em uma API mudam na mesma versão, não quero ir a cada um dos meus controladores e mudar nada para um manipulador que não mudou entre as versões. Eu também não quero ter a lógica para descobrir qual versão usar no próprio controlador (usando localizadores de serviço), pois o Spring já está descobrindo qual método chamar.
Então, pegando uma API com as versões 1.0, até 1.8, onde um manipulador foi introduzido na versão 1.0 e modificado na v1.7, gostaria de lidar com isso da seguinte maneira. Imagine que o código está dentro de um controlador e que existe algum código capaz de extrair a versão do cabeçalho. (O seguinte é inválido na primavera)
@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;
}
Isso não é possível no Spring, pois os 2 métodos têm a mesma RequestMapping
anotação e o Spring falha ao carregar. A ideia é que a VersionRange
anotação pode definir um intervalo de versão aberta ou fechada. O primeiro método é válido das versões 1.0 a 1.6, enquanto o segundo para a versão 1.7 em diante (incluindo a versão mais recente 1.8). Eu sei que essa abordagem é interrompida se alguém decidir passar a versão 99.99, mas estou bem em conviver com isso.
Agora, uma vez que o acima não é possível sem um retrabalho sério de como funciona o spring, eu estava pensando em consertar a maneira como os manipuladores combinam com as solicitações, em particular para escrever meu próprio ProducesRequestCondition
, e ter o intervalo de versão lá. Por exemplo
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;
}
Desse modo, posso fechar ou abrir intervalos de versão definidos na parte de produtos da anotação. Estou trabalhando nessa solução agora, com o problema de que ainda tenho que substituir algumas classes principais do Spring MVC ( RequestMappingInfoHandlerMapping
, RequestMappingHandlerMapping
e RequestMappingInfo
), das quais não gosto, porque isso significa trabalho extra sempre que decido atualizar para uma versão mais recente do Primavera.
Eu agradeceria qualquer pensamento ... e especialmente, qualquer sugestão para fazer isso de uma forma mais simples e fácil de manter.
Editar
Adicionando uma recompensa. Para obter a recompensa, responda à pergunta acima sem sugerir ter essa lógica no próprio controlador. O Spring já tem muita lógica para selecionar qual método de controlador chamar, e eu quero pegar carona nisso.
Editar 2
Eu compartilhei o POC original (com algumas melhorias) no github: https://github.com/augusto/restVersioning
produces={"application/json-1.0", "application/json-1.1"}
etc