Migrating from Actix-web
Migrating from Actix-web
Guide for developers migrating from Actix-web to Reinhardt.
Table of Contents
Handler Differences
Actix-web Handlers
use actix_web::{web, HttpResponse};
async fn get_user(path: web::Path<u32>) -> HttpResponse {
let user_id = path.into_inner();
HttpResponse::Ok().json(user_id)
}Reinhardt Handlers
use reinhardt::{Path, Response};
async fn get_user(Path(id): Path<u32>) -> Response {
Response::ok().with_json(&id).unwrap()
}
// Or implement Handler trait for stateful handlers
use reinhardt::Handler;
use async_trait::async_trait;
struct UserHandler {
// State
}
#[async_trait]
impl Handler for UserHandler {
async fn handle(&self, request: Request) -> Result<Response, Error> {
Ok(Response::ok())
}
}Extractors vs DI Params
Actix-web Extractors
use actix_web::{web, FromRequest};
#[derive(Deserialize)]
struct User {
username: String,
}
async fn create_user(user: web::Json<User>) -> HttpResponse {
HttpResponse::Ok().json(user)
}Reinhardt DI Params
use reinhardt::{Json, Path};
use serde::Deserialize;
#[derive(Deserialize)]
struct User {
username: String,
}
async fn create_user(
Json(user): Json<User>
) -> Response {
Response::ok().with_json(&user).unwrap()
}Middleware
Actix-web Middleware
use actix_web::{dev::Service, Error, HttpMessage};
struct LoggingMiddleware<S> {
service: S,
}
impl<S, B> Service<ServiceRequest<B>> for LoggingMiddleware<S>
where
S: Service<ServiceRequest<B>, B, Response = ServiceResponse<B, Error = Error>,
{
type Error = Error;
type Future = Next<S, B>;
fn call(&self, req: ServiceRequest<B>) -> Self::Future {
println!("Request: {:?}", req);
self.service.call(req)
}
}Reinhardt Middleware
use async_trait::async_trait;
use reinhardt::{Handler, Middleware, Request, Response};
pub struct LoggingMiddleware;
#[async_trait]
impl Middleware for LoggingMiddleware {
async fn process(&self, request: Request, next: Arc<dyn Handler>) -> Result<Response> {
println!("Request: {} {}", request.method, request.uri.path());
next.handle(request).await
}
}State Management
Actix-web State
use actix_web::{web, App, HttpServer};
struct AppState {
db: Database,
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let db = Database::new();
let app_state = web::Data::new(AppState { db });
HttpServer::new(move || {
App::new()
.app_data(app_state.clone())
.route("/users", web::get().to(get_users))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}Reinhardt DI Context
use reinhardt::di::{InjectionContext, SingletonScope};
use reinhardt::ServerRouter;
// Set up DI context
let singleton_scope = Arc::new(SingletonScope::new());
let di_ctx = Arc::new(InjectionContext::builder(singleton_scope)
.add_transient(Database::new())
.build());
// Register with router
let router = ServerRouter::new()
.with_di_context(di_ctx);
// Access in handler
async fn handler_with_di(req: Request) -> Response {
if let Some(db) = req.get_di_context::<Database>() {
// Use database
Response::ok()
} else {
Response::internal_server_error()
}
}Routing Patterns
Actix-web Routing
use actix_web::{web, App, HttpServer};
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.route("/users", web::get().to(get_users))
.route("/users", web::post().to(create_user))
.route("/users/{id}", web::get().to(get_user))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}Reinhardt Routing
use reinhardt::ServerRouter;
use hyper::Method;
let router = ServerRouter::new()
.function("/users", Method::GET, get_users)
.function("/users", Method::POST, create_user)
.function_named("/users/{id}", Method::GET, "user-detail", get_user);
// Or use Handler trait
let router = ServerRouter::new()
.handler_with_method("/users", Method::GET, GetUsersHandler);Response Building
Actix-web
use actix_web::{HttpResponse, http::StatusCode};
HttpResponse::Ok()
.content_type("application/json")
.json(data)
HttpResponse::Created()
.content_type("application/json")
.json(data)
HttpResponse::NotFound()
.json(serde_json::json!({
"error": "Not found"
}))Reinhardt
use reinhardt::Response;
Response::ok()
.with_json(&data)
.unwrap()
Response::created()
.with_json(&data)
.unwrap()
Response::not_found()
.with_json(&serde_json::json!({
"error": "Not found"
}))
.unwrap()Shared State
Actix-web
// Using web::Data
async fn handler(
db: web::Data<Arc<Database>>,
) -> HttpResponse {
let users = db.get_users().await;
HttpResponse::Ok().json(users)
}Reinhardt
// Using DI context via request
async fn handler(req: Request) -> Response {
if let Some(db) = req.get_di_context::<Database>() {
let users = db.get_users().await;
Response::ok().with_json(&users).unwrap()
} else {
Response::internal_server_error()
}
}Migration Checklist
- Convert handlers to
Handlertrait or functions - Replace extractors with DI params (
Json,Path,Query, etc.) - Convert middleware to
Middlewaretrait - Replace
web::Datawith DI context - Convert routing configuration to
ServerRouter - Update response building
- Add error handling
- Test changes