Ir para o conteúdo principal

[Gov.Doc-API] Implementar middleware personalizado

Data de elaboração 13/01/2023
Responsável pelo estudo

Nara Carolina Galvão Feitosa

Raissa de Sousa Stodulski
Taillon Miguel Gonçalves
Ádelle Camarão Monteiro

Equipe do estudo Tambakiss
Alvo Gov.Doc API
Origem

Implementação, para facilitar novas integrações pois estará padronizando os retornos esperados dos endpoints, facilitando o entendimento e tratamento dos mesmos.

Objetivo Com o middleware personalizado, facilitar novas integrações pois estará padronizando e simplificando os retornos esperados.esperados (tanto bem sucedidos quanto de validações e/ou erros).
Documentação correlata (opcional)
Observações


A. Introdução

Para facilitar novas implementaçintegrações ecom alterações noo Gov.Doc Doc-API, propõem-se implementar versionamentomiddleware personalizado na API,mesma, pois é um padrão utilizado em todo o mundo nas APIsaplicações independentemente das tecnologias utilizadas. Assim sendo, objetivo desse estudo é analisar as possibilidades de implementação, identificar as possíveis alterações e levantar as demandas necessárias.


1. O que é middleware

"[É o componente que] podemos usar para interceptar a solicitação, e assim, modificá-la enquanto ela passa pelo sistema. Os componentes de middleware, organizados em uma cadeia, formam o pipeline de solicitação. Esses componentes são escritos (ou registrados) no método “Configure” da classe “StartUp”. Neste caso, existem basicamente dois tipos de componentes de middleware. Componentes de middleware padrão (integrados) e personalizados." (Jesus, Daniel)

"Em termos práticos, middleware seria um trecho de código que pode ser executado no fluxo de execução da aplicação. [São]  organizados em um pipeline e são executados conforme uma solicitação é recebida e uma resposta enviada. A imagem abaixo ilustra este pipeline:" (Nascimento, Wladimilson)

image.png

É possível definir middleware de diversas funcionalidades, por exemplo, no trecho de código abaixo, temos oito middlewares:

1. Exception/error handling 2. HTTP Strict Transport Security Protocol 3. HTTPS redirection
4. Static file server
5. Cookie policy enforcement
6. Authentication
7. Session
8.MVC

[xxxxxxxxxxxxxxx]

2. Exemplos de implementação

Se é uma API que possui várias integrações ou se tem grande impacto nos sistemas que integram com ela, é de grande valia implementar o versionamento. O mesmo, permite que ao longo das alterações que a API sofre, você possa gradualmente descontinuando funcionalidades e permitindo que novas implementações não impactem integrações existentes com a API. O melhor momento para implementação é na criação da API.

Foi identificado a necessidade de implementar o versionamento devido aos seguintes cenários:

  • "Já se deparou com uma situação terrível de ter desenvolvido um sistema que consome algum tipo de API, e ele parar de funcionar, pois o serviço que o sistema consumia foi atualizado? Ou também em uma outra ótica para quem desenvolve as APIs, aquela discussão árdua para atualiza-la, criando até comitês de inúmeras pessoas (clientes), discutindo horas somente para atualizar um atributo que é necessário para uma situação (cliente) e para outro não faz sentido a alteração?". 

3. Opções de implementação

Há três possíveis implementações:

  • URL, versão por Path
    • Exemplo: https://api-v1.minhagastronomia/vinhos ou https://api.minhagastronomia/v1/vinhos
    • Prós e Contras
      • PrósContras
        1. É a opçDescrição mais utilizada do mercado1. Adiciona comprimento à sua rota 

        2. É muito mais claro e simples. Além de dar um visual mais clean na URL, facilita a navegação para outras versões da API. É mais dev-friendly comparado a outras abordagens.


        3. Muitos frameworks oferecem suporte à esse versionamento
        4. Você pode facilmente estruturar sua API para permitir o versionamento por rota
  • Accept headers, o header customizado
    • Exemplo: Accept-Version: v2
    • Prós e Contras
      • PrósContras
        1. A priori, uma solução fácil.1. Obriga a informar cabeçalhos personalizados 
        2. Se formos seguir a especificação ao pé da letra, essa é a maneira correta de fazer o versionamento de APIs.2. Não é dev-friendly, pois a requisição tem que ser feita com muito mais cuidado.
        3. É que sua URL permanece clean e intacta.
  • Query string, passar por parâmetro na URL
    • Exemplo: /products/product-name?version=v2
    • Prós e Contras
      • PrósContras
        1. É uma abordagem que já foi muito utilizada.1. Caiu em desuso. É conhecida como má prática por muitos desenvolvedores.

        2. Além de prejudicar a navegação para outras versões, a legibilidade da URL fica ruim em cenários de muitos parâmetros na query string


4. Implementando

Algumas possibilidades e sugestões de implementação levantadas.

  • Pode se implementar utilizando os pacotes disponíveis: WebApi.Versioning e Mvc.Versioning
  •  

     

     


    Código
    Para1. umaConfigura implementaçãna Startup

     

    image.png

    2. Criando a classe Middleware

     

    image.png

    3. A chamada pode ser usando .UseMiddleware

     

    image.png

    4. Mas o superrecomendado fácilé (comcriar ASP.NETum Core)método de extensão e utiliza-lo no Configure()

     

    image.png

     

    image.png

    Cria endpoint configurado para gerar exceção.

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    Cria um DTO para estruturar o retorno de exceções.

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    Cria a classe middleware para tratar/padronizar o tratamento/retorno de erros.

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    Configura na Startup o middleware criado.


    image.pngimage.png

    Para quando possui uma API mas não possui versionamento 

    image.png

    Quando há 3 versões mas somente 2 controllers, é possível implementar mais de uma versão por controller.


    image.pngimage.png

    Para descontinuar o uso de uma versão no endpoint.


     

    image.pngimage.png

    image.pngimage.png

    Implementar status 301 - Moved permanently.

    Indica que o endpoint com a URI solicitada foi movida permanentemente para outra URI.

    Pode ser usado para indicar o uso de uma versão de API obsoleta / sem suporte.
    image.png


    • 5.3. Alterações necessárias 

      A sugestão é utilizar o middleware para tratar e padronizar os erros.

      Status HTTP: 500 - Internal Server Error
      Retorno: { mensagens: [ "mensagem de validação 1", "mensagem de validação 2"] }

      Mas seria necessário fazer um protótipo para tentar padronizar o retorno de validações.

      Status HTTP: 400 - Bad Request
      Retorno: { mensagens: [ "mensagem de validação 1", "mensagem de validação 2"] }

      E padronizar o retorno de bem-sucedido tanto de criação (201 - Created) quanto qualquer outro (200 - OK).

      Status HTTP: 200 - OK
      Retorno: { mensagem: "mensagem de bem-sucedido" }
               ou { mensagem: "mensagem de bem-sucedido", objeto: { } }

      Status HTTP: 201 - Created 
      Retorno: { mensagem: "mensagem de bem-sucedido", objeto: { } }

      Uma ideia seria criar um BaseService onde elaboraremos uma novaestrutura controllerque compermita versionamento,adicionar levarmensagens osde endpointsvalidação doe Gov.Docantes (somentede utilizadosrealizar pora ele)ação, paraverifica ela,se caiu em alguma validação e retorna o BadRequest. Ou pode criar uma padronizaçclasse de exceção para atuais/futurosBadRequest projetosonde (comoquando éfor elaboradagerado essa BadRequestException, usa um middleware para padronizar/formatar o númeroretorno.

      da versão, como será

      Para a organizaçãquestão dedo endpointbem-sucedido, epode osapenas retornosser - HTTP status code) e por fim, montarcriado um calendáriodto { mensagem: string, objeto: object } que o Service retornará para descontinuar controller nãoque versionada.retornará return Ok(dto);

      • Criar pasta dentro de Controllers para cada versão.
      • Para cada controller:
        • Criar nova controller dentro da pasta /Controller/v2 com a mesma nomenclatura.
        • Mover controller antiga para dentro da pasta /Controller/v1.
        • Adicionar [ApiVersion("2")] e [Route("v{version:apiVersion}/[controller]")] na nova controller 
        • Mover endpoints utilizados pelos Gov.Doc (frontend) para a versão 2.
      • Criar pasta dentro de Services e Dtos para cada versão
      • Elaborar calendário com datas:
        • Para subir versão 2.0 para development, staging e production
        • Para descontinuar endpoints sem versão

      B. Conclusão

      Concluímos que essas são alterações necessárias para implementar o versionamentomiddleware personalizado e que irá agregar grande valor para as APIs que aplicarem. PermitiráFacilitará entregasnovas maisintegrações, fluídastanto eno detratamento menorquanto impacto.no entendimento dos retornos.


      Fontes
      1. "Aprendendo os componentes de Middleware do Asp .Net Core -Parte 1", Daniel Jesus.
      2. "Compreendendo os middlewares no ASP.NET Core", Wladimilson M. Nascimento.
      3. "Criando um middleware customizado para ASP.NET Core", RESTfulWladimilson M. Nascimento.
      4. "Padrões de Web API versioning madeParte easy02: Middleware", ScottKenerry Hanselman.
      5. "A importância do versionamento de APIs", Patrick Francis Gomes Rocha.Serain.