Migrating from Axum
Migrating from Axum
Guide for developers migrating from Axum to Reinhardt.
Table of Contents
Handler Differences
Axum Handlers
use axum::{
extract::{Path, Query},
Json, response::Json,
};
async fn get_user(
Path(id): Path<u32>,
Query(params): Query<Params>,
) -> Json<User> {
let user = fetch_user(id, params).await;
Json(user)
}Reinhardt Handlers
use reinhardt::{Path, Query};
use reinhardt::Response;
async fn get_user(
Path(id): Path<u32>,
Query(params): Query<Params>,
) -> Response {
let user = fetch_user(id, params).await;
Response::ok().with_json(&user).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())
}
}State vs DI Context
Axum State
use axum::{
extract::State,
response::Json,
};
use std::sync::Arc;
struct AppState {
db: Arc<Database>,
};
async fn get_user(
State(state): State<Arc<AppState>>,
) -> Json<User> {
let user = state.db.get_user(123).await;
Json(user)
}Reinhardt DI Context
use reinhardt::Response;
// Get dependencies from request via DI context
async fn get_user(req: Request) -> Response {
if let Some(db) = req.get_di_context::<Database>() {
let user = db.get_user(123).await;
Response::ok().with_json(&user).unwrap()
} else {
Response::internal_server_error()
}
}Layer vs Middleware
Axum Layers
use axum::{
routing::get,
Router,
Layer,
middleware::Logger,
};
let app = Router::new()
.route("/users", get(handler))
.layer(Logger::new());Reinhardt Middleware
use reinhardt::ServerRouter;
use reinhardt::LoggingMiddleware;
let router = ServerRouter::new()
.with_middleware(LoggingMiddleware::new())
.function("/users", Method::GET, handler);Router Differences
Axum Router
use axum::{
routing::get,
Router,
Json,
};
let app = Router::new()
.route("/users", get(get_users))
.route("/users", post(create_user))
.route("/users/:id", get(get_user));Reinhardt Router
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);Extractors
Axum Extractors
use axum::{
extract::{Path, Query, Json},
response::Json,
};
async fn handler(
Path(id): Path<u32>,
Query(params): Query<Params>,
Json(data): Json<Data>,
) -> Json<Response> {
// ...
}Reinhardt DI Params
use reinhardt::{Path, Query, Json};
use reinhardt::Response;
async fn handler(
Path(id): Path<u32>,
Query(params): Query<Params>,
Json(data): Json<Data>,
) -> Response {
// ...
}Available extractors in Reinhardt:
Json<T>- JSON bodyForm<T>- Form dataQuery<T>- Query parametersPath<T>- Path parametersBody- Raw body bytesMultipart- Multipart form dataHeader<T>- Typed headerHeaderNamed- Named header
Response Building
Axum
use axum::{
extract::Path,
Json,
response::{Html, IntoResponse, Json},
};
async fn get_user(Path(id): Path<u32>) -> impl IntoResponse {
let user = fetch_user(id).await;
Json(user)
}Reinhardt
use reinhardt::Path;
use reinhardt::Response;
async fn get_user(Path(id): Path<u32>) -> Response {
let user = fetch_user(id).await;
Response::ok().with_json(&user).unwrap()
}Error Handling
Axum
use axum::{
response::{IntoResponse, Response},
Json,
http::StatusCode,
};
impl IntoResponse for AppError {
fn into_response(self) -> Response {
let (status, message) = match self {
AppError::NotFound => (StatusCode::NOT_FOUND, "Not found"),
AppError::InternalError => (StatusCode::INTERNAL_SERVER_ERROR, "Internal error"),
};
(status, Json(serde_json::json!({ "error": message }))).into_response()
}
}Reinhardt
use reinhardt::{Error, Response};
impl From<AppError> for Response {
fn from(err: AppError) -> Self {
match err {
AppError::NotFound => Response::not_found(),
AppError::InternalError => Response::internal_server_error(),
}
}
}Middleware Creation
Axum Tower Middleware
use axum::{
extract::Request,
response::Response,
};
use tower::{ServiceBuilder, ServiceExt};
use http::StatusCode;
async fn middleware(request: Request, next: Next) -> Response {
println!("Request: {:?}", request.uri());
next.run(request).await
}
let app = Router::new()
.route("/users", get(handler))
.layer(middleware);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
}
}Migration Checklist
- Convert handlers to
Handlertrait or functions - Replace State with DI context
- Replace layers with middleware
- Convert routing configuration
- Update extractors to DI params
- Update error handling
- Add tests