Tower para Rust: guia completo com exemplos

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

O que é Tower e para que serve?

\n\n

Tower é uma biblioteca fundamental do ecossistema Rust que fornece abstrações para construir serviços de rede modulares, compostos e assíncronos e middleware. Ela não é um framework HTTP pronto (como Actix-web ou Axum), mas sim um "material de construção" para eles. Axum, por exemplo, é construído sobre Tower.

\n\n

A ideia principal do Tower é a trait Service, que representa uma função assíncrona que transforma uma requisição (Request) em uma resposta (Response). Middleware (ou "Layer") no Tower é uma forma de encapsular um serviço dentro de outro, adicionando comportamento extra (logging, autenticação, timeouts, balanceamento de carga, etc.) sem modificar o código original do serviço.

\n\n

Para que serve?

\n
    \n
  • Modularidade: Você pode dividir a lógica complexa de processamento de requisições em componentes pequenos, independentes e reutilizáveis (serviços e middleware).
  • \n
  • Composição: Middleware pode ser facilmente combinado, "empilhando" uns sobre os outros como camadas (layers).
  • \n
  • Assincronia: Tower é projetada para funcionar com Rust assíncrono (tokio, async-std) e suporta futures.
  • \n
  • Testabilidade: Cada componente pode ser testado isoladamente.
  • \n
\n\n

Instalação do Tower

\n\n

Tower é uma biblioteca Rust, portanto é instalada através do gerenciador de pacotes Cargo. Adicione a dependência ao seu arquivo Cargo.toml:

\n\n
[dependencies]\ntower = { version = "0.4", features = ["full"] } # "full" inclui todos os recursos\ntokio = { version = "1", features = ["full"] } # Para o runtime assíncrono\n
\n\n

Depois disso, execute o comando no terminal:

\n
cargo build
\n\n

A biblioteca será baixada e compilada junto com seu projeto.

\n\n

Início rápido: Seu primeiro serviço e middleware

\n\n

Vamos criar um serviço simples que recebe uma string e a retorna em maiúsculas. Em seguida, vamos encapsulá-lo em um middleware que registra (log) cada requisição.

\n\n
use std::convert::Infallible;\nuse std::task::{Context, Poll};\nuse tower::{Service, Layer, ServiceBuilder};\nuse tower::layer::util::Identity;\nuse std::future::{Ready, ready};\n\n// 1. Definindo nosso serviço\n#[derive(Clone)]\nstruct MyService;\n\nimpl<Request> Service<Request> for MyService {\n    type Response = String;\n    type Error = Infallible;\n    type Future = Ready<Result<Self::Response, Self::Error>>;\n\n    fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        Poll::Ready(Ok(()))\n    }\n\n    fn call(&mut self, req: Request) -> Self::Future {\n        // Simplesmente retorna uma string\n        ready(Ok(format!("Olá do serviço! Requisição: {:?}", std::any::type_name::<Request>())))\n    }\n}\n\n// 2. Definindo middleware para logging\n#[derive(Clone)]\nstruct LogMiddleware;\n\nimpl<S> Layer<S> for LogMiddleware {\n    type Service = LogService<S>;\n\n    fn layer(&self, inner: S) -> Self::Service {\n        LogService { inner }\n    }\n}\n\n#[derive(Clone)]\nstruct LogService<S> {\n    inner: S,\n}\n\nimpl<S, Request> Service<Request> for LogService<S>\nwhere\n    S: Service<Request>,\n    S::Future: std::marker::Send,\n    Request: std::fmt::Debug,\n{\n    type Response = S::Response;\n    type Error = S::Error;\n    type Future = S::Future;\n\n    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {\n        self.inner.poll_ready(cx)\n    }\n\n    fn call(&mut self, req: Request) -> Self::Future {\n        printl                    

Recommendations