Skip to content

Commit

Permalink
Add implementation for utoipa-actix-web bindings (#1158)
Browse files Browse the repository at this point in the history
Implements wrappers for `ServiceConfig`, `App`, `Scope` of actix-web.
This allows users to create `App` with collecting `paths` and `schemas`
recursively without registering them to `#[openapi(...)]` attribute.

Example of new supported syntax.
```rust
 use actix_web::{get, App};
 use utoipa_actix_web::{scope, AppExt};

 #[derive(utoipa::ToSchema)]
 struct User {
     id: i32,
 }

 #[utoipa::path(responses((status = OK, body = User)))]
 #[get("/user")]
 async fn get_user() -> Json<User> {
     Json(User { id: 1 })
 }

 let (_, mut api) = App::new()
     .into_utoipa_app()
     .service(scope::scope("/api/v1").service(get_user))
     .split_for_parts();
```

Relates #283 Relates #662
Closes #121 Closes #657
  • Loading branch information
juhaku authored Oct 22, 2024
1 parent 83a3a2d commit 2bfbee7
Show file tree
Hide file tree
Showing 17 changed files with 1,120 additions and 10 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ jobs:
- utoipa-scalar
- utoipa-axum
- utoipa-config
- utoipa-actix-web
fail-fast: true
runs-on: ubuntu-latest

Expand Down Expand Up @@ -72,6 +73,8 @@ jobs:
changes=true
elif [[ "$change" == "utoipa-config" && "${{ matrix.crate }}" == "utoipa-config" && $changes == false ]]; then
changes=true
elif [[ "$change" == "utoipa-actix-web" && "${{ matrix.crate }}" == "utoipa-actix-web" && $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 Expand Up @@ -134,7 +137,7 @@ jobs:
~/.cargo/git/db/
examples/**/target/
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}_examples

- name: Test that examples compile
run: |
./scripts/validate-examples.sh
1 change: 1 addition & 0 deletions .github/workflows/draft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jobs:
- utoipa-scalar
- utoipa-axum
- utoipa-config
- utoipa-actix-web
runs-on: ubuntu-latest

steps:
Expand Down
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ members = [
"utoipa-scalar",
"utoipa-axum",
"utoipa-config",
"utoipa-actix-web",
]

[workspace.metadata.publish]
Expand All @@ -26,4 +27,5 @@ order = [
"utoipa-rapidoc",
"utoipa-scalar",
"utoipa-axum",
"utoipa-actix-web",
]
4 changes: 3 additions & 1 deletion scripts/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ set -e
: "${CARGO:=cargo}"
: "${CARGO_COMMAND:=test}"

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

for crate in $crates; do
echo "Testing crate: $crate..."
Expand Down Expand Up @@ -44,5 +44,7 @@ for crate in $crates; do
pushd utoipa-config/config-test-crate/
$CARGO ${CARGO_COMMAND}
popd
elif [[ "$crate" == "utoipa-actix-web" ]]; then
$CARGO ${CARGO_COMMAND} -p utoipa-actix-web
fi
done
7 changes: 7 additions & 0 deletions utoipa-actix-web/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Changelog - utoipa-actix-web

## Unreleased

### Added

* Add implementation for utoipa-actix-web bindings (https://github.com/juhaku/utoipa/pull/1158)
33 changes: 33 additions & 0 deletions utoipa-actix-web/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[package]
name = "utoipa-actix-web"
description = "Utoipa's actix-web bindings for seamless integration of the two"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
readme = "README.md"
keywords = ["utoipa", "actix-web", "bindings"]
repository = "https://github.com/juhaku/utoipa"
categories = ["web-programming"]
authors = ["Juha Kukkonen <juha7kukkonen@gmail.com>"]
rust-version.workspace = true

[dependencies]
utoipa = { path = "../utoipa", version = "5" }
actix-web = { version = "4", default-features = false }
actix-service = "2"

[dev-dependencies]
utoipa = { path = "../utoipa", version = "5", features = [
"actix_extras",
"macros",
"debug",
] }
actix-web = { version = "4", default-features = false, features = ["macros"] }
serde = "1"

[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-actix-web/LICENSE-APACHE
1 change: 1 addition & 0 deletions utoipa-actix-web/LICENSE-MIT
54 changes: 54 additions & 0 deletions utoipa-actix-web/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# utoipa-actix-web - Bindings for Actix Web and utoipa

[![Utoipa build](https://github.com/juhaku/utoipa/actions/workflows/build.yaml/badge.svg)](https://github.com/juhaku/utoipa/actions/workflows/build.yaml)
[![crates.io](https://img.shields.io/crates/v/utoipa-actix-web.svg?label=crates.io&color=orange&logo=rust)](https://crates.io/crates/utoipa-actix-web)
[![docs.rs](https://img.shields.io/static/v1?label=docs.rs&message=utoipa-actix-web&color=blue&logo=data:image/svg+xml;base64,PHN2ZyByb2xlPSJpbWciIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDUxMiA1MTIiPjxwYXRoIGZpbGw9IiNmNWY1ZjUiIGQ9Ik00ODguNiAyNTAuMkwzOTIgMjE0VjEwNS41YzAtMTUtOS4zLTI4LjQtMjMuNC0zMy43bC0xMDAtMzcuNWMtOC4xLTMuMS0xNy4xLTMuMS0yNS4zIDBsLTEwMCAzNy41Yy0xNC4xIDUuMy0yMy40IDE4LjctMjMuNCAzMy43VjIxNGwtOTYuNiAzNi4yQzkuMyAyNTUuNSAwIDI2OC45IDAgMjgzLjlWMzk0YzAgMTMuNiA3LjcgMjYuMSAxOS45IDMyLjJsMTAwIDUwYzEwLjEgNS4xIDIyLjEgNS4xIDMyLjIgMGwxMDMuOS01MiAxMDMuOSA1MmMxMC4xIDUuMSAyMi4xIDUuMSAzMi4yIDBsMTAwLTUwYzEyLjItNi4xIDE5LjktMTguNiAxOS45LTMyLjJWMjgzLjljMC0xNS05LjMtMjguNC0yMy40LTMzLjd6TTM1OCAyMTQuOGwtODUgMzEuOXYtNjguMmw4NS0zN3Y3My4zek0xNTQgMTA0LjFsMTAyLTM4LjIgMTAyIDM4LjJ2LjZsLTEwMiA0MS40LTEwMi00MS40di0uNnptODQgMjkxLjFsLTg1IDQyLjV2LTc5LjFsODUtMzguOHY3NS40em0wLTExMmwtMTAyIDQxLjQtMTAyLTQxLjR2LS42bDEwMi0zOC4yIDEwMiAzOC4ydi42em0yNDAgMTEybC04NSA0Mi41di03OS4xbDg1LTM4Ljh2NzUuNHptMC0xMTJsLTEwMiA0MS40LTEwMi00MS40di0uNmwxMDItMzguMiAxMDIgMzguMnYuNnoiPjwvcGF0aD48L3N2Zz4K)](https://docs.rs/utoipa-actix-web/latest/)
![rustc](https://img.shields.io/static/v1?label=rustc&message=1.75&color=orange&logo=rust)

This crate implements necessary bindings for automatically collecting `paths` and `schemas` recursively from Actix Web
`App`, `Scope` and `ServiceConfig`. It provides natural API reducing duplication and support for scopes while generating
OpenAPI specification without the need to declare `paths` and `schemas` to `#[openapi(...)]` attribute of `OpenApi` derive.

Currently only `service(...)` calls supports automatic collection of schemas and paths. Manual routes via `route(...)` or
`Route::new().to(...)` is not supported.

## Install

Add dependency declaration to `Cargo.toml`.

```toml
[dependencies]
utoipa-actix-web = "0.1"
```

## Examples

Collect handlers annotated with `#[utoipa::path]` recursively from `service(...)` calls to compose OpenAPI spec.

```rust
use actix_web::{get, App};
use utoipa_actix_web::{scope, AppExt};

#[derive(utoipa::ToSchema)]
struct User {
id: i32,
}

#[utoipa::path(responses((status = OK, body = User)))]
#[get("/user")]
async fn get_user() -> Json<User> {
Json(User { id: 1 })
}

let (_, mut api) = App::new()
.into_utoipa_app()
.service(scope::scope("/api/v1").service(get_user))
.split_for_parts();
```

## 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 2bfbee7

Please sign in to comment.