Vapora/docs/adrs/0002-axum-backend.md
Jesús Pérez 7110ffeea2
Some checks failed
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
chore: extend doc: adr, tutorials, operations, etc
2026-01-12 03:32:47 +00:00

3.3 KiB

ADR-002: Axum como Backend Framework

Status: Accepted | Implemented Date: 2024-11-01 Deciders: Backend Architecture Team Technical Story: Selecting REST API framework with optimal async/middleware composition for Tokio ecosystem


Decision

Usar Axum 0.8.6 como framework REST API (no Actix-Web, no Rocket) para exponer 40+ endpoints de VAPORA.


Rationale

  1. Composable Middleware: Tower ecosystem provides first-class composable middleware patterns
  2. Type-Safe Routing: Router defined as strong types (not string-based paths)
  3. Tokio Ecosystem: Built directly on Tokio (not abstraction layer), enabling precise async control
  4. Extractors: Powerful extractor system (Json, State, Path, custom extractors) reduces boilerplate
  5. Performance: Zero-copy response bodies, streaming support, minimal overhead

Alternatives Considered

Actix-Web

  • Mature framework with larger ecosystem
  • Cons: Actor model adds complexity, different async patterns than Tokio, harder to integrate with Tokio primitives

Rocket

  • Developer-friendly API
  • Cons: Synchronous-first (async as afterthought), less composable, worse error handling

Axum (CHOSEN)

  • Minimal abstraction over Tokio/Tower
  • Pros: Composable, type-safe, Tokio-native, growing ecosystem

Trade-offs

Pros:

  • Composable middleware (Tower trait-based)
  • Type-safe routing with strong types
  • Zero-cost abstractions, excellent performance
  • Perfect integration with Tokio async ecosystem
  • Streaming responses, WebSocket support built-in

Cons:

  • ⚠️ Smaller ecosystem than Actix-Web
  • ⚠️ Steeper learning curve (requires understanding Tower traits)
  • ⚠️ Fewer third-party integrations available

Implementation

Router Definition:

let app = Router::new()
    .route("/api/v1/projects", post(create_project).get(list_projects))
    .route("/api/v1/projects/:id", get(get_project).put(update_project))
    .route("/metrics", get(metrics_handler))
    .layer(TraceLayer::new_for_http())
    .layer(CorsLayer::permissive())
    .layer(Extension(Arc::new(app_state)));

let listener = TcpListener::bind("0.0.0.0:8001").await?;
axum::serve(listener, app).await?;

Key Files:

  • /crates/vapora-backend/src/main.rs:126-259 (router setup)
  • /crates/vapora-backend/src/api/ (handlers)
  • /crates/vapora-backend/Cargo.toml (dependencies)

Verification

# Build backend
cargo build -p vapora-backend

# Test API endpoints
cargo test -p vapora-backend -- --nocapture

# Run server and check health
cargo run -p vapora-backend &
curl http://localhost:8001/health
curl http://localhost:8001/metrics

Expected: 40+ endpoints accessible, health check responds 200 OK, metrics endpoint returns Prometheus format


Consequences

  • All HTTP handling must use Axum extractors (learning curve for team)
  • Request/response types must be serializable (integration with serde)
  • Middleware stacking order matters (defensive against bugs)
  • Easy to add WebSocket support later (Axum has built-in support)

References

  • Axum Documentation
  • /crates/vapora-backend/src/main.rs (router definition)
  • /crates/vapora-backend/Cargo.toml (Axum dependency)

Related ADRs: ADR-001 (Workspace), ADR-008 (Tokio)