//! Run with //! //! ```not_rust //! cargo run -p example-versioning //! ``` use axum::{ async_trait, extract::{FromRequestParts, Path}, http::{request::Parts, StatusCode}, response::{IntoResponse, Response}, routing::get, RequestPartsExt, Router, }; use std::{collections::HashMap, net::SocketAddr}; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; #[tokio::main] async fn main() { tracing_subscriber::registry() .with( tracing_subscriber::EnvFilter::try_from_default_env() .unwrap_or_else(|_| "example_versioning=debug".into()), ) .with(tracing_subscriber::fmt::layer()) .init(); // build our application with some routes let app = Router::new().route("/:version/foo", get(handler)); // run it let addr = SocketAddr::from(([127, 0, 0, 1], 3000)); tracing::debug!("listening on {}", addr); axum::Server::bind(&addr) .serve(app.into_make_service()) .await .unwrap(); } async fn handler(version: Version) { println!("received request with version {:?}", version); } #[derive(Debug)] enum Version { V1, V2, V3, } #[async_trait] impl FromRequestParts for Version where S: Send + Sync, { type Rejection = Response; async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result { let params: Path> = parts.extract().await.map_err(IntoResponse::into_response)?; let version = params .get("version") .ok_or_else(|| (StatusCode::NOT_FOUND, "version param missing").into_response())?; match version.as_str() { "v1" => Ok(Version::V1), "v2" => Ok(Version::V2), "v3" => Ok(Version::V3), _ => Err((StatusCode::NOT_FOUND, "unknown version").into_response()), } } }