Skip to content

Commit

Permalink
Add utoipa axum bindings (#1004)
Browse files Browse the repository at this point in the history
This PR adds a new crate `utoipa-axum` which provides bindings between
`axum` and `utoipa`. It aims to blend as much as possible to the
existing philosophy of axum way of registering handlers.

This commit introduces new `OpenApiRouter` what wraps `OpenApi` and axum
`Router` which provides passthrough implementation for most of the axum
Router methods and collects and combines the `OpenApi` from registered
routes. Routes registred only via `routes!()` macro will get added to
the `OpenApi`.

Also this commit introduces `routes!()` macro which collects axum
handlers annotated with `#[utoipa::path()]` attribute macro to single
paths intance which is then provided to the `OpenApiRouter`.

Example of supported sytanx.
```rust
let user_router: OpenApiRouter = OpenApiRouter::new()
    .routes(routes!(search_user))
    .routes(routes!(get_user, post_user, delete_user));
```

Fixes #991
  • Loading branch information
juhaku committed Aug 26, 2024
1 parent f2a7143 commit a0db8b9
Show file tree
Hide file tree
Showing 18 changed files with 808 additions and 53 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ jobs:
- utoipa-redoc
- utoipa-rapidoc
- utoipa-scalar
- utoipa-axum
fail-fast: true
runs-on: ubuntu-latest

Expand Down Expand Up @@ -62,6 +63,8 @@ jobs:
changes=true
elif [[ "$change" == "utoipa-scalar" && "${{ matrix.crate }}" == "utoipa-scalar" && $changes == false ]]; then
changes=true
elif [[ "$change" == "utoipa-axum" && "${{ matrix.crate }}" == "utoipa-axum" && $changes == false ]]; then
changes=true
fi
done < <(git diff --name-only ${{ github.sha }}~ ${{ github.sha }} | grep .rs | awk -F \/ '{print $1}')
echo "${{ matrix.crate }} changes: $changes"
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ members = [
"utoipa-redoc",
"utoipa-rapidoc",
"utoipa-scalar",
"utoipa-axum",
]

[workspace.metadata.publish]
Expand All @@ -22,4 +23,5 @@ order = [
"utoipa-redoc",
"utoipa-rapidoc",
"utoipa-scalar",
"utoipa-axum",
]
4 changes: 3 additions & 1 deletion scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -e

: "${CARGO:=cargo}"

crates="${1:-utoipa utoipa-gen utoipa-swagger-ui utoipa-redoc utoipa-rapidoc}"
crates="${1:-utoipa utoipa-gen utoipa-swagger-ui utoipa-redoc utoipa-rapidoc utoipa-scalar utoipa-axum}"

for crate in $crates; do
echo "Testing crate: $crate..."
Expand All @@ -31,5 +31,7 @@ for crate in $crates; do
$CARGO test -p utoipa-rapidoc --features actix-web,rocket,axum
elif [[ "$crate" == "utoipa-scalar" ]]; then
$CARGO test -p utoipa-scalar --features actix-web,rocket,axum
elif [[ "$crate" == "utoipa-axum" ]]; then
$CARGO test -p utoipa-axum --features debug,utoipa/debug
fi
done
30 changes: 30 additions & 0 deletions utoipa-axum/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "utoipa-axum"
description = "Compile time generated OpenAPI documentation for Rust"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
readme = "README.md"
keywords = ["utoipa", "axum", "bindings"]
repository = "https://github.com/juhaku/utoipa"
categories = ["web-programming"]
authors = ["Juha Kukkonen <juha7kukkonen@gmail.com>"]
rust-version.workspace = true

[features]
debug = []

[dependencies]
axum = { version = "0.7", default-features = false }
utoipa = { version = "5.0.0-alpha", path = "../utoipa", default-features = false }
async-trait = "0.1"
tower-service = "0.3"
tower-layer = "0.3.2"
paste = "1.0"

[package.metadata.docs.rs]
features = []
rustdoc-args = ["--cfg", "doc_cfg"]

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(doc_cfg)'] }
1 change: 1 addition & 0 deletions utoipa-axum/LICENSE-APACHE
1 change: 1 addition & 0 deletions utoipa-axum/LICENSE-MIT
47 changes: 47 additions & 0 deletions utoipa-axum/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# utoipa-axum - Bindings for Axum and utoipa

Utoipa axum brings `utoipa` and `axum` closer together by the way of providing an ergonomic API that is extending on
the `axum` API. It gives a natural way to register handlers known to `axum` and also simultaneously generates OpenAPI
specification from the handlers.

## Install

Add dependency declaration to `Cargo.toml`.

```toml
[dependencies]
utoipa_axum = "0.1"
```

## Examples

Use `OpenApiRouter` to collect handlers with `#[utoipa::path]` macro to compose service and form OpenAPI spec.

```rust
#[derive(utoipa::ToSchema)]
struct Todo {
id: i32,
}

#[derive(utoipa::OpenApi)]
#[openapi(components(schemas(Todo)))]
struct Api;

let mut router: OpenApiRouter = OpenApiRouter::with_openapi(Api::openapi())
.routes(get_path(search_user))
.routes(
get_path(get_user)
.post_path(post_user)
.delete_path(delete_user),
);

let api = router.to_openapi();
let axum_router: axum::Router = router.into();
```

## License

Licensed under either of [Apache 2.0](LICENSE-APACHE) or [MIT](LICENSE-MIT) license at your option.

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate
by you, shall be dual licensed, without any additional terms or conditions.
Loading

0 comments on commit a0db8b9

Please sign in to comment.