Skip to main content

Actix Web | Packages | Rust

  • Actix Web | Packages | Rust

Actix Web (Rust)

Image

Image

Image

Image

1. Visão Geral

Actix Web é um framework web de alta performance para Rust, construído sobre o runtime assíncrono do ecossistema Rust (baseado em tokio). É amplamente utilizado para:

  • APIs REST de alta concorrência
  • Microsserviços
  • Gateways HTTP
  • Backends com baixa latência

Características técnicas relevantes:

  • Modelo actor-based (derivado do ecossistema Actix)
  • Execução assíncrona (async/await)
  • Alto throughput (comparável a frameworks como FastAPI e Express, porém com footprint menor)
  • Forte tipagem em handlers e middlewares
  • Sistema robusto de extração de dados (extractors)

2. Estrutura Básica de Projeto

Criação

cargo new actix_api
cd actix_api

Cargo.toml

[dependencies]
actix-web = "4"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
env_logger = "0.11"

3. Servidor HTTP Mínimo

use actix_web::{get, App, HttpServer, Responder};

#[get("/")]
async fn index() -> impl Responder {
"API online"
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(index)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}

Conceitos importantes

  • #[get("/")]: macro para registrar rota
  • Responder: trait que converte retorno em HttpResponse
  • HttpServer::new: cria pool de workers (por padrão = número de CPUs)
  • .run().await: inicia runtime async

4. API REST Realista (CRUD)

Modelo

use serde::{Deserialize, Serialize};

#[derive(Serialize, Deserialize, Clone)]
struct User {
id: u32,
name: String,
}

Estado Compartilhado (App State)

use std::sync::Mutex;

struct AppState {
users: Mutex<Vec<User>>,
}

CREATE (POST)

use actix_web::{post, web, HttpResponse};

#[post("/users")]
async fn create_user(
data: web::Data<AppState>,
payload: web::Json<User>,
) -> HttpResponse {
let mut users = data.users.lock().unwrap();
users.push(payload.into_inner());

HttpResponse::Created().finish()
}

READ (GET ALL)

use actix_web::{get, web, HttpResponse};

#[get("/users")]
async fn list_users(data: web::Data<AppState>) -> HttpResponse {
let users = data.users.lock().unwrap();
HttpResponse::Ok().json(users.clone())
}

READ (GET BY ID)

#[get("/users/{id}")]
async fn get_user(
data: web::Data<AppState>,
path: web::Path<u32>,
) -> HttpResponse {
let users = data.users.lock().unwrap();
let id = path.into_inner();

if let Some(user) = users.iter().find(|u| u.id == id) {
HttpResponse::Ok().json(user)
} else {
HttpResponse::NotFound().finish()
}
}

Configuração Completa

use actix_web::{App, HttpServer, web};

#[actix_web::main]
async fn main() -> std::io::Result<()> {
let state = web::Data::new(AppState {
users: Mutex::new(vec![]),
});

HttpServer::new(move || {
App::new()
.app_data(state.clone())
.service(create_user)
.service(list_users)
.service(get_user)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}

5. Extractors (Extração Tipada)

Actix utiliza o conceito de extractors para injetar dados automaticamente no handler.

Tipos comuns:

ExtractorUso
web::Json<T>Body JSON
web::Path<T>Parâmetros de rota
web::Query<T>Query string
web::Data<T>Estado global
HttpRequestRequest completo

Exemplo Query String

use serde::Deserialize;

#[derive(Deserialize)]
struct Pagination {
page: u32,
limit: u32,
}

#[get("/items")]
async fn list_items(query: web::Query<Pagination>) -> HttpResponse {
HttpResponse::Ok().body(format!(
"Page: {}, Limit: {}",
query.page, query.limit
))
}

6. Middleware

Middleware intercepta requests/responses.

Logger

use actix_web::middleware::Logger;

HttpServer::new(|| {
App::new()
.wrap(Logger::default())
})

Ativar:

RUST_LOG=info cargo run

7. Tratamento de Erros Customizado

use actix_web::{ResponseError, HttpResponse};
use thiserror::Error;

#[derive(Error, Debug)]
enum ApiError {
#[error("Usuário não encontrado")]
NotFound,
}

impl ResponseError for ApiError {
fn error_response(&self) -> HttpResponse {
match self {
ApiError::NotFound => HttpResponse::NotFound().body(self.to_string()),
}
}
}

Uso:

async fn example() -> Result<HttpResponse, ApiError> {
Err(ApiError::NotFound)
}

8. Integração com Banco (Exemplo com SQLx)

sqlx = { version = "0.7", features = ["runtime-tokio", "postgres"] }
use sqlx::PgPool;

struct AppState {
db: PgPool,
}

Query real:

let user = sqlx::query_as!(
User,
"SELECT id, name FROM users WHERE id = $1",
user_id
)
.fetch_one(&data.db)
.await?;

9. Performance e Arquitetura

Modelo de Concorrência

  • Worker threads independentes
  • Event loop async
  • Sem GC
  • Uso extensivo de zero-cost abstractions

Quando usar

✔ APIs de alta performance ✔ Microservices ✔ Sistemas com alta concorrência

Quando não usar

✖ Protótipos rápidos (complexidade maior que Node) ✖ Equipe sem familiaridade com Rust


10. Organização Recomendada de Projeto

src/
├── main.rs
├── handlers/
├── models/
├── errors/
├── services/
└── routes.rs

Separar:

  • Lógica de negócio (services)
  • Handlers HTTP
  • Modelos
  • Camada de persistência

11. Comparação Conceitual

FrameworkLinguagemModeloPerformance
Actix WebRustAsync + ActorsMuito alta
AxumRustTower + AsyncAlta
ExpressNodeEvent LoopMédia
FastAPIPythonAsyncAlta