.NET Core — API Versioning

Nelson Souza
5 min readJul 24, 2019

--

Versionamento de APIs + Swagger

Olá tudo bem? Hoje abordaremos um tema de suma importância: o versionamento de APIs.

Sim, é muito importante pensar que na construção de APIs ao longo do tempo podem haver novas features ou em algum momento meia dúzia de métodos ficarem depreciados. Isso acontece muito quando precisamos trabalhar acessando APIs de terceiros.

Na grande maioria das vezes, a empresa do outro lado, que expõe determinada API, não se preocupa em estender, em melhorar performance, continua entregando resultados em XML complexo (por exemplo). E sua aplicação moderna, preparada para ser performática, acaba dependendo da empresa parceira e em algum momento as coisas não se casam bem.

A proposta aqui é pensar em desfazer toda essa loucura e preparar nosso ambiente de forma saudável e inteligente. E para isso, iremos usar uma biblioteca para .NET Core da própria Microsoft chamada Microsoft.AspNetCore.Mvc.Versioning.

Iniciando o projeto

Vamos criar um projeto em branco do tipo ASP Net Core Web Application:

No Package Manager Console, vamos adicionar 2 bibliotecas:

install-package Microsoft.AspNetCore.Mvc.Versioning
install-package Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer
  • Microsoft.AspNetCore.Mvc.Versioning é a biblioteca principal que vai tratar de nosso versionamento.
  • Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer é uma biblioteca que fará o mapeamento de metadados, lista de métodos acessíveis da API e suas versões, expondo isso para nossa documentação.

Cenário

  • Imagine que o seu cliente consome uma API para retornar uma lista de produtos.
  • O método dessa API de produtos precisa passar 3 parâmetros de entrada para retornar essa tal lista que contem 50 propriedades e em formato XML.
  • Agora, o seu cliente decidiu consumir essa API em dispositivos móveis. Quer mostrar somente 5 propriedades de cada item da lista, passar 1 parâmetro de entrada e o retorno deve ser JSON.
  • Você decide então criar um novo método para API que funcione em dispositivos móveis, mas acaba fazendo o que muita gente até hoje ainda faz, que é a velha gambiarra: põe ifs malucos, reutiliza o mesmo código da API pesada e pronto, cria objetos aqui e ali e tá funcionando! Afinal não pode simplesmente apagar a API existente, por que muita gente ainda consome a versão em XML. Resumo da ópera: over head and rework!

Bom, daria pra criar uma nova API para resolver isso, por que não? Sim, dá, não seria uma má idéia. Mas, vai fazer isso sempre que houver esse tipo de problema? E o ciclo de vida de suas APIs, não existe?

Então, por que não criar uma versão destas API? Teríamos aí uma versão legada (chamamos de versão 1.0) e por outro lado estaríamos construindo a versão 2.0. Em um momento específico, essa API 1.0 estaria depreciada e assim seus clientes alterariam as chamadas para a nova versão.

Construindo o versionamento

Criaremos uma estrutura de versionamento, veja na imagem abaixo:

  • Features/v1/Products → irá retornar uma lista de produtos contendo Id, Name, Department e Price.
  • Features/v2/Products → irá retornar uma lista de produtos contendo Id, Name, Department, Price e agora o cliente pediu que adicionasse o SKU — Stock Keeping Unit ou Unidade de Manutenção de Estoque.

Na opção v2 vamos abordar 2 métodos: um método normal que traz os produtos e um outro para a versão mobile, só para diferenciar. Será algo mais ou menos assim:

http://domain/api/v1/productshttp://domain/api/v2/products
http://domain/api/v2/products/mobile-version

Isso é um exemplo que estou passando, não quer dizer que seja exatamente desta forma. A estrutura cabe a quem está desenvolvendo o projeto de acordo com as especificações.

Vamos configurar nosso Startup.cs da seguinte forma:

Entendendo o código acima na parte dos serviços de versionamento:

services.AddApiVersioning

  • DefaultApiVersion é opcional, assumindo que a versão padrão da API é 1.0, não faz muito sentido ter. Essa opção é usada para especificar a versão da API padrão a ser usada quando nenhuma versão é especificada na solicitação. Isso padronizará na versão para 1.0.
  • ReportApiVersions permite que a API retorne versões no header do response (também é opcional, mas pode ser útil).
  • AssumeDefaultVersionWhenUnspecified quer dizer que se não existir uma versão especificada, será assumida a default (1.0).

services.AddVersionedApiExplorer

  • GroupNameFormat formatação para identificar os versionamentos da API. Neste caso v é menor versão e VVV maior, menor versão e status.
    Ex: 1.0-RC, 1.50-RC1.

A lista completa pode ser vista aqui: https://github.com/microsoft/aspnet-api-versioning/wiki/Version-Format

  • SubstituteApiVersionInUrl permite que seja controlada a versão da API antes de serem substituídos nos modelos de rota.
    Ex: Se você não possui versão em uma rota específica, automaticamente é redirecionado para a versão default.

Em nossas Controllers vamos informar que existem a v1 e v2:

  • Features/v1/Products/ProductsController
[ApiController]
[ApiVersion("1", Deprecated = true)] // futura API depreciada
[Route("api/v{version:apiVersion}/products")]
[Produces("application/json")]
public class ProductsController : ControllerBase
  • Features/v2/Products/ProductsController
[ApiController]
[ApiVersion("2")]
[Route("api/v{version:apiVersion}/products")]
[Produces("application/json")]
public class ProductsController : ControllerBase

v{version:apiVersion} nada mais é que uma formatação com palavras reservadas que o .NET Core interpreta a partir do middleware da biblioteca ApiVersioning.

Exibindo versionamento no Swagger

Para começo de tudo, vamos instalar as bibliotecas do Swagger:

install-package Swashbuckle.AspNetCore.Swagger
install-package Swashbuckle.AspNetCore.SwaggerGen
install-package Swashbuckle.AspNetCore.SwaggerUI

No arquivo Startup.cs vamos adicionar o seguinte no Services:

services.AddSwaggerGen();

E no Configure:

As versões foram adicionadas no Swagger como pode ver. Na v1 temos somente um método e na v2 temos o método padrão e mais a versão mobile.

A interface IApiVersionDescriptionProvider é usada para filtrar o versionamento das APIs e documentar no Swagger.

Confesso que é muita coisa para explicar passo a passo. Mas já ajuda alguma coisa com o código fonte disponível no final do post.

Conclusão

Bom, acho que devo ter ajudado no breve entendimento dessa nova biblioteca para .NET Core. Mas, o intuito aqui era de tentar deixar o mais claro possível que o versionamento e a documentação é muito importante. Tratar isso como item principal do projeto é um ponto positivo e que deve ser pensado desde o início para não termos retrabalho no futuro.

Referências

--

--