|
Neste
artigo vamos apresentar boas práticas que podemos usar na criação de APIs
REST na plataforma .NET. |

Criar uma API que apenas "funciona" é simples. O verdadeiro desafio é projetar serviços que sejam escaláveis, fáceis de manter, seguros e intuitivos para quem os consome.
Neste artigo, vamos direto ao ponto: o que define uma API REST de alta qualidade e como aplicar essas boas práticas na prática com ASP.NET Core / Minimal APIs.
Existem três princípios para o design da API REST:Uma API REST deve ser orientada a recursos, o que significa que os recursos (como clientes, pedidos, produtos) devem ser claramente identificáveis e acessíveis através de URIs significativas. As URIs devem ser intuitivas e fornecer uma maneira fácil de identificar e manipular os recursos.
Os métodos HTTP (GET, POST, PUT, DELETE, etc.) devem ser utilizados de acordo com as operações que estão sendo realizadas nos recursos. Por exemplo, GET para recuperar dados, POST para criar novos recursos, PUT/PATCH para atualizar recursos existentes e DELETE para excluir recursos.
Criando uma API RESTPara criar uma API REST na plataforma .NET, você pode usar o framework ASP.NET Core, que oferece suporte nativo para o desenvolvimento de APIs RESTful. Aqui está um exemplo básico de como criar uma API REST utilizando o ASP.NET Core:
Passo 1: Crie um novo projeto ASP.NET Core Web API.
Passo 2: Defina seus
controladores.
Crie controladores para lidar com as solicitações HTTP. Um controlador é uma
classe que herda de ControllerBase e contém métodos para manipular
diferentes tipos de solicitações HTTP (GET, POST, PUT, DELETE).
[ApiController] [Route("api/[controller]")] public class ProductsController : ControllerBase { } |
GET /getTodosLivros POST /criarNovoLivro POST /deletarLivro?id=5 |
GET /api/v1/livros # Obter lista de livros GET /api/v1/livros/{id} # Obter um livro específico POST /api/v1/livros # Criar um novo livro PUT /api/v1/livros/{id} # Atualizar o livro inteiro PATCH /api/v1/livros/{id} # Atualização parcial do livro DELETE /api/v1/livros/{id} # Remover um livro |
| Método | Finalidade | Sucesso Típico | ||
| GET | Ler dados | 200 OK | ||
| POST | Criar recursos | 201 Created (header location) | ||
| PUT/PATCH | Atualizar | 200 OK ou 204 No Content | ||
| DELETE | Deletar/Remover | 204 No Content |
[ApiController] [Route("api/v1/[controller]")] public class LivrosController : ControllerBase { private readonly ILivroService _livroService; public LivrosController(ILivroService livroService) => _livroService = livroService; [HttpGet("{id:int}")] public async Task<IActionResult> GetById(int id) { var livro = await _livroService.ObterPorIdAsync(id); if (livro is null) return NotFound(); // 404 Not Found return Ok(livro); // 200 OK } [HttpPost] public async Task<IActionResult> Create([FromBody] CriarLivroDto dto) { var livroCriado = await _livroService.CriarAsync(dto); // Retorna 201 Created + Header Location para GET /api/v1/livros/{id} return CreatedAtAction(nameof(GetById), new { id = livroCriado.Id }, livroCriado); } } |
POST /api/v1/pedidos Content-Type: application/json {
"clienteId": 1024,
"valorTotal": 150.00,
"itens": ["Livro C#", "Caneca"]
}
|
PUT /api/v1/pedidos/101 Content-Type: application/json {
"clienteId": 1024,
"valorTotal": 200.00,
"status": "AguardandoPagamento"
}
|
| PUT
/api/v1/pedidos/d3b07384-d113-4601-a79b-2a2d4b967d2e Content-Type: application/json { "clienteId": 1024, "valorTotal": 150.00 } |
POST /api/v1/pedidos ---> Servidor cria ID 1
|
{ "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1", "title": "Um ou mais erros de validação ocorreram.", "status": 400, "errors": { "Preco": ["O preço deve ser maior que zero."] } } |
.cs:
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); // Habilita a exibição padronizada de detalhes de problemas builder.Services.AddProblemDetails(); var app = builder.Build(); // Intercepta exceções não tratadas e converte para ProblemDetails app.UseExceptionHandler(); app.UseStatusCodePages(); app.MapControllers(); app.Run(); |
// Exemplo utilizando a biblioteca Asp.Versioning.Mvc [ApiVersion("1.0")] [Route("api/v{version:apiVersion}/[controller]")] [ApiController] public class ProdutosV1Controller : ControllerBase { /* ... */ } [ApiVersion("2.0")] [Route("api/v{version:apiVersion}/[controller]")] [ApiController] public class ProdutosV2Controller : ControllerBase { /* ... */ } |
// Habilitando Rate Limiting no Program.cs (.NET 7+) builder.Services.AddRateLimiter(options => { options.AddFixedWindowLimiter("FixedPolicy", opt => { opt.PermitLimit = 100; opt.Window = TimeSpan.FromMinutes(1); }); }); |
/// <summary> /// Obtém os detalhes de um livro pelo seu identificador. /// </summary> /// <param name="id">ID do livro</param> /// <response code="200">Retorna o livro solicitado</response> /// <response code="404">Se o livro não for encontrado</response> [HttpGet("{id}")] [ProducesResponseType(typeof(LivroDto), StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status404NotFound)] public async Task<IActionResult> GetById(int id) { /* ... */ } |
Para garantir que sua API REST na
plataforma .NET seja bem compreendida e facilmente adotada pelos
desenvolvedores, é essencial fornecer uma documentação clara e abrangente. Aqui
estão algumas recomendações para criar uma boa documentação para sua API REST:
Descrição geral da API: Forneça uma visão geral da API, incluindo seu
propósito, funcionalidades principais e os recursos que ela expõe. Isso ajuda os
desenvolvedores a entenderem o propósito e o escopo da API.
Guia de
início rápido: Forneça um guia passo a passo para os desenvolvedores começarem a
usar sua API rapidamente. Isso pode incluir instruções para configuração,
autenticação, exemplos de solicitações e respostas, etc.
Descrição dos
recursos: Documente todos os recursos da API, incluindo detalhes sobre os
endpoints disponíveis, os parâmetros de solicitação aceitos, os formatos de
resposta esperados e os códigos de status retornados.
Exemplos de uso:
Inclua exemplos de solicitações e respostas para cada endpoint da
API. Isso
ajuda os desenvolvedores a entenderem como interagir com a API e a formatar
corretamente as solicitações e respostas.
Modelos de dados: Documente os
modelos de dados usados pela API, incluindo os campos e tipos de dados aceitos
em cada solicitação e resposta. Isso ajuda os desenvolvedores a entenderem a
estrutura dos dados manipulados pela API.
Autenticação e autorização:
Descreva os métodos de autenticação e autorização suportados pela API, incluindo
como obter e usar tokens de acesso ou chaves de API. Forneça exemplos de como
autenticar solicitações na API.
Limitações e políticas de uso: Documente
quaisquer limitações ou políticas de uso da API, como limites de taxa, quotas de
acesso ou restrições de uso. Isso ajuda os desenvolvedores a entenderem as
restrições impostas pela API.
Referência da API: Forneça uma referência
completa da API, incluindo uma lista de todos os endpoints, parâmetros de
solicitação e respostas suportadas, e os códigos de status retornados. Isso
ajuda os desenvolvedores a consultar rapidamente a documentação para encontrar
informações sobre endpoints específicos.
Ferramentas de interação com a
API: Se possível, forneça ferramentas de interação com a API, como clientes HTTP
ou SDKs para diferentes linguagens de programação. Isso facilita a integração e
o desenvolvimento de aplicativos que consomem a API.
Manutenção da
documentação: Mantenha a documentação atualizada com as últimas alterações na
API. Isso inclui atualizar exemplos, modelos de dados e referências de endpoint
sempre que a API for atualizada ou alterada.
8.
Testando a sua API
Quando se trata de testar uma API REST
em .NET, é importante adotar boas práticas de teste de unidade para garantir que
sua API esteja funcionando conforme o esperado e que seja robusta o suficiente
para lidar com diferentes cenários. Aqui estão algumas recomendações e boas
práticas para testar APIs REST no .NET:
Separação de camadas: Estruture
sua aplicação de forma que a lógica de negócios, a camada de acesso a dados e a
lógica de apresentação estejam separadas. Isso permite que você teste cada
camada isoladamente, facilitando a escrita e a execução de testes de unidade.
Testes unitários: Escreva testes unitários para cada componente da sua API
REST, incluindo controladores, serviços e classes utilitárias. Isso ajuda a
garantir que cada parte da sua API esteja funcionando corretamente de forma
isolada.
Mocks e stubs: Use mocks e stubs para isolar as dependências
externas da sua API durante os testes. Isso permite que você simule o
comportamento de objetos externos, como bancos de dados ou serviços web,
tornando os testes mais previsíveis e independentes.
Testes de
integração: Além dos testes unitários, escreva testes de integração para validar
a interação entre os diferentes componentes da sua API. Isso pode incluir testes
de integração de ponta a ponta para simular cenários reais de uso da API.
Testes automatizados: Automatize a execução dos seus testes de unidade e
integração para garantir que eles sejam executados regularmente como parte do
processo de desenvolvimento. Isso ajuda a identificar problemas o mais cedo
possível e a evitar regressões.
Dados de teste: Use dados de teste
realistas e representativos ao escrever seus testes de unidade e integração.
Isso ajuda a garantir que seus testes cubram uma variedade de cenários de uso da
API e identifiquem potenciais problemas antes de serem implantados em produção.
Testes de desempenho: Além dos testes funcionais, considere realizar testes
de desempenho para avaliar o desempenho da sua API REST em condições de carga e
estresse. Isso pode ajudar a identificar gargalos de desempenho e otimizar a sua
API conforme necessário.
Testes de segurança: Verifique se sua API REST
está protegida contra vulnerabilidades de segurança com testes de segurança
regulares. Isso pode incluir testes de segurança automatizados, revisões de
código e auditorias de segurança.
Conclusão:
Projetar boas APIs REST na plataforma .NET exige equilíbrio entre seguir a convenção arquitetural e manter o código limpo e idiomático. Ao adotar endpoints semânticos, status codes corretos, respostas de erro padronizadas com ProblemDetails e segurança desde o início, suas APIs ganham em robustez, escalabilidade e facilidade de integração.
E estamos conversados ...![]()
"Bendito seja o Deus e Pai de
nosso Senhor Jesus Cristo, o Pai das misericórdias e o Deus de toda a
consolação"
2
Coríntios 1:3
Referências: