🦀 actix-web Integration Guide

Use Ranvier transitions in actix-web handlers

Overview

actix-web is a powerful, pragmatic, and extremely fast web framework for Rust. You can integrate Ranvier transitions into actix handlers to leverage both frameworks' strengths:

  • actix-web: Extractors, middleware, robust HTTP handling
  • Ranvier: Schematic visualization, Bus propagation, composable logic

Integration Pattern

The recommended approach is to call Ranvier transitions from within actix handlers:

Example: Calling Ranvier Transition from actix Handler

use actix_web::{{web, HttpRequest, HttpResponse}};
use ranvier_core::{{Bus, Outcome}};
use ranvier_macros::transition;
use ranvier_runtime::Axon;

// Define your Ranvier transition
#[transition]
async fn process_order(
    order: Order,
    _res: &(),
    bus: &mut Bus
) -> Outcome<OrderResult, AppError> {{
    // Your business logic here
    Outcome::Next(OrderResult {{ id: order.id, status: "processed" }})
}}

// actix handler
async fn create_order(
    req: HttpRequest,
    order: web::Json<Order>,
    pipeline: web::Data<Axon<Order, OrderResult, AppError, ()>>
) -> HttpResponse {{
    let mut bus = Bus::new();

    // Optional: Extract auth from request and put in Bus
    if let Some(auth) = req.extensions().get::<AuthContext>() {{
        bus.insert(auth.clone());
    }}

    // Execute Ranvier pipeline
    match pipeline.execute(order.into_inner(), &(), &mut bus).await {{
        Outcome::Next(result) => HttpResponse::Ok().json(result),
        Outcome::Fault(err) => HttpResponse::BadRequest().json(err),
        _ => HttpResponse::InternalServerError().finish(),
    }}
}}

// actix app setup
#[actix_web::main]
async fn main() -> std::io::Result<()> {{
    let pipeline = Axon::simple::<AppError>("order-pipeline")
        .then(process_order);

    HttpServer::new(move || {{
        App::new()
            .app_data(web::Data::new(pipeline.clone()))
            .route("/orders", web::post().to(create_order))
    }})
    .bind(("127.0.0.1", 8080))?
    .run()
    .await
}}

Example: Using actix Extractors with Ranvier

use actix_web::{{web, HttpResponse, Responder}};
use actix_web_httpauth::extractors::bearer::BearerAuth;

async fn protected_handler(
    auth: BearerAuth,  // actix extractor
    data: web::Json<RequestData>,
    pipeline: web::Data<Axon<RequestData, ResponseData, AppError, ()>>
) -> impl Responder {{
    let mut bus = Bus::new();

    // Put extracted token in Bus for Ranvier transitions
    bus.insert(auth.token().to_string());

    match pipeline.execute(data.into_inner(), &(), &mut bus).await {{
        Outcome::Next(result) => HttpResponse::Ok().json(result),
        Outcome::Fault(err) => HttpResponse::Unauthorized().json(err),
        _ => HttpResponse::InternalServerError().finish(),
    }}
}}

When to Use This Approach

✅ Good for:

  • Existing actix-web apps adding Ranvier for complex business logic
  • Teams familiar with actix extractors and middleware
  • Need actix's performance for HTTP handling
  • Want Ranvier's Schematic visualization for business workflows

⚠️ Consider:

  • Context bridging: You need to manually bridge actix request context (extractors) to Ranvier Bus
  • Middleware visibility: actix middleware won't appear in Ranvier Schematic
  • Testing: actix integration tests needed (unit test Ranvier transitions separately)

Trade-offs

AspectBenefitLimitation
ExtractorsUse actix's powerful extractors (Json, Query, Path, Auth)Manual bridging to Bus required
MiddlewareLeverage actix middleware ecosystemNot visible in Ranvier Schematic
Business LogicRanvier transitions with Schematic visualizationExtra boilerplate for actix ↔ Ranvier integration
Performanceactix's proven HTTP performance + Ranvier logicMinimal overhead from context bridging

Comparison with Alternatives

  • vs Pure Ranvier: actix integration gives you actix extractors/middleware, but loses some Schematic visibility
  • vs Tower Integration: Similar pattern, but actix has different extractor model (function parameters vs request.extensions)
  • vs Axum Integration: actix uses trait-based extractors, Axum uses type-based extractors

Next Steps

Note: A complete actix-web + Ranvier example is planned for a future milestone. For now, use the code snippets above as a starting point.

To learn more about integration patterns: