🦀 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
| Aspect | Benefit | Limitation |
|---|---|---|
| Extractors | Use actix's powerful extractors (Json, Query, Path, Auth) | Manual bridging to Bus required |
| Middleware | Leverage actix middleware ecosystem | Not visible in Ranvier Schematic |
| Business Logic | Ranvier transitions with Schematic visualization | Extra boilerplate for actix ↔ Ranvier integration |
| Performance | actix's proven HTTP performance + Ranvier logic | Minimal 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