# 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**:
```rust
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

```bash
# 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](https://docs.rs/axum/)
- `/crates/vapora-backend/src/main.rs` (router definition)
- `/crates/vapora-backend/Cargo.toml` (Axum dependency)

---

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