Os padrões de projeto evoluíram para resolver problemas frequentemente encontrados em aplicativos de software. São soluções para problemas e complexidades recorrentes no design de software. Discutimos muitos padrões de design aqui, incluindo o padrão de especificação, o padrão de unidade de trabalho, o padrão de objeto nulo, o padrão de opções, o padrão flyweight, o padrão de comando, o padrão de intérprete e o padrão singleton.
Neste post vamos nos aprofundar no padrão de design REPR (request-endpoint-response), como ele simplifica o desenvolvimento de APIs e como pode ser implementado em C#.
Para usar os exemplos de código fornecidos neste artigo, você deve ter o Visual Studio 2022 instalado em seu sistema. Se ainda não tiver uma cópia, você pode baixar o Visual Studio 2022 aqui.
Qual é o padrão de design REPR?
O padrão de design REPR é uma abordagem que ajuda os desenvolvedores a aprimorar a capacidade de manutenção, reutilização e extensibilidade do código, isolando preocupações. Os desenvolvedores podem criar APIs bem estruturadas e facilmente expansíveis, concentrando-se na solicitação, no endpoint e na resposta.
O padrão de design REPR promove a modularização e garante uma separação distinta entre a solicitação de entrada, a lógica no terminal e a resposta de saída. Análogo à arquitetura de fatia vertical, o padrão de design REPR simplifica o desenvolvimento de APIs, organizando suas APIs em torno de terminais em vez de controladores. Lembre-se de que o padrão de design REPR não é baseado em REST nem em recursos. Em vez disso, é um padrão usado para definir os endpoints da API.
Por que usar o padrão de design REPR?
O padrão MVC (model-view-controller) tem sido tradicionalmente usado para construir endpoints de API. Embora o padrão MVC tenha vários benefícios, uma das principais restrições dessa abordagem são os controladores inchados, também conhecidos como “problema do controlador inchado”. Isso ocorre porque muitas vezes você acaba com controladores com métodos díspares que não são coesos (eles nunca se chamam) e que realmente não pertencem um ao outro. Como resultado, o aplicativo se afasta dos métodos baseados em REST e acaba com uma coleção solta de métodos expostos em terminais HTTP.
O padrão REPR resolve o problema de inchaço do controlador, eliminando a necessidade de ter vários métodos de ação em um controlador. Em vez disso, o padrão REPR segue o princípio de responsabilidade única, permitindo que você tenha um controlador por ação compatível em um caso de uso típico. Outros benefícios importantes incluem a separação de preocupações, melhor reutilização de código, melhor legibilidade e capacidade de manutenção, melhor testabilidade e depuração mais simples, além de maior segurança e escalabilidade.
No entanto, o padrão REPR também tem algumas desvantagens. Isso inclui maior complexidade e duplicação de código.
Crie um projeto de API Web ASP.NET Core no Visual Studio 2022
Para criar um projeto de API Web ASP.NET Core 8 no Visual Studio 2022, siga as etapas descritas abaixo.
- Inicie o IDE do Visual Studio 2022.
- Clique em “Criar novo projeto”.
- Na janela “Criar novo projeto”, selecione “API Web ASP.NET Core” na lista de modelos exibida.
- Clique em Avançar.
- Na janela “Configure seu novo projeto”, especifique o nome e o local do novo projeto. Opcionalmente, marque a caixa de seleção “Colocar solução e projeto no mesmo diretório”, dependendo de suas preferências.
- Clique em Avançar.
- Na janela “Informações adicionais” mostrada a seguir, selecione “.NET 8.0 (Long Term Support)” como a versão da estrutura e certifique-se de que a caixa “Usar controladores” esteja marcada. Estaremos usando controladores neste projeto.
- Em outra parte da janela “Informações adicionais”, deixe o “Tipo de autenticação” definido como “Nenhum” (o padrão) e certifique-se de que as caixas de seleção “Ativar suporte à API aberta”, “Configurar para HTTPS” e “Ativar Docker” permaneçam desmarcadas . Não usaremos nenhum desses recursos aqui.
- Clique em Criar.
Usaremos este projeto de API Web do ASP.NET Core para trabalhar com o padrão de design REPR nas seções abaixo.
Componentes do padrão de design REPR
Como o nome sugere, o padrão de design REPR inclui três componentes:
- Solicitação: representa os dados de entrada que o endpoint espera. Esses objetos de solicitação devem ser usados para validação de entrada e passagem de dados entre as camadas da aplicação.
- Endpoint: representa a lógica executada pelo endpoint para uma determinada solicitação.
- Resposta: Isso representa os dados de saída que o terminal retorna.
Crie um objeto de solicitação
O trecho de código a seguir ilustra uma classe de solicitação típica.
public class CreateUserRequest { public int UserId { get; set; } public string Username { get; set; } public string Password { get; set; } public string Email { get; set; } }
Da mesma forma, uma classe de solicitação para a criação de um novo produto ficaria assim:
public class CreateProductRequest { public int Id { get; set; } public string ProductName { get; set; } public string Category { get; set; } public string Description { get; set; } public decimal Quantity { get; set; } public decimal Price { get; set; } }
E uma classe de solicitação para recuperar dados do produto ficaria assim:
public class GetProductRequest { public int Id { get; set; } public string ProductName { get; set; } public string Description { get; set; } public decimal Price { get; set; } }
Implemente a lógica no endpoint
Consulte a pasta Controllers no projeto que você criou anteriormente. Clique com o botão direito na pasta Controladores e crie um novo controlador de API chamado CreateProductController. Substitua o código gerado padrão pelo código a seguir.
using Microsoft.AspNetCore.Mvc; namespace REPR_Example.ProductAPI.Endpoints.Product.CreateProduct { (Route("api/(controller)")) (ApiController) public class CreateProductController : ControllerBase { (HttpPost(Name = "GetProducts")) (ProducesResponseType(StatusCodes.Status204NoContent)) public ActionResult GetProductsAsync( GetProductRequest getProductRequest) { //Write your code here to retrieve products. return NoContent(); } (HttpPost(Name = "CreateProduct")) (ProducesResponseType(StatusCodes.Status204NoContent)) public ActionResult CreateProductAsync (CreateProductRequest createProductRequest) { //Write your code here to implement logic such as, //validation, mapping etc. return NoContent(); } } }
Agora, considere o seguinte endpoint HTTP GET.
https://localhost:4586/api/getproducts
Quando esse endpoint for atingido, a resposta típica em JSON será semelhante a esta:
{ "products": ( { "id": 1, "name": "HP ZBook Laptop", "description": " i9 Laptop with 32 GB RAM and 1 TB SSD", "price": 2500 }, { "id": 2, "name": "Lenovo Thinkpad Laptop", "description": "i9 Laptop with 16 GB RAM and 1 TB SSD", "price": 1500 } ) }
Crie o objeto de resposta
Por último, mas não menos importante, o trecho de código a seguir ilustra uma classe de resposta típica.
public class CreateProductResponse { public int StatusCode { get; set; } public string ErrorMessage { get; set; } }
Deve-se observar aqui que nem todos os terminais precisarão de dados de entrada para as classes de solicitação ou resposta. Em muitos casos, pode ser necessário apenas enviar o código de status HTTP na resposta.
Casos de uso do padrão REPR
Um caso de uso típico do padrão REPR é CQRS (segregação de responsabilidade de comando e consulta), onde você precisa ter um endpoint separado para cada comando e consulta. A arquitetura de fatia vertical é outro caso de uso do padrão REPR, onde a aplicação é dividida em camadas verticais dependendo de suas responsabilidades.
Dito isto, você não está obrigado a usar o REPR para construir um estilo específico de arquitetura. Você pode definir recursos RESTful e até mesmo endpoints no estilo RPC usando o padrão de design REPR. Você pode decidir optar por esse padrão com base nos requisitos do seu aplicativo.
O padrão de design REPR ajuda a melhorar a legibilidade, a capacidade de manutenção e a escalabilidade da sua base de código, isolando as diversas camadas do seu aplicativo, como a interface do usuário, a lógica de negócios e as camadas de acesso a dados. Você pode modificar e expandir o padrão REPR de acordo com suas necessidades, incorporando camadas ou componentes adicionais.