Endpoints

Endpoints no Repository Pattern: Implementando um CRUD Completo

Configurando os Endpoints com Minimal APIs

Os endpoints HTTP são configurados para expor as operações CRUD do repositório através da infraestrutura do ASP.NET Core. No arquivo Program.cs, os endpoints básicos são substituídos por implementações completas que consomem a abstração IProductRepository, garantindo a separação entre a camada de apresentação e a lógica de acesso a dados.

Endpoint GET para Listagem com Paginação

O endpoint inicial de listagem é refatorado para incluir suporte a paginação e tratamento adequado de cancelamento assíncrono:

// Endpoint inicial simplificado
app.MapGet("/v1/products", async (IProductRepository repository) 
    => await repository.GetAllAsync());

Substituído por:

// Endpoint completo com paginação e tratamento de token
app.MapGet(
    "/v1/products", 
    async (
        CancellationToken token, 
        IProductRepository repository, 
        int skip = 0, 
        int take = 25)
    => Results.Ok(await repository.GetAllAsync(skip, take, token)));

Características implementadas:

  • Paginação nativa: Parâmetros skip e take com valores padrão permitem consultas como /v1/products?skip=10&take=5

  • Controle assíncrono: O CancellationToken é injetado automaticamente pelo framework para permitir o cancelamento de operações longas

  • Resposta HTTP semântica: Uso de Results.Ok() retorna código de status 200 com o corpo da resposta formatado como JSON

  • Desacoplamento: A dependência é na interface IProductRepository, não na implementação concreta

Endpoint GET por ID

O endpoint para recuperação de um recurso específico é implementado com rota parametrizada:

Por:

Observações técnicas:

  • O {id} na rota é um route parameter que captura o valor da URL

  • O sistema de model binding do ASP.NET Core converte automaticamente o valor para int

  • A ausência do produto resulta em resposta null, que pode ser tratada com Results.NotFound() em implementações mais robustas

Endpoint POST para Criação

A criação de novos recursos utiliza o verbo HTTP POST com dados no corpo da requisição:

Por:

Processo de deserialização:

  1. O framework lê o corpo da requisição como JSON

  2. Converte os dados para uma instância da classe Product

  3. Injeta automaticamente os parâmetros token, repository e product

  4. Executa a operação de criação através do repositório

Endpoint PUT para Atualização

A atualização de recursos existentes utiliza o verbo HTTP PUT:

Substituído por:

Considerações de design:

  • O objeto Product completo é enviado no corpo da requisição, incluindo o Id

  • O repositório é responsável por localizar e atualizar a entidade correspondente

  • Em APIs RESTful puristas, considera-se usar PATCH para atualizações parciais

Endpoint DELETE para Exclusão

A exclusão de recursos utiliza o verbo HTTP DELETE com identificação através da rota:

Substituído por:

Análise da implementação:

  1. Verificação de existência: Primeiro busca o produto para confirmar sua existência

  2. Resposta condicional: Retorna 404 Not Found se o recurso não existir

  3. Operação de exclusão: Executa a exclusão apenas após confirmação

  4. Retorno do objeto excluído: Convenção que permite ao cliente confirmar o que foi removido

Padrões e Estruturas Comuns

Injeção Automática de Parâmetros

O sistema de Minimal APIs do ASP.NET Core fornece dependency injection automática para:

  • Serviços registrados: Como IProductRepository configurado com AddTransient<>()

  • Parâmetros de requisição: Como CancellationToken para controle assíncrono

  • Dados de rota e query: Como id, skip, e take

Tratamento Semântico de Respostas

Os helpers Results.* proporcionam respostas HTTP padronizadas:

Método Helper

Código HTTP

Uso Típico

Results.Ok()

200 OK

Operação bem-sucedida com corpo

Results.NotFound()

404 Not Found

Recurso não encontrado

Results.Created()

201 Created

Recurso criado com URL de localização

Results.NoContent()

204 No Content

Operação bem-sucedida sem corpo

Executando e Testando a Aplicação

Inicialização do Serviço

Ao executar a aplicação, o sistema registra as informações de inicialização:

A aplicação fica disponível na porta 5039, configurada automaticamente pelo Kestrel, o servidor web embutido do ASP.NET Core.

Configuração do Ambiente de Banco de Dados

Para operações de persistência real, o SQL Server em container Docker precisa ser inicializado:

Saída esperada:

Esta etapa é necessária apenas para ambientes de desenvolvimento utilizando containers. Em produção, a conexão seria configurada para um servidor de banco de dados gerenciado.

Sequência de Testes no Postman

A validação dos endpoints é realizada através de requisições HTTP sequenciais, simulando o fluxo completo de operações CRUD.

1. Criação de Produto (POST)

Requisição:

Resposta (200 OK):

Análise: A operação de criação retorna o objeto persistido, incluindo o identificador gerado pelo banco de dados. Em APIs RESTful puristas, considera-se retornar 201 Created com cabeçalho Location apontando para o recurso criado.

2. Listagem de Produtos (GET)

Requisição:

Resposta (200 OK):

Observação: A listagem retorna um array JSON, mesmo contendo um único elemento, mantendo consistência com o contrato da API.

3. Obtenção por ID (GET com parâmetro)

Requisição:

Resposta (200 OK):

Padrão RESTful: A URL /v1/products/{id} segue a convenção de recursos aninhados, onde cada produto é acessível através de seu identificador único.

4. Atualização de Produto (PUT)

Requisição:

Resposta (200 OK):

Idempotência: O verbo PUT é idempotente - múltiplas requisições idênticas produzem o mesmo resultado que uma única requisição.

5. Verificação da Atualização

Requisição:

Resposta (200 OK):

Consistência de dados: A verificação confirma que a atualização foi persistida corretamente no banco de dados.

6. Exclusão de Produto (DELETE)

Requisição:

Resposta (200 OK):

Convenção de retorno: A API retorna o objeto excluído, permitindo ao cliente confirmar a operação. Alternativamente, poderia retornar 204 No Content sem corpo.

7. Verificação após Exclusão

Requisição:

Resposta (200 OK):

Estado final: A listagem vazia confirma que o recurso foi removido permanentemente do repositório.

Melhorias e Boas Práticas

Validação de Entrada

Para aumentar a robustez da API, a validação dos dados de entrada pode ser implementada:

Versionamento de API

Considerar implementar versionamento para evolução da API:

Tratamento de Exceções

Implementar um middleware para tratamento uniforme de erros:

Documentação com OpenAPI

A integração com Swagger/OpenAPI facilita a documentação e teste da API:

Conclusões e Próximas Etapas

Resultados Alcançados

A implementação demonstra a integração bem-sucedida entre:

  1. Minimal APIs para definição concisa de endpoints

  2. Repository Pattern para abstração do acesso a dados

  3. Dependency Injection para inversão de controle

  4. Entity Framework Core para persistência ORM

  5. Testes manuais com Postman para validação funcional

Princípios Arquiteturais Aplicados

  • Separation of Concerns: Endpoints lidam com HTTP, repositórios com dados

  • Dependency Inversion: Dependências de abstrações, não de implementações

  • Single Responsibility: Cada componente tem uma responsabilidade bem definida

  • Open/Closed: Extensível através de novas implementações de IProductRepository

Recomendações para Evolução

  1. Autenticação e Autorização: Implementar mecanismos como JWT para segurança

  2. Logging Estruturado: Adicionar logs semânticos para monitoramento

  3. Testes Automatizados: Desenvolver testes de integração e unitários

  4. Cache Estratégico: Implementar cache para endpoints de leitura frequente

  5. Versionamento de API: Estruturar para evolução sem breaking changes

  6. Documentação Automática: Expandir documentação com exemplos e códigos de erro

A arquitetura resultante proporciona uma base sólida para desenvolvimento de APIs escaláveis e manteníveis, onde modificações na camada de persistência ou na lógica de negócio podem ser realizadas com impacto mínimo nos consumidores da API.

Atualizado