Estrutura ideal para serviços web em Rust
Guia prático para estruturar serviços web Rust com arquitetura limpa, workspaces Cargo e crates modulares.
Organizar um serviço web Rust de forma eficaz é tão importante quanto o código em si. Uma boa estrutura proporciona builds mais rápidos, testes simplificados e refatorações mais seguras. Este guia apresenta padrões práticos, desde pequenas APIs a backends de produção, otimizados para clareza, modularidade e crescimento a longo prazo.
Por que a estrutura do projeto importa
- Builds mais rápidos: módulos e crates bem definidos reduzem recompilações desnecessárias.
- Clareza para a equipe: limites e nomenclaturas consistentes ajudam os colaboradores a encontrar código rapidamente.
- Dependências mais limpas: regras de visibilidade e traits facilitam a gestão de dependências.
- Testabilidade: interfaces claras tornam os testes unitários, de integração e end-to-end mais fáceis.
- Preparação para o futuro: a estrutura absorve o crescimento de funcionalidades e mudanças de frameworks.
Conceitos centrais na organização de projetos Rust
Workspaces Cargo
Utilize um workspace para agrupar crates relacionadas (API, domínio, infraestrutura, compartilhados), compartilhar versões e manter as preocupações separadas.
# Cargo.toml (raiz do workspace) [workspace] members = ["api", "domain", "infrastructure", "shared"] [workspace.dependencies] tokio = { version = "1.0", features = ["full"] } serde = { version = "1.0", features = ["derive"] }
- Ideal para aplicativos grandes, microsserviços, bibliotecas compartilhadas ou equipes múltiplas.
Módulos & Visibilidade
Exponha apenas o necessário, mantendo detalhes de implementação privados e agrupando itens relacionados em módulos.
// lib.rs pub mod api; pub mod domain; mod internal; // api/mod.rs pub mod v1; mod middleware; // domain/mod.rs pub mod models; pub mod services; mod repositories;
pub(público),pub(crate)(todo o crate),pub(super)(pai), padrão privado.
Padrões de estrutura de projeto
1) Serviço web básico (Pequenas APIs, PoCs)
my-service/ ├── Cargo.toml ├── src/ │ ├── main.rs │ ├── lib.rs │ ├── config/ │ ├── handlers/ │ ├── models/ │ ├── services/ │ └── utils/ ├── tests/ └── README.md
Exemplo: ponto de entrada delegando para código da biblioteca.
use my_service::config::AppConfig; use my_service::handlers::create_app; #[tokio::main] async fn main() { let config = AppConfig::from_env(); let app = create_app(config).await; axum::Server::bind(&&"0.0.0.0:3000".parse().unwrap()) .serve(app.into_make_service()) .await .unwrap(); }
- Prós: fácil de entender, testável, ideal para serviços de único propósito.
2) Estrutura avançada multi-módulo (Apps maiores)
Adote arquitetura limpa: separe API, domínio, infraestrutura e crates ou módulos compartilhados.
src/ ├── api/ # Camada HTTP e roteamento ├── domain/ # Entidades, serviços, repositórios (traits) ├── infrastructure/ # BD, clientes externos, config, logging └── shared/ # Erros, tipos, helpers
- Fluxo de dependência:
api → domain;infrastructure → domain;sharedé reutilizável. - Domínio sem dependências de frameworks externos ou BD.
Arquitetura limpa em Rust
- Domínio: entidades, objetos de valor, traits de repositório, serviços de domínio.
- Aplicação: orquestra casos de uso, DTOs, transações, CQRS.
- Infraestrutura: implementações de BD, APIs externas, configuração, observabilidade.
- Apresentação: roteamento HTTP, handlers, middleware, validação.
Rust recompensa a estruturação cuidadosa. Comece simples e evolua para uma arquitetura limpa conforme as necessidades crescem. Mantenha a lógica de domínio independente, use traits para desacoplar implementações, confie em workspaces para escalabilidade e invista cedo em testes e observabilidade. Faça melhorias incrementais, documente decisões e deixe a estrutura trabalhar a seu favor.