Recipe

Axum (Rust) primer

Axum is a fast, ergonomic web framework built on Tokio and Tower. This primer walks you through wiring an Axum service that proxies prompts into the Meridian gateway, with typed handlers, shared state, and the minimum middleware you need for a production deploy.

1. Install and pin dependencies

Axum versions move quickly. Pin the major+minor in Cargo.tomland use tokio with the full feature set while you iterate. Trim features before you ship.

# Cargo.toml
[dependencies]
axum = "0.7"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
tower = "0.4"
tower-http = { version = "0.5", features = ["trace", "cors"] }

2. Define typed handlers with shared state

Axum extractors turn request bodies, query strings, and shared state into function arguments. Keep your AppState cheap to clone (wrap heavyweight resources in Arc) and return concrete types so OpenAPI generators can introspect the surface.

use axum::{
    routing::{get, post},
    Router, Json, extract::State,
};
use serde::{Deserialize, Serialize};
use std::sync::Arc;

#[derive(Clone)]
struct AppState {
    api_key: Arc<String>,
}

#[derive(Deserialize)]
struct ChatRequest { model: String, prompt: String }

#[derive(Serialize)]
struct ChatResponse { id: String, output: String }

async fn health() -> &'static str { "ok" }

async fn chat(
    State(state): State<AppState>,
    Json(req): Json<ChatRequest>,
) -> Json<ChatResponse> {
    let _ = state.api_key;
    Json(ChatResponse {
        id: "msg_01".into(),
        output: format!("echo[{}]: {}", req.model, req.prompt),
    })
}

#[tokio::main]
async fn main() {
    let state = AppState { api_key: Arc::new(std::env::var("MERIDIAN_KEY").unwrap_or_default()) };
    let app = Router::new()
        .route("/health", get(health))
        .route("/v1/chat", post(chat))
        .with_state(state);

    let listener = tokio::net::TcpListener::bind("0.0.0.0:8080").await.unwrap();
    axum::serve(listener, app).await.unwrap();
}

3. Layer middleware and deploy

Compose tower-http layers for tracing, CORS, and timeouts. For Meridian-backed services we recommend a 30s upstream timeout, a request-id layer keyed on x-request-id, and a graceful shutdown on SIGTERM so the container exits cleanly during rolling deploys.