axum-integration
Wires injectable with Axum handlers using Inject<T> as an extractor. Use when adding dependency injection to Axum routes, setting up AxumState or custom InjectableState, or getting handler extraction
SKILL.mdskills/axum-integration/SKILL.md
GitHubAxum Integration
Setup
use injectable::{prelude::*, axum::AxumState};
use axum::{routing::get, Router};
#[tokio::main]
async fn main() {
let container = Container::builder().build().await.unwrap();
let state = AxumState::new(container);
let app = Router::new()
.route("/users", get(list_users))
.with_state(state);
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
Handlers
use injectable::prelude::*;
// Inject<T> works like any Axum extractor
async fn list_users(
Inject(svc): Inject<UserService>, // destructure to get Arc<UserService>
db: Inject<Database>, // or keep as Inject<T>
) -> axum::Json<Vec<User>> {
axum::Json(svc.list().await.unwrap())
}
// Mix with other extractors
async fn create_user(
Inject(svc): Inject<UserService>,
axum::Json(body): axum::Json<CreateUserBody>,
) -> impl axum::response::IntoResponse { /* … */ }
Custom state
use injectable::axum::InjectableState;
#[derive(Clone)]
struct AppState {
container: Arc<Container>,
version: &'static str,
}
impl InjectableState for AppState {
fn resolve_context(&self) -> &ResolveContext {
self.container.context()
}
}
// Use AppState instead of AxumState:
let app = Router::new()
.route("/", get(handler))
.with_state(AppState { container: Arc::new(container), version: "1.0" });
Custom auth extractor
use axum::{async_trait, extract::FromRequestParts, http::request::Parts};
struct AuthUser { email: String }
#[async_trait]
impl FromRequestParts<AppState> for AuthUser {
type Rejection = StatusCode;
async fn from_request_parts(parts: &mut Parts, state: &AppState) -> Result<Self, StatusCode> {
let api_key = parts.headers.get("x-api-key")
.and_then(|v| v.to_str().ok())
.ok_or(StatusCode::UNAUTHORIZED)?;
let auth: Inject<AuthService> = Inject::extract(state.resolve_context())
.await.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
auth.validate(api_key).await
.map(|email| AuthUser { email })
.ok_or(StatusCode::UNAUTHORIZED)
}
}
See guides/07-axum-basics.md and guides/08-axum-custom-state.md.