axum
only.Expand description
Open API code generation for axum
.
The implementation closely mimics the api of axum
with
extra care taken in order to allow seamless transitions.
The notable types are ApiRouter
and ApiMethodRouter
that wrap
axum::Router
and axum::routing::MethodRouter
respectively.
Likewise, the top-level methods in axum::routing
have their counterparts
in routing
.
§Examples
Take the following axum
example:
use axum::{response::IntoResponse, routing::post, Json, Router};
use serde::Deserialize;
#[derive(Deserialize)]
struct User {
name: String,
}
async fn hello_user(Json(user): Json<User>) -> impl IntoResponse {
format!("hello {}", user.name)
}
#[tokio::main]
async fn main() {
let app = Router::new().route("/hello", post(hello_user));
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(listener, app).await.unwrap();
}
We can apply the following changes to generate documentation for it:
// Replace some of the `axum::` types with `aide::axum::` ones.
use aide::{
axum::{
routing::{get, post},
ApiRouter, IntoApiResponse,
},
openapi::{Info, OpenApi},
};
use axum::{Extension, Json};
use schemars::JsonSchema;
use serde::Deserialize;
// We'll need to derive `JsonSchema` for
// all types that appear in the api documentation.
#[derive(Deserialize, JsonSchema)]
struct User {
name: String,
}
async fn hello_user(Json(user): Json<User>) -> impl IntoApiResponse {
format!("hello {}", user.name)
}
// Note that this clones the document on each request.
// To be more efficient, we could wrap it into an Arc,
// or even store it as a serialized string.
async fn serve_api(Extension(api): Extension<OpenApi>) -> impl IntoApiResponse {
Json(api)
}
#[tokio::main]
async fn main() {
let app = ApiRouter::new()
// Change `route` to `api_route` for the route
// we'd like to expose in the documentation.
.api_route("/hello", post(hello_user))
// We'll serve our generated document here.
.route("/api.json", get(serve_api));
let mut api = OpenApi {
info: Info {
description: Some("an example API".to_string()),
..Info::default()
},
..OpenApi::default()
};
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
axum::serve(
listener,
app
// Generate the documentation.
.finish_api(&mut api)
// Expose the documentation to the handlers.
.layer(Extension(api))
.into_make_service(),
)
.await
.unwrap();
}
Only routes added via api_route
are visible in the documentation,
this makes exposed routes explicit and less error-prone.
§Adding details.
The above example includes routes and request parameters but it’s lacking response types and additional metadata such as descriptions, as these are not possible to infer just via types.
§Responses
Generally we can add information at the following levels:
- Operation level (e.g.
get_with
) - Route level (
api_route_with
) - API-level (
finish_api_with
)
All of these are additive and the API-level information will not override route or operation metadata unless explicitly stated.
With this being said, we can specify the response status code
and the type for our hello_user
operation:
// ...
.api_route(
"/hello",
post_with(hello_user, |op| op.response::<200, String>()),
)
// ...
And on the API-level we define that in every unspecified case, we return some kind of text:
// ...
app.finish_api_with(&mut api, |api| api.default_response::<String>())
// ...
§Other Metadata
We can extend our hello_user
operation with further metadata:
// ...
.api_route(
"/hello",
post_with(hello_user, |o| {
o.id("helloUser")
.description("says hello to the given user")
.response_with::<200, String, _>(|res| {
res.description("a simple message saying hello to the user")
.example(String::from("hello Tom"))
})
}),
)
// ...
§Composability
Just like in axum
, nesting and merging routers is possible,
and the documented routes will be updated as expected.
Modules§
- routing
- Method routing that closely mimics
axum::routing
while extending it with API documentation-specific features..
Structs§
- ApiRouter
- A wrapper over
axum::Router
that adds API documentation-specific features.
Traits§
- Axum
Operation Handler - A trait that extends
axum::handler::Handler
with API operation details. - Into
ApiResponse - A trait analogous to
IntoResponse
that allows writingimpl IntoApiResponse
for documented handlers. Axum’sIntoResponse
cannot be used for these handlers since the return type has to implementOperationOutput
. - Router
Ext - Convenience extension trait for
axum::Router
.