rust 71 lines · 8 steps

Self-documenting routes in Axum

A builder wraps Axum's Router to record every route's metadata and expose it as an /openapi.json endpoint.

Explained by highlit
1use axum::{
2 extract::State,
3 routing::{get, post, MethodRouter},
4 Json, Router,
5};
6use serde::Serialize;
7use std::sync::Arc;
8 
9#[derive(Clone, Serialize)]
10struct RouteInfo {
11 method: &'static str,
12 path: String,
13 summary: &'static str,
14}
15 
16#[derive(Clone, Default)]
17struct ApiCatalog {
18 routes: Vec<RouteInfo>,
19}
20 
21struct DocumentedRouter<S> {
22 router: Router<S>,
23 catalog: ApiCatalog,
24}
25 
26impl<S> DocumentedRouter<S>
27where
28 S: Clone + Send + Sync + 'static,
29{
30 fn new() -> Self {
31 Self {
32 router: Router::new(),
33 catalog: ApiCatalog::default(),
34 }
35 }
36 
37 fn route(
38 mut self,
39 method: &'static str,
40 path: &str,
41 summary: &'static str,
42 handler: MethodRouter<S>,
43 ) -> Self {
44 self.catalog.routes.push(RouteInfo {
45 method,
46 path: path.to_string(),
47 summary,
48 });
49 self.router = self.router.route(path, handler);
50 self
51 }
52 
53 fn finish(self) -> Router<S> {
54 let catalog = Arc::new(self.catalog);
55 self.router.route(
56 "/openapi.json",
57 get(move || {
58 let catalog = Arc::clone(&catalog);
59 async move { Json(catalog.routes.clone()) }
60 }),
61 )
62 }
63}
64 
65pub fn build_api() -> Router {
66 DocumentedRouter::new()
67 .route("GET", "/users", "List all users", get(list_users))
68 .route("POST", "/users", "Create a user", post(create_user))
69 .route("GET", "/users/:id", "Fetch a single user", get(show_user))
70 .finish()
71}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Wrapping a framework type lets you capture side metadata every time you call its methods.
  2. 2A move closure that clones an Arc gives each request cheap shared access to immutable data.
  3. 3Threading self through builder methods keeps route registration and documentation in a single fluent chain.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Self-documenting routes in Axum — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code