Como dar suporte a diferentes versões da API

15

Estou escrevendo uma API Rest e estou pensando em como lidar melhor com o suporte a diferentes versões. Por isso, não quero dizer como definir um URI como V2 ou V3, mas como estruturar o código, pois ele precisa:

  • Suporte várias versões ao mesmo tempo, por exemplo. Os URIs V1 e V2 e V3 devem estar ativos ao mesmo tempo. Eu me aposentaria do V1 quando o V4 chegasse, a fim de restringir o valor suportado a qualquer momento.
  • Evite o máximo de duplicação de código possível
  • Facilite a adição de alterações sem interrupção a uma versão, sem impactar em outras versões

Parece que existem poucas abordagens que podem ser adotadas:

  • Use o Git para controlar as versões, com uma ramificação para as diferentes versões (e versões antigas não tendo, essencialmente, novos trabalhos de desenvolvimento). Isso significaria nenhuma duplicação de código, pois apenas a versão mais recente está no código, mas as versões anteriores precisariam trabalhar com a nova versão do banco de dados até que sejam desativadas.

  • Código duplicado para que cada versão seja manipulada no mesmo aplicativo e tenha um caminho de código totalmente separado, mas isso significaria muita duplicação

  • Reutilize muito código nas versões, mas isso tornaria mais difícil a manutenção, pois a alteração de uma versão tem mais probabilidade de afetar uma versão anterior

Existe alguma prática recomendada para lidar com esse problema, pois todas as opções parecem ter seus próprios problemas?

Andy Davies
fonte
1
Se você especificar o número da versão na URL (por exemplo, myserver / api / 3.1.4 / user / get), poderá passar o número da versão para qualquer função que chamar, para localizar o comportamento específico da versão sem compartilhar muito código.
James McLeod

Respostas:

5

Faça isso:

Reutilize muito código nas versões, mas isso tornaria mais difícil a manutenção, pois a alteração de uma versão tem mais probabilidade de afetar uma versão anterior

mas não quebre as versões anteriores.

Você deve ter testes para verificar se todas as versões suportadas estão funcionando corretamente. Se você não tiver esses testes, primeiro crie-os para cobrir qualquer código que esteja sendo alterado.

Kevin Cline
fonte
2

Uma combinação do uso de ramificações de liberação do GIT (ou dividir cada versão em um repositório separado) para oferecer suporte e manter versões antigas da API e possivelmente ter algum código reutilizável que pode ser compartilhado como uma dependência, como uma biblioteca comum, é provavelmente o caminho ir. Portanto, cada versão da API seria um artefato implementável separadamente. Isso permite flexibilidade para que, por exemplo, a API V1 possa depender dos itens comuns V1, enquanto as APIs V2, V3, V4 podem depender dos itens comuns V2. Isso seria o mais fácil e limpo do ponto de vista do desenvolvimento, pois sua base de código não se multiplica a cada nova versão; em vez disso, cada versão é isolada em seu próprio projeto / base de código e se preocupa apenas consigo mesma.

Outro motivo para implantar artefatos separados é que pode haver preocupações transversais, como um mecanismo de segurança, ou estruturas / bibliotecas como a estrutura de injeção de dependência que podem mudar nas versões mais recentes da API e criariam muita dificuldade em oferecer suporte a APIs mais antigas, se elas todos vivem na mesma base de código (e Classloader em tempo de execução, se for Java).

Toda abordagem, seja uma ramificação por versão ou uma base de código duplicada monolítica, sempre terá o problema de um ponto de integração comum (como o DB ou um esquema de cache distribuído) que precisa ser alterado. APIs de versões mais antigas podem exigir algum tipo de manutenção para trabalhar com essas alterações ou a introdução de algumas outras ferramentas (como visualizações de banco de dados) para ajudar na compatibilidade. Essa pode ser uma dificuldade inevitável, dependendo da natureza das suas alterações.

PaulMooney
fonte
0

Não sei o quão diferentes são os resultados das versões da API, mas você pode ter uma camada de compatibilidade no meio que pode alternar entre as versões e preencher lacunas ou traduzir dados.

Dito isto - geralmente nunca funciona de maneira individual -, portanto, um design de tipo de comutador ou máquina de estado me ajudou com esse problema.

Zach Leighton
fonte