Estratégia de Erro
Erros de camada: enums precisos no domínio interno, mapeamento de transporte nas bordas, agregação de contexto em binários.
Receita
// domínio
pub enum OrderError { NotFound(OrderId), InvalidState }
// api
impl IntoResponse for ApiError {
fn into_response(self) -> Response { /* status + body */ }
}Quando usar isso: Mais de um crate ou superfície de API externa.
Exemplo de Trabalho
Requisição do usuário -> ApiError -> OrderError -> sqlx::Error
- O domínio retorna
Result<T, OrderError> - A infraestrutura implementa o mapeamento de
sqlx::ErrorparaOrderError::Database - A API mapeia
OrderErrorpara404/409com problem+json mainusaanyhowapenas para erros de banner de inicialização
O que isso demonstra:
- Variantes se alinham com casos de negócios, não com strings de driver
#[from]para tradução de infraestrutura uma vez- O corpo HTTP público difere dos logs de Debug internos
Análise Detalhada
Crate error opcional no workspace para um wrapper compartilhado AppError. Use #[non_exhaustive] em enums públicos.
Armadilhas
- Vazamento de sqlx para handlers - acoplamento. Correção: mapear na fronteira do repositório.
- Um único enum de Erro gigante - incontrolável. Correção: enum por contexto delimitado.
- Exibição como contrato de API - dor de i18n. Correção: códigos de erro estáveis em JSON.
- anyhow em biblioteca - evitar.
- panic no mapper - variantes inalcançáveis devem ser tratadas com
#[non_exhaustive].
Alternativas
| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| snafu | crates de erro com contexto | padrão da equipe thiserror |
| Apenas StatusCode | ferramentas internas | API Pública |
FAQs
mapeamento de retry?
Marque OrderError::Transient para retentativa de middleware.
mapeamento grpc?
tonic::Status a partir de uma tabela de variantes do domínio.
SDK do cliente?
Exportar enum de código de erro estável espelhando o servidor.
níveis de log?
4xx warn, 5xx error, com trace id.
mapeamento de teste?
Testes de tabela de variantes -> status.
erros serde?
Separar DeserializationError na fronteira antes do domínio.
múltiplas apis?
ApiError compartilhado no crate da api reexportado.
domínio no_std?
Implementações manuais do trait core::error::Error.
observabilidade?
tracing::error!(error=?e) no caminho 5xx.
migração?
Adicionar variantes sem quebrar com non_exhaustive.
Relacionados
- Regras de Tratamento de Erro
- Tratamento de Erro em Handlers
- thiserror
- Melhores Práticas de Arquitetura
Versões da Pilha: Esta página foi escrita para Rust 1.97.0 (edição 2024), Tokio 1.x, Axum 0.8, serde 1.0, sqlx 0.8, clap 4, e Polars 0.46+.