Modele recursos e operações HTTP
Use caminhos que representem recursos, como /api/pedidos e /api/pedidos/{id}, e métodos HTTP para expressar a operação: GET consulta, POST cria, PUT substitui, PATCH altera parcialmente e DELETE remove. Mantenha nomes e formatos coerentes; não transforme cada verbo de negócio em uma rota sem considerar o recurso e seu contrato.
Respeite a semântica de cada método. GET deve ser seguro e não provocar mudanças; PUT e DELETE são idempotentes pela semântica HTTP, embora a implementação precise preservar esse comportamento. POST pode exigir uma chave de idempotência quando clientes podem repetir uma solicitação após timeout.
Separe o contrato HTTP do domínio
Receba e devolva DTOs próprios da API, em vez de expor entidades de persistência. Isso reduz acoplamento, evita publicar campos internos acidentalmente e permite validar o formato de entrada. Valide limites e formato na borda; regras de negócio e invariantes continuam no domínio ou na aplicação.
app.MapPost("/api/pedidos", async (
CriarPedidoRequest request,
IPedidoService pedidos,
CancellationToken cancellationToken) =>
{
if (request.Itens.Count == 0)
return Results.ValidationProblem(new Dictionary<string, string[]>
{
["itens"] = ["Inclua ao menos um item."]
});
var criado = await pedidos.CriarAsync(request, cancellationToken);
return Results.Created($"/api/pedidos/{criado.Id}", criado);
});O exemplo é um recorte: a aplicação também deve limitar quantidades e tamanhos, tratar autorização e aplicar as regras do caso de uso. Não confie em validação feita apenas pelo cliente.
Escolha respostas HTTP que comuniquem o resultado
Retorne 201 Created ao criar um recurso e, quando apropriado, inclua seu endereço em Location; 200 para uma resposta com representação; 204 quando não há corpo; 400 para entrada inválida; 401 quando falta autenticação; 403 quando a identidade não tem permissão; 404 para recurso ausente e 409 para conflito de estado. Não use 200 com uma mensagem de erro no corpo.
Configure respostas de erro consistentes, por exemplo com AddProblemDetails e tratamento de exceções do ASP.NET Core. Não exponha stack traces, SQL, tokens nem mensagens internas. Registre contexto seguro nos logs e devolva ao cliente apenas detalhes apropriados.
Paginação, filtros e limites
Uma coleção não deve retornar um volume ilimitado de registros. Defina paginação com tamanho máximo controlado pelo servidor, ordenação estável e filtros documentados. Offset é simples para conjuntos menores; cursores/keyset podem funcionar melhor em listas grandes e mutáveis. Seja explícito sobre o formato de metadados e o que acontece quando um filtro é inválido.
Evolua o contrato sem quebrar clientes
Adicionar campos opcionais costuma ser mais compatível que renomear ou mudar o significado de campos existentes. Para mudanças incompatíveis, estabeleça uma estratégia de versão e um período de migração observável. Documente exemplos e erros, use testes de contrato quando produtor e consumidores evoluem separadamente e evite versionar toda mudança aditiva.
Autenticação e autorização devem ser aplicadas no servidor, por políticas e permissões adequadas ao recurso — veja autenticação e autorização em ASP.NET Core. Teste o pipeline HTTP com testes de integração.