[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 |
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 |
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)
É 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 PathExemplo:https://api-v1.minhagastronomia/vinhosouhttps://api.minhagastronomia/v1/vinhosPrós e ContrasPrósContras1. É a opçDescriçãomais utilizada do mercado1. Adiciona comprimento à sua rota2. É 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 versionamento4. Você pode facilmente estruturar sua API para permitir o versionamento por rota
Accept headers, o header customizadoExemplo: Accept-Version: v2Prós e ContrasPrósContras1. A priori, uma solução fácil.1. Obriga a informar cabeçalhos personalizados2. 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 URLExemplo: /products/product-name?version=v2Prós e ContrasPrósContras1. É 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.VersioningeMvc.Versioning.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 controllerMover endpoints utilizados pelos Gov.Doc (frontend) para a versão 2.
Criar pasta dentro de Services e Dtos para cada versãoElaborar calendário com datas:Para subir versão 2.0 para development, staging e productionPara descontinuar endpoints sem versão
- "Aprendendo os componentes de Middleware do Asp .Net Core -Parte 1", Daniel Jesus.
- "Compreendendo os middlewares no ASP.NET Core", Wladimilson M. Nascimento.
- "Criando um middleware customizado para ASP.NET Core",
RESTfulWladimilson M. Nascimento. - "Padrões de Web API
versioning–madeParteeasy02: Middleware",ScottKenerryHanselman. "A importância do versionamento de APIs", Patrick Francis Gomes Rocha.Serain.
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.
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);
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.