From 2a25cd531d332ee1c975a64eb463126a15e313b8 Mon Sep 17 00:00:00 2001 From: David Steele Date: Fri, 17 Apr 2026 14:21:31 +0100 Subject: [PATCH] Update 8.0.x with rust-server from master and remove support for rust-server-deprecated --- .github/workflows/samples-rust-server.yaml | 86 + .../main/resources/rust-server/Cargo.mustache | 161 +- .../src/main/resources/rust-server/README.md | 1 + .../resources/rust-server/README.mustache | 69 +- .../main/resources/rust-server/auth.mustache | 9 +- .../resources/rust-server/bin-cli.mustache | 353 + .../main/resources/rust-server/cargo-config | 3 +- .../rust-server/client-callbacks.mustache | 7 +- .../rust-server/client-imports.mustache | 11 +- .../resources/rust-server/client-mod.mustache | 183 +- .../rust-server/client-operation.mustache | 348 +- .../client-request-body-instance.mustache | 111 + ...lient-request-body-multipart-form.mustache | 65 + .../client-response-body-instance.mustache | 22 + ...t-response-body-multipart-related.mustache | 76 + .../resources/rust-server/context.mustache | 125 +- .../rust-server/example-client-main.mustache | 109 +- .../example-client-server.mustache | 1 + .../rust-server/example-server-auth.mustache | 61 +- .../example-server-common.mustache | 63 +- .../rust-server/example-server-main.mustache | 18 +- .../example-server-operation.mustache | 10 +- .../example-server-server.mustache | 1 + .../generate-multipart-related.mustache | 39 + .../resources/rust-server/header.mustache | 36 +- .../main/resources/rust-server/lib.mustache | 78 +- .../resources/rust-server/models.mustache | 338 +- .../resources/rust-server/response.mustache | 16 +- .../rust-server/server-callbacks.mustache | 59 +- .../rust-server/server-imports.mustache | 14 +- .../rust-server/server-make-service.mustache | 64 +- .../resources/rust-server/server-mod.mustache | 7 +- .../rust-server/server-operation.mustache | 455 +- .../server-request-body-basic.mustache | 63 + .../server-request-body-form.mustache | 24 + .../server-request-body-instance.mustache | 24 + ...erver-request-body-multipart-form.mustache | 98 + ...er-request-body-multipart-related.mustache | 86 + .../server-response-body-instance.mustache | 53 + .../rust-server/server-server_auth.mustache | 9 +- .../server-service-footer.mustache | 15 +- .../server-service-header.mustache | 123 +- .../resources/rust-server/validate.mustache | 60 + .../output/multipart-v3/.cargo/config.toml | 19 + .../multipart-v3/.openapi-generator/FILES | 3 +- .../multipart-v3/.openapi-generator/VERSION | 2 +- .../output/multipart-v3/Cargo.toml | 126 +- .../rust-server/output/multipart-v3/README.md | 71 +- .../output/multipart-v3/api/openapi.yaml | 10 +- .../output/multipart-v3/bin/cli.rs | 223 + .../multipart-v3/examples/client/main.rs | 81 +- .../multipart-v3/examples/server/main.rs | 16 +- .../multipart-v3/examples/server/server.rs | 63 +- .../examples/server/server_auth.rs | 45 +- .../output/multipart-v3/src/auth.rs | 9 +- .../output/multipart-v3/src/client/mod.rs | 389 +- .../output/multipart-v3/src/context.rs | 58 +- .../output/multipart-v3/src/header.rs | 36 +- .../output/multipart-v3/src/lib.rs | 23 +- .../output/multipart-v3/src/models.rs | 284 +- .../output/multipart-v3/src/server/mod.rs | 397 +- .../multipart-v3/src/server/server_auth.rs | 9 +- .../output/no-example-v3/.cargo/config.toml | 19 + .../no-example-v3/.openapi-generator/FILES | 3 +- .../no-example-v3/.openapi-generator/VERSION | 2 +- .../output/no-example-v3/Cargo.toml | 114 +- .../output/no-example-v3/README.md | 65 +- .../output/no-example-v3/api/openapi.yaml | 2 +- .../output/no-example-v3/bin/cli.rs | 159 + .../no-example-v3/examples/client/main.rs | 75 +- .../no-example-v3/examples/server/main.rs | 16 +- .../no-example-v3/examples/server/server.rs | 63 +- .../examples/server/server_auth.rs | 45 +- .../output/no-example-v3/src/auth.rs | 9 +- .../output/no-example-v3/src/client/mod.rs | 224 +- .../output/no-example-v3/src/context.rs | 58 +- .../output/no-example-v3/src/header.rs | 36 +- .../output/no-example-v3/src/lib.rs | 23 +- .../output/no-example-v3/src/models.rs | 90 +- .../output/no-example-v3/src/server/mod.rs | 187 +- .../no-example-v3/src/server/server_auth.rs | 9 +- .../output/openapi-v3/.cargo/config.toml | 19 + .../openapi-v3/.openapi-generator/FILES | 5 +- .../openapi-v3/.openapi-generator/VERSION | 2 +- .../rust-server/output/openapi-v3/Cargo.toml | 124 +- .../rust-server/output/openapi-v3/README.md | 116 +- .../output/openapi-v3/api/openapi.yaml | 108 +- .../rust-server/output/openapi-v3/bin/cli.rs | 789 ++ .../output/openapi-v3/docs/NullableTest.md | 10 +- .../openapi-v3/docs/ObjectUntypedProps.md | 2 +- .../output/openapi-v3/docs/default_api.md | 52 +- .../output/openapi-v3/examples/client/main.rs | 157 +- .../openapi-v3/examples/client/server.rs | 63 +- .../output/openapi-v3/examples/server/main.rs | 16 +- .../openapi-v3/examples/server/server.rs | 95 +- .../openapi-v3/examples/server/server_auth.rs | 50 +- .../rust-server/output/openapi-v3/src/auth.rs | 9 +- .../output/openapi-v3/src/client/callbacks.rs | 171 +- .../output/openapi-v3/src/client/mod.rs | 1467 +-- .../output/openapi-v3/src/context.rs | 74 +- .../output/openapi-v3/src/header.rs | 36 +- .../rust-server/output/openapi-v3/src/lib.rs | 118 +- .../output/openapi-v3/src/models.rs | 3332 +++++-- .../output/openapi-v3/src/server/callbacks.rs | 121 +- .../output/openapi-v3/src/server/mod.rs | 851 +- .../openapi-v3/src/server/server_auth.rs | 9 +- .../output/ops-v3/.cargo/config.toml | 19 + .../output/ops-v3/.openapi-generator/FILES | 3 +- .../output/ops-v3/.openapi-generator/VERSION | 2 +- .../rust-server/output/ops-v3/Cargo.toml | 114 +- .../rust-server/output/ops-v3/README.md | 139 +- .../rust-server/output/ops-v3/bin/cli.rs | 767 ++ .../output/ops-v3/examples/client/main.rs | 149 +- .../output/ops-v3/examples/server/main.rs | 16 +- .../output/ops-v3/examples/server/server.rs | 63 +- .../ops-v3/examples/server/server_auth.rs | 45 +- .../rust-server/output/ops-v3/src/auth.rs | 9 +- .../output/ops-v3/src/client/mod.rs | 1151 +-- .../rust-server/output/ops-v3/src/context.rs | 58 +- .../rust-server/output/ops-v3/src/header.rs | 36 +- .../rust-server/output/ops-v3/src/lib.rs | 23 +- .../rust-server/output/ops-v3/src/models.rs | 4 +- .../output/ops-v3/src/server/mod.rs | 344 +- .../output/ops-v3/src/server/server_auth.rs | 9 +- .../.cargo/config.toml | 19 + .../.openapi-generator/FILES | 19 +- .../.openapi-generator/VERSION | 2 +- .../Cargo.toml | 130 +- .../README.md | 140 +- .../api/openapi.yaml | 309 +- .../bin/cli.rs | 1169 +++ .../docs/ArrayTest.md | 2 +- ...quareBracketModelNameRightSquareBracket.md | 10 + .../docs/EnumArrays.md | 6 +- .../EnumArraysArrayArrayEnumInnerInner.md | 9 + .../docs/EnumArraysArrayEnumInner.md | 9 + .../docs/EnumArraysJustSymbol.md | 9 + .../docs/EnumTest.md | 8 +- .../docs/EnumTestEnumInteger.md | 9 + .../docs/EnumTestEnumString.md | 9 + .../FindPetsByStatusStatusParameterInner.md | 9 + .../docs/MapTest.md | 4 +- .../docs/MapTestMapMapOfEnumValueValue.md | 9 + .../docs/Order.md | 2 +- .../docs/OrderStatus.md | 9 + .../docs/Pet.md | 2 +- .../docs/PetStatus.md | 9 + ...tersEnumHeaderStringArrayParameterInner.md | 9 + ...EnumParametersEnumHeaderStringParameter.md | 9 + ...tEnumParametersEnumQueryDoubleParameter.md | 9 + ...EnumParametersEnumQueryIntegerParameter.md | 9 + ...TestEnumParametersRequestEnumFormString.md | 9 + .../docs/fake_api.md | 74 +- .../docs/pet_api.md | 96 +- .../docs/store_api.md | 66 +- .../docs/user_api.md | 64 +- .../examples/client/main.rs | 247 +- .../examples/server/main.rs | 18 +- .../examples/server/server.rs | 247 +- .../examples/server/server_auth.rs | 50 +- .../src/auth.rs | 9 +- .../src/client/mod.rs | 2472 ++--- .../src/context.rs | 107 +- .../src/header.rs | 36 +- .../src/lib.rs | 555 +- .../src/models.rs | 8328 ++++++++++++----- .../src/server/mod.rs | 2361 +++-- .../src/server/server_auth.rs | 9 +- .../ping-bearer-auth/.cargo/config.toml | 19 + .../ping-bearer-auth/.openapi-generator/FILES | 3 +- .../.openapi-generator/VERSION | 2 +- .../output/ping-bearer-auth/Cargo.toml | 114 +- .../output/ping-bearer-auth/README.md | 67 +- .../output/ping-bearer-auth/bin/cli.rs | 164 + .../ping-bearer-auth/examples/client/main.rs | 77 +- .../ping-bearer-auth/examples/server/main.rs | 16 +- .../examples/server/server.rs | 63 +- .../examples/server/server_auth.rs | 45 +- .../output/ping-bearer-auth/src/auth.rs | 9 +- .../output/ping-bearer-auth/src/client/mod.rs | 226 +- .../output/ping-bearer-auth/src/context.rs | 74 +- .../output/ping-bearer-auth/src/header.rs | 36 +- .../output/ping-bearer-auth/src/lib.rs | 23 +- .../output/ping-bearer-auth/src/models.rs | 4 +- .../output/ping-bearer-auth/src/server/mod.rs | 164 +- .../src/server/server_auth.rs | 9 +- .../rust-server-test/.cargo/config.toml | 19 + .../rust-server-test/.openapi-generator/FILES | 3 +- .../.openapi-generator/VERSION | 2 +- .../output/rust-server-test/Cargo.toml | 114 +- .../output/rust-server-test/README.md | 79 +- .../output/rust-server-test/api/openapi.yaml | 19 +- .../output/rust-server-test/bin/cli.rs | 320 + .../docs/ANullableContainer.md | 4 +- .../rust-server-test/docs/AllOfObject.md | 2 +- .../rust-server-test/examples/client/main.rs | 89 +- .../rust-server-test/examples/server/main.rs | 16 +- .../examples/server/server.rs | 63 +- .../examples/server/server_auth.rs | 45 +- .../output/rust-server-test/src/auth.rs | 9 +- .../output/rust-server-test/src/client/mod.rs | 538 +- .../output/rust-server-test/src/context.rs | 58 +- .../output/rust-server-test/src/header.rs | 36 +- .../output/rust-server-test/src/lib.rs | 23 +- .../output/rust-server-test/src/models.rs | 768 +- .../output/rust-server-test/src/server/mod.rs | 320 +- .../src/server/server_auth.rs | 9 +- 207 files changed, 26042 insertions(+), 11660 deletions(-) create mode 100644 .github/workflows/samples-rust-server.yaml create mode 100644 modules/openapi-generator/src/main/resources/rust-server/bin-cli.mustache create mode 100644 modules/openapi-generator/src/main/resources/rust-server/client-request-body-instance.mustache create mode 100644 modules/openapi-generator/src/main/resources/rust-server/client-request-body-multipart-form.mustache create mode 100644 modules/openapi-generator/src/main/resources/rust-server/client-response-body-instance.mustache create mode 100644 modules/openapi-generator/src/main/resources/rust-server/client-response-body-multipart-related.mustache create mode 100644 modules/openapi-generator/src/main/resources/rust-server/generate-multipart-related.mustache create mode 100644 modules/openapi-generator/src/main/resources/rust-server/server-request-body-basic.mustache create mode 100644 modules/openapi-generator/src/main/resources/rust-server/server-request-body-form.mustache create mode 100644 modules/openapi-generator/src/main/resources/rust-server/server-request-body-instance.mustache create mode 100644 modules/openapi-generator/src/main/resources/rust-server/server-request-body-multipart-form.mustache create mode 100644 modules/openapi-generator/src/main/resources/rust-server/server-request-body-multipart-related.mustache create mode 100644 modules/openapi-generator/src/main/resources/rust-server/server-response-body-instance.mustache create mode 100644 modules/openapi-generator/src/main/resources/rust-server/validate.mustache create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/.cargo/config.toml create mode 100644 samples/server/petstore/rust-server/output/multipart-v3/bin/cli.rs create mode 100644 samples/server/petstore/rust-server/output/no-example-v3/.cargo/config.toml create mode 100644 samples/server/petstore/rust-server/output/no-example-v3/bin/cli.rs create mode 100644 samples/server/petstore/rust-server/output/openapi-v3/.cargo/config.toml create mode 100644 samples/server/petstore/rust-server/output/openapi-v3/bin/cli.rs create mode 100644 samples/server/petstore/rust-server/output/ops-v3/.cargo/config.toml create mode 100644 samples/server/petstore/rust-server/output/ops-v3/bin/cli.rs create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/.cargo/config.toml create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/bin/cli.rs create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/DollarSpecialLeftSquareBracketModelNameRightSquareBracket.md create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArraysArrayArrayEnumInnerInner.md create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArraysArrayEnumInner.md create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArraysJustSymbol.md create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumTestEnumInteger.md create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumTestEnumString.md create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/FindPetsByStatusStatusParameterInner.md create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/MapTestMapMapOfEnumValueValue.md create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/OrderStatus.md create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/PetStatus.md create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumHeaderStringArrayParameterInner.md create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumHeaderStringParameter.md create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumQueryDoubleParameter.md create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumQueryIntegerParameter.md create mode 100644 samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersRequestEnumFormString.md create mode 100644 samples/server/petstore/rust-server/output/ping-bearer-auth/.cargo/config.toml create mode 100644 samples/server/petstore/rust-server/output/ping-bearer-auth/bin/cli.rs create mode 100644 samples/server/petstore/rust-server/output/rust-server-test/.cargo/config.toml create mode 100644 samples/server/petstore/rust-server/output/rust-server-test/bin/cli.rs diff --git a/.github/workflows/samples-rust-server.yaml b/.github/workflows/samples-rust-server.yaml new file mode 100644 index 000000000000..7530b82530d6 --- /dev/null +++ b/.github/workflows/samples-rust-server.yaml @@ -0,0 +1,86 @@ +name: Samples Rust Servers + +on: + push: + paths: + - "samples/server/petstore/rust-server/**" + - "samples/server/petstore/rust-axum/**" + pull_request: + paths: + - "samples/server/petstore/rust-server/**" + - "samples/server/petstore/rust-axum/**" + +jobs: + build: + name: Build Rust + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + sample: + # these folders contain sub-projects of rust clients, servers + - samples/server/petstore/rust-server/ + - samples/server/petstore/rust-server-deprecated/ + - samples/server/petstore/rust-axum/ + steps: + - uses: actions/checkout@v5 + - uses: actions-rs/toolchain@v1 + with: + toolchain: stable + + - name: Rust cache + uses: Swatinem/rust-cache@v2 + with: + cache-targets: false # Don't cache workspace target directories as they don't exist + cache-directories: + ${{ matrix.sample }}/target + workspaces: | + ${{ matrix.sample }}/output/* + + - name: Build + working-directory: ${{ matrix.sample }} + run: | + set -e + cargo build --all-targets --all-features + cargo build --all-targets --no-default-features + - name: Tests + working-directory: ${{ matrix.sample }} + run: | + set -e + + # Iterate through each package and test various features + for package in $(find output -maxdepth 1 -mindepth 1 -type d) + do + pushd $package + # Not all versions have a server example + if test -f examples/server/main.rs; then + cargo build --example ${package##*/}-server --features="server" + fi + # Not all versions have a client example + if test -f examples/client/main.rs; then + cargo build --example ${package##*/}-client --features="client" + fi + # Test the CLI works if present + if test -f bin/cli.rs; then + cargo build --bin ${package##*/} --features cli + ../../target/debug/${package##*/} --help + fi + # Test the validate feature if it exists + if cargo read-manifest | grep -q '"validate"'; then + cargo build --features validate --all-targets + fi + # Test TLS features if they exist + if cargo read-manifest | grep -q '"client-tls"'; then + # Client without TLS (HTTP-only) + cargo build --no-default-features --features=client --lib + # Client with TLS (using native-tls) + cargo build --no-default-features --features=client,client-tls --lib + # Server without TLS + cargo build --no-default-features --features=server --lib + fi + cargo fmt + cargo test + cargo clippy + cargo doc + popd + done diff --git a/modules/openapi-generator/src/main/resources/rust-server/Cargo.mustache b/modules/openapi-generator/src/main/resources/rust-server/Cargo.mustache index 1cd664417e0e..3d145ccb6c50 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/Cargo.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/Cargo.mustache @@ -28,128 +28,179 @@ repository = "{{.}}" documentation = "{{.}}" {{/documentationUrl}} {{#homePageUrl}} -homepage = "{{.}} +homepage = "{{.}}" {{/homePageUrl}} [features] -default = ["client", "server"] +default = ["client", "server", "client-tls"] client = [ -{{#apiUsesMultipart}} - "mime_0_2", -{{/apiUsesMultipart}} {{#apiUsesMultipartFormData}} "multipart", "multipart/client", "swagger/multipart_form", {{/apiUsesMultipartFormData}} {{#apiUsesMultipartRelated}} - "hyper_0_10", "mime_multipart", + "mime_multipart", "swagger/multipart_related", {{/apiUsesMultipartRelated}} {{#usesUrlEncodedForm}} "serde_urlencoded", {{/usesUrlEncodedForm}} {{#hasCallbacks}} - "serde_ignored", "regex", "percent-encoding", "lazy_static", + "serde_ignored", "percent-encoding", {{^apiUsesByteArray}}"lazy_static", "regex",{{/apiUsesByteArray}} {{/hasCallbacks}} {{! Anything added to the list below, should probably be added to the callbacks list below }} - "hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url" + "hyper", "percent-encoding", "hyper-util/http1", "hyper-util/http2", "url" +] +# TLS support - automatically selects backend based on target OS: +# - macOS/Windows/iOS: native-tls via hyper-tls +# - Other platforms: OpenSSL via hyper-openssl +# Dependencies are in target-specific sections below +client-tls = [ + "client", + "dep:native-tls", + "dep:hyper-tls", + "dep:openssl", + "dep:hyper-openssl", + "swagger/tls" ] server = [ -{{#apiUsesMultipart}} - "mime_0_2", -{{/apiUsesMultipart}} {{#apiUsesMultipartFormData}} "multipart", "multipart/server", "swagger/multipart_form", {{/apiUsesMultipartFormData}} {{#apiUsesMultipartRelated}} - "hyper_0_10", "mime_multipart", + "mime_multipart", "swagger/multipart_related", {{/apiUsesMultipartRelated}} {{#hasCallbacks}} - "native-tls", "hyper-openssl", "hyper-tls", "openssl", + "hyper-util/http1", "hyper-util/http2", {{/hasCallbacks}} {{! Anything added to the list below, should probably be added to the callbacks list above }} - "serde_ignored", "hyper", "regex", "percent-encoding", "url", "lazy_static" + "serde_ignored", "hyper", "percent-encoding", "url", + {{^apiUsesByteArray}}"lazy_static", "regex"{{/apiUsesByteArray}} +] +cli = [ +{{#apiHasDeleteMethods}} + "dialoguer", +{{/apiHasDeleteMethods}} + "anyhow", "clap", "clap-verbosity-flag", "simple_logger", "tokio" ] conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"] -[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] -native-tls = { version = "0.2", optional = true } -hyper-tls = { version = "0.5", optional = true } - -[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] -hyper-openssl = { version = "0.9", optional = true } -openssl = {version = "0.10", optional = true } +mock = ["mockall"] +validate = [{{^apiUsesByteArray}}"regex",{{/apiUsesByteArray}} "serde_valid", "swagger/serdevalid"] [dependencies] # Common -async-trait = "0.1.24" +async-trait = "0.1.89" chrono = { version = "0.4", features = ["serde"] } futures = "0.3" -swagger = { version = "6.1", features = ["serdejson", "server", "client", "tls", "tcp"] } -log = "0.4.0" +swagger = { version = "7.0.0", features = ["serdejson", "server", "client"] } +headers = "0.4.1" +log = "0.4.29" + mime = "0.3" +mockall = { version = "0.14", optional = true } +{{#apiUsesByteArray}} +lazy_static = "1.5" +regex = "1.12" +{{/apiUsesByteArray}} + serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -validator = { version = "0.16", features = ["derive"] } +{{#apiUsesIntegerEnums}} +serde_repr = "0.1" +{{/apiUsesIntegerEnums}} +serde_valid = { version = "2.0", optional = true } + +validator = { version = "0.20", features = ["derive"] } # Crates included if required by the API definition {{#usesXml}} -# TODO: this should be updated to point at the official crate once -# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream -serde-xml-rs = {git = "https://github.com/Metaswitch/serde-xml-rs" , branch = "master"} +serde-xml-rs = "0.8" {{/usesXml}} -{{#apiUsesMultipart}} -mime_0_2 = { package = "mime", version = "0.2.6", optional = true } -{{/apiUsesMultipart}} {{#apiUsesMultipartFormData}} -multipart = { version = "0.16", default-features = false, optional = true } +multipart = { version = "0.18", default-features = false, optional = true } {{/apiUsesMultipartFormData}} {{#apiUsesUuid}} -uuid = {version = "1.3.1", features = ["serde", "v4"]} +uuid = { version = "1.23.0", features = ["serde", "v4"]} {{/apiUsesUuid}} # Common between server and client features -hyper = {version = "0.14", features = ["full"], optional = true} +bytes = "1.11" +http-body-util = "0.1.3" +hyper = { version = "1.9.0", features = ["full"], optional = true } +hyper-util = { version = "0.1.20", features = ["service"] } {{#apiUsesMultipartRelated}} -mime_multipart = {version = "0.5", optional = true} -hyper_0_10 = {package = "hyper", version = "0.10", default-features = false, optional=true} +mime_multipart = { version = "0.10", optional = true, package = "mime-multipart-hyper1" } {{/apiUsesMultipartRelated}} -serde_ignored = {version = "0.1.1", optional = true} -url = {version = "2.1", optional = true} +serde_ignored = { version = "0.1.14", optional = true } +url = { version = "2.5", optional = true } # Client-specific {{#usesUrlEncodedForm}} -serde_urlencoded = {version = "0.6.1", optional = true} +serde_urlencoded = { version = "0.7.1", optional = true } {{/usesUrlEncodedForm}} +tower-service = "0.3.3" # Server, and client callback-specific -lazy_static = { version = "1.4", optional = true } -percent-encoding = {version = "2.1.0", optional = true} -regex = {version = "1.3", optional = true} +{{^apiUsesByteArray}} +lazy_static = { version = "1.5", optional = true } +regex = { version = "1.12", optional = true } +{{/apiUsesByteArray}} +percent-encoding = { version = "2.3.2", optional = true } + +# CLI-specific +anyhow = { version = "1", optional = true } +clap = { version = "4.6.0", features = ["env"], optional = true } +clap-verbosity-flag = { version = "3.0", optional = true } +simple_logger = { version = "5.2.0", features = ["stderr"], optional = true } +tokio = { version = "1.50.0", features = ["rt-multi-thread", "macros"], optional = true } +{{#apiHasDeleteMethods}} +dialoguer = { version = "0.12", optional = true } +{{/apiHasDeleteMethods}} # Conversion -frunk = { version = "0.3.0", optional = true } -frunk_derives = { version = "0.3.0", optional = true } -frunk_core = { version = "0.3.0", optional = true } -frunk-enum-derive = { version = "0.2.0", optional = true } -frunk-enum-core = { version = "0.2.0", optional = true } +frunk = { version = "0.4.4", optional = true } +frunk_derives = { version = "0.4.4", optional = true } +frunk_core = { version = "0.4.4", optional = true } +frunk-enum-derive = { version = "0.3.0", optional = true } +frunk-enum-core = { version = "0.3.0", optional = true } -# Bearer authentication -jsonwebtoken = { version = "9.3.0", optional = false } +# TLS dependencies - platform-specific backends +# On macOS/Windows/iOS, use native-tls via hyper-tls +[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] +native-tls = { version = "0.2", optional = true } +hyper-tls = { version = "0.6", optional = true } + +# On other platforms (Linux, etc.), use OpenSSL via hyper-openssl +[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] +openssl = { version = "0.10", optional = true } +hyper-openssl = { version = "0.10", optional = true } [dev-dependencies] -clap = "2.25" -env_logger = "0.7" -tokio = { version = "1.14", features = ["full"] } +always_send = "0.1.1" +clap = "4.6.0" +env_logger = "0.11" +tokio = { version = "1.50.0", features = ["full"] } native-tls = "0.2" +pin-project = "1.1.11" + +# Bearer authentication, used in examples +jsonwebtoken = {version = "10.3.0", features = ["rust_crypto"]} [target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies] -tokio-openssl = "0.6" openssl = "0.10" +tokio-openssl = "0.6" [[example]] -name = "client" +name = "{{{packageName}}}-client" +path = "examples/client/main.rs" required-features = ["client"] [[example]] -name = "server" +name = "{{{packageName}}}-server" +path = "examples/server/main.rs" required-features = ["server"] + +[[bin]] +name = "{{{packageName}}}" +path = "bin/cli.rs" +required-features = ["client", "cli"] diff --git a/modules/openapi-generator/src/main/resources/rust-server/README.md b/modules/openapi-generator/src/main/resources/rust-server/README.md index 3e2bf9cbf571..bacaef541d14 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/README.md +++ b/modules/openapi-generator/src/main/resources/rust-server/README.md @@ -5,6 +5,7 @@ The Rust Server Generator templates use Mustache Partials. The following tree shows which templates include which: - `api_doc.mustache` +- `bin-cli.mustache` - `cargo-config` - `Cargo.mustache` - `context.mustache` diff --git a/modules/openapi-generator/src/main/resources/rust-server/README.mustache b/modules/openapi-generator/src/main/resources/rust-server/README.mustache index 7a87abc73630..64dbbf55ff86 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/README.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/README.mustache @@ -28,6 +28,7 @@ This autogenerated project defines an API crate `{{{packageName}}}` which contai * Data types representing the underlying data model. * A `Client` type which implements `Api` and issues HTTP requests for each operation. * A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. +* A CLI tool to drive basic API operations from the command line. It also contains an example server and client which make use of `{{{packageName}}}`: @@ -39,27 +40,51 @@ It also contains an example server and client which make use of `{{{packageName} arguments on the command line. You can use the example server and client as a basis for your own code. -See below for [more detail on implementing a server](#writing-a-server). +See below for [more detail on the examples](#using-the-generated-library). + +## CLI + +Run the included CLI tool with: + +``` +cargo run --bin cli --features=cli +``` + +To pass in arguments, put them after `--`, for example: + +``` +cargo run --bin cli --features=cli -- --help +``` + +See the help text for available options. + +To build a standalone tool, use: + +``` +cargo build --bin cli --features=cli --release +``` + +You'll find the binary at `target/release/cli`. ## Examples Run examples with: ``` -cargo run --example +cargo run --example {{{packageName}}}- ``` To pass in arguments to the examples, put them after `--`, for example: ``` -cargo run --example client -- --help +cargo run --example {{{packageName}}}-client -- --help ``` ### Running the example server To run the server, follow these simple steps: ``` -cargo run --example server +cargo run --example {{{packageName}}}-server ``` ### Running the example client @@ -70,11 +95,11 @@ To run a client, follow one of the following simple steps: {{#apis}} {{#operations}} {{#operation}} - {{#vendorExtensions}} + {{#exts}} {{^x-no-client-example}} -cargo run --example client {{{operationId}}} +cargo run --example {{{packageName}}}-client {{{operationId}}} {{/x-no-client-example}} - {{/vendorExtensions}} + {{/exts}} {{/operation}} {{/operations}} {{/apis}} @@ -85,7 +110,7 @@ cargo run --example client {{{operationId}}} The examples can be run in HTTPS mode by passing in the flag `--https`, for example: ``` -cargo run --example server -- --https +cargo run --example {{{packageName}}}-server -- --https ``` This will use the keys/certificates from the examples directory. Note that the @@ -101,8 +126,36 @@ The generated library has a few optional features that can be activated through * `client` * This defaults to enabled and creates the basic skeleton of a client implementation based on hyper * The constructed client implements the API trait by making remote API call. +* `client-tls` + * This default to enabled and provides HTTPS support with automatic TLS backend selection: + - macOS/Windows/iOS: native-tls + hyper-tls + - Linux/Unix/others: OpenSSL + hyper-openssl * `conversions` * This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types. +* `cli` + * This defaults to disabled and is required for building the included CLI tool. +* `validate` + * This defaults to disabled and allows JSON Schema validation of received data using `MakeService::set_validation` or `Service::set_validation`. + * Note, enabling validation will have a performance penalty, especially if the API heavily uses regex based checks. + +### HTTPS/TLS Support + +HTTPS support is included by default. To disable it (for example, to reduce dependencies), you can: + +```toml +[dependencies] +{{{packageName}}} = { version = "{{{packageVersion}}}", default-features = false, features = ["client", "server"] } +``` + +**For server with callbacks that need HTTPS:** +```toml +[dependencies] +{{{packageName}}} = { version = "{{{packageVersion}}}", features = ["server", "client-tls"] } +``` + +The TLS backend is automatically selected based on your target platform: +- **macOS, Windows, iOS**: Uses `native-tls` (system TLS libraries) +- **Linux, Unix, other platforms**: Uses `openssl` See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`. diff --git a/modules/openapi-generator/src/main/resources/rust-server/auth.mustache b/modules/openapi-generator/src/main/resources/rust-server/auth.mustache index cbaba3dca7c6..a6a39f79450f 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/auth.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/auth.mustache @@ -1,8 +1,7 @@ use std::collections::BTreeSet; -use crate::server::Authorization; use serde::{Deserialize, Serialize}; -use swagger::{ApiError, auth::{Basic, Bearer}}; - +use swagger::{ApiError, auth::Authorization}; +use headers::authorization::{Basic, Bearer}; #[derive(Debug, Serialize, Deserialize)] pub struct Claims { pub sub: String, @@ -24,7 +23,7 @@ pub trait AuthenticationApi { /// Method should be implemented (see example-code) to map Basic (Username:password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result; -} +} // Implement it for AllowAllAuthenticator (dummy is needed, but should not used as we have Bearer authorization) use swagger::auth::{AllowAllAuthenticator, RcBound, Scopes}; @@ -34,7 +33,7 @@ fn dummy_authorization() -> Authorization { // However, if you want to use it anyway this can not be unimplemented, so dummy implementation added. // unimplemented!() Authorization{ - subject: "Dummmy".to_owned(), + subject: "Dummy".to_owned(), scopes: Scopes::Some(BTreeSet::new()), // create an empty scope, as this should not be used issuer: None } diff --git a/modules/openapi-generator/src/main/resources/rust-server/bin-cli.mustache b/modules/openapi-generator/src/main/resources/rust-server/bin-cli.mustache new file mode 100644 index 000000000000..013262c1d12d --- /dev/null +++ b/modules/openapi-generator/src/main/resources/rust-server/bin-cli.mustache @@ -0,0 +1,353 @@ +//! CLI tool driving the API client +use anyhow::{anyhow, Context, Result}; +use clap::Parser; +{{#apiHasDeleteMethods}} +use dialoguer::Confirm; +{{/apiHasDeleteMethods}} +use log::{debug, info}; +// models may be unused if all inputs are primitive types +#[allow(unused_imports)] +use {{{externCrateName}}}::{ + models, ApiNoContext, Client, ContextWrapperExt, +{{#apiInfo}} + {{#apis}} + {{#operations}} + {{#operation}} + {{{operationId}}}Response, + {{/operation}} + {{/operations}} + {{/apis}} +{{/apiInfo}} +}; +use simple_logger::SimpleLogger; +use swagger::{AuthData, ContextBuilder, EmptyContext, Push, XSpanIdString}; + +type ClientContext = swagger::make_context_ty!( + ContextBuilder, + EmptyContext, + Option, + XSpanIdString +); + +{{! See code in RustServerCodegen if you are adding additional short option usage here. }} +#[derive(Parser, Debug)] +#[clap( + name = "{{appName}}", + version = "{{version}}", + about = "CLI access to {{appName}}" +)] +struct Cli { + #[clap(subcommand)] + operation: Operation, + + /// Address or hostname of the server hosting this API, including optional port + #[clap(short = 'a', long, default_value = "http://localhost")] + server_address: String, + + /// Path to the client private key if using client-side TLS authentication + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_certificate", "server_certificate"]))] + client_key: Option, + + /// Path to the client's public certificate associated with the private key + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_key", "server_certificate"]))] + client_certificate: Option, + + /// Path to CA certificate used to authenticate the server + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long)] + server_certificate: Option, + + /// If set, write output to file instead of stdout + #[clap(short, long)] + output_file: Option, + + #[command(flatten)] + verbosity: clap_verbosity_flag::Verbosity, +{{#apiHasDeleteMethods}} + + /// Don't ask for any confirmation prompts + #[allow(dead_code)] + #[clap(short, long)] + force: bool, +{{/apiHasDeleteMethods}} +{{#hasHttpBearerMethods}} + + /// Bearer token if used for authentication + #[arg(env = "{{#lambda.uppercase}}{{externCrateName}}{{/lambda.uppercase}}_BEARER_TOKEN", hide_env = true)] + bearer_token: Option, +{{/hasHttpBearerMethods}} +{{^hasHttpBearerMethods}} +{{#hasOAuthMethods}} + + /// Bearer token if used for authentication + #[arg(env = "{{#lambda.uppercase}}{{externCrateName}}{{/lambda.uppercase}}_BEARER_TOKEN", hide_env = true)] + bearer_token: Option, +{{/hasOAuthMethods}} +{{/hasHttpBearerMethods}} +{{#hasApiKeyMethods}} + + /// API key for authentication + #[arg(long, env = "{{#lambda.uppercase}}{{externCrateName}}{{/lambda.uppercase}}_API_KEY", hide_env = true)] + api_key: Option, +{{/hasApiKeyMethods}} +} + +#[derive(Parser, Debug)] +enum Operation { +{{#apiInfo}} + {{#apis}} + {{#operations}} + {{#operation}} + {{#summary}} + /// {{{summary}}} + {{/summary}} + {{operationId}} { + {{#allParams}} + {{#description}} + /// {{{description}}} + {{/description}} + {{^isPrimitiveType}} + #[clap(value_parser = parse_json::<{{{dataType}}}>{{#isArray}}, long{{/isArray}})] + {{/isPrimitiveType}} + {{#isByteArray}} + #[clap(value_parser = parse_json::<{{{dataType}}}>)] + {{/isByteArray}} + {{#isBinary}} + #[clap(value_parser = parse_json::<{{{dataType}}}>)] + {{/isBinary}} + {{#isBoolean}} + {{#isPrimitiveType}} + {{#exts.x-provide-cli-short-opt}} + #[clap(short, long)] + {{/exts.x-provide-cli-short-opt}} + {{^exts.x-provide-cli-short-opt}} + #[clap(long)] + {{/exts.x-provide-cli-short-opt}} + {{/isPrimitiveType}} + {{/isBoolean}} + {{{paramName}}}: {{^required}}Option<{{/required}}{{{dataType}}}{{^required}}>{{/required}}, + {{/allParams}} + }, + {{/operation}} + {{/operations}} + {{/apis}} +{{/apiInfo}} +} + +// On Linux/Unix with OpenSSL (client-tls feature), support certificate pinning and mutual TLS +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + if args.client_certificate.is_some() { + debug!("Using mutual TLS"); + let client = Client::try_new_https_mutual( + &args.server_address, + args.server_certificate.clone().unwrap(), + args.client_key.clone().unwrap(), + args.client_certificate.clone().unwrap(), + ) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else if args.server_certificate.is_some() { + debug!("Using TLS with pinned server certificate"); + let client = + Client::try_new_https_pinned(&args.server_address, args.server_certificate.clone().unwrap()) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else { + debug!("Using client without certificates"); + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) + } +} + +// On macOS/Windows/iOS or without client-tls feature, use simple client (no cert pinning/mutual TLS) +#[cfg(any( + not(feature = "client-tls"), + all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")) +))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + // Client::try_new() automatically detects the URL scheme (http:// or https://) + // and creates the appropriate client. + // Note: Certificate pinning and mutual TLS are only available on Linux/Unix with OpenSSL + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) +} + +#[tokio::main] +async fn main() -> Result<()> { + let args = Cli::parse(); + if let Some(log_level) = args.verbosity.log_level() { + SimpleLogger::new().with_level(log_level.to_level_filter()).init()?; + } + + debug!("Arguments: {:?}", &args); + +{{#hasHttpBearerMethods}} + let mut auth_data: Option = None; + + if let Some(ref bearer_token) = args.bearer_token { + debug!("Using bearer token"); + auth_data = AuthData::bearer(bearer_token); + } +{{#hasApiKeyMethods}} + if let Some(ref api_key) = args.api_key { + debug!("Using API key"); + auth_data = Some(AuthData::apikey(api_key)); + } +{{/hasApiKeyMethods}} +{{/hasHttpBearerMethods}} +{{^hasHttpBearerMethods}} + {{#hasOAuthMethods}} + let mut auth_data: Option = None; + + if let Some(ref bearer_token) = args.bearer_token { + debug!("Using bearer token"); + auth_data = AuthData::bearer(bearer_token); + } +{{#hasApiKeyMethods}} + if let Some(ref api_key) = args.api_key { + debug!("Using API key"); + auth_data = Some(AuthData::apikey(api_key)); + } +{{/hasApiKeyMethods}} + {{/hasOAuthMethods}} +{{/hasHttpBearerMethods}} +{{^hasHttpBearerMethods}} + {{^hasOAuthMethods}} +{{#hasApiKeyMethods}} + let mut auth_data: Option = None; + + if let Some(ref api_key) = args.api_key { + debug!("Using API key"); + auth_data = Some(AuthData::apikey(api_key)); + } +{{/hasApiKeyMethods}} +{{^hasApiKeyMethods}} + let auth_data: Option = None; +{{/hasApiKeyMethods}} + {{/hasOAuthMethods}} +{{/hasHttpBearerMethods}} + + #[allow(trivial_casts)] + let context = swagger::make_context!( + ContextBuilder, + EmptyContext, + auth_data, + XSpanIdString::default() + ); + + let client = create_client(&args, context)?; + + let result = match args.operation { + {{#apiInfo}} + {{#apis}} + {{#operations}} + {{#operation}} + Operation::{{operationId}} { + {{#allParams}} + {{paramName}}, + {{/allParams}} + } => { + {{#exts.x-is-delete}} + prompt(args.force, "This will delete the given entry, are you sure?")?; + {{/exts.x-is-delete}} + info!("Performing a {{operationId}} request{{^pathParams}}");{{/pathParams}}{{#pathParams}}{{#-first}} on {:?}", ({{/-first}}{{/pathParams}} + {{#pathParams}} + &{{paramName}}{{^-last}},{{/-last}} + {{#-last}} + )); + {{/-last}} + {{/pathParams}} + + let result = client.{{{exts.x-operation-id}}}( + {{#allParams}} + {{{paramName}}}{{#isArray}}.as_ref(){{/isArray}}, + {{/allParams}} + ).await?; + debug!("Result: {:?}", result); + + match result { + {{#responses}} + {{{operationId}}}Response::{{{exts.x-response-id}}} + {{#dataType}} + {{^hasHeaders}} + (body) + {{/hasHeaders}} + {{#hasHeaders}} + { + body, + {{/hasHeaders}} + {{/dataType}} + {{^dataType}} + {{#hasHeaders}} + { + {{/hasHeaders}} + {{/dataType}} + {{#headers}} + {{{name}}}, + {{#-last}} + } + {{/-last}} + {{/headers}} + => "{{{exts.x-response-id}}}\n".to_string() + {{#dataType}} + + + {{/dataType}} + {{^dataType}} + {{#hasHeaders}} + + + {{/hasHeaders}} + {{^hasHeaders}} + , + {{/hasHeaders}} + {{/dataType}} + {{#dataType}} + {{^hasHeaders}} + &serde_json::to_string_pretty(&body)?, + {{/hasHeaders}} + {{#hasHeaders}} + &format!("body: {}\n", serde_json::to_string_pretty(&body)?) + + {{/hasHeaders}} + {{/dataType}} + {{#headers}} + &format!( + "{{{name}}}: {}\n", + serde_json::to_string_pretty(&{{{name}}})? + ){{^-last}} +{{/-last}}{{#-last}},{{/-last}} + {{/headers}} + {{/responses}} + } + } + {{/operation}} + {{/operations}} + {{/apis}} + {{/apiInfo}} + }; + + if let Some(output_file) = args.output_file { + std::fs::write(output_file, result)? + } else { + println!("{}", result); + } + Ok(()) +} +{{#apiHasDeleteMethods}} + +fn prompt(force: bool, text: &str) -> Result<()> { + if force || Confirm::new().with_prompt(text).interact()? { + Ok(()) + } else { + Err(anyhow!("Aborting")) + } +} +{{/apiHasDeleteMethods}} + +// May be unused if all inputs are primitive types +#[allow(dead_code)] +fn parse_json(json_string: &str) -> Result { + serde_json::from_str(json_string).map_err(|err| anyhow!("Error parsing input: {}", err)) +} diff --git a/modules/openapi-generator/src/main/resources/rust-server/cargo-config b/modules/openapi-generator/src/main/resources/rust-server/cargo-config index b8acc9c00c8c..df91f0f117f3 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/cargo-config +++ b/modules/openapi-generator/src/main/resources/rust-server/cargo-config @@ -6,7 +6,8 @@ rustflags = [ "-W", "trivial_numeric_casts", # detects trivial casts of numeric types which could be removed - "-W", "unsafe_code", # usage of `unsafe` code + # unsafe is used in `TokioIo` bridging code copied from `hyper`. + # "-W", "unsafe_code", # usage of `unsafe` code "-W", "unused_qualifications", # detects unnecessarily qualified names diff --git a/modules/openapi-generator/src/main/resources/rust-server/client-callbacks.mustache b/modules/openapi-generator/src/main/resources/rust-server/client-callbacks.mustache index 44e16903d948..f79bfe5c9cfb 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/client-callbacks.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/client-callbacks.mustache @@ -18,11 +18,14 @@ use crate::{{{operationId}}}Response; {{#callbacks}} {{>server-paths}} + {{/callbacks}} {{>server-make-service}} + {{>server-service-header}} + {{#apiInfo}} {{#apis}} {{#operations}} @@ -31,6 +34,7 @@ use crate::{{{operationId}}}Response; {{#urls}} {{#requests}} {{>server-operation}} + {{/requests}} {{/urls}} {{/callbacks}} @@ -44,6 +48,7 @@ use crate::{{{operationId}}}Response; {{/pathSet}} {{/callbacks}} {{>server-service-footer}} + /// Request parser for `Api`. pub struct ApiRequestParser; impl RequestParser for ApiRequestParser { @@ -58,7 +63,7 @@ impl RequestParser for ApiRequestParser { {{#urls}} {{#requests}} // {{{operationId}}} - {{{httpMethod}}} {{{path}}} - hyper::Method::{{{vendorExtensions.x-http-method}}} if path.matched(paths::ID_{{{vendorExtensions.x-path-id}}}) => Some("{{{operationId}}}"), + hyper::Method::{{{exts.x-http-method}}} if path.matched(paths::ID_{{{exts.x-path-id}}}) => Some("{{{operationId}}}"), {{/requests}} {{/urls}} {{/callbacks}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/client-imports.mustache b/modules/openapi-generator/src/main/resources/rust-server/client-imports.mustache index f4a0bbd93cc1..649de2d79b39 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/client-imports.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/client-imports.mustache @@ -1,10 +1,12 @@ use async_trait::async_trait; +use bytes::Bytes; use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt}; +use http_body_util::{combinators::BoxBody, Full}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; -use hyper::{Body, Request, Response, service::Service, Uri}; +use hyper::{body::{Body, Incoming}, Request, Response, service::Service, Uri}; use percent_encoding::{utf8_percent_encode, AsciiSet}; use std::borrow::Cow; -use std::convert::TryInto; +use std::convert::{TryInto, Infallible}; use std::io::{ErrorKind, Read}; use std::error::Error; use std::future::Future; @@ -18,6 +20,7 @@ use std::string::ToString; use std::task::{Context, Poll}; use swagger::{ApiError, AuthData, BodyExt, Connector, DropContextService, Has, XSpanIdString}; use url::form_urlencoded; +use tower_service::Service as _; {{#apiUsesMultipartFormData}} use mime::Mime; @@ -25,8 +28,8 @@ use std::io::Cursor; use multipart::client::lazy::Multipart; {{/apiUsesMultipartFormData}} {{#apiUsesMultipartRelated}} -use hyper_0_10::header::{Headers, ContentType}; -use mime_multipart::{Node, Part, generate_boundary, write_multipart}; +use hyper::header::HeaderMap; +use mime_multipart::{Node, Part, write_multipart}; {{/apiUsesMultipartRelated}} use crate::models; diff --git a/modules/openapi-generator/src/main/resources/rust-server/client-mod.mustache b/modules/openapi-generator/src/main/resources/rust-server/client-mod.mustache index c49bdd656df7..cc9569c92b78 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/client-mod.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/client-mod.mustache @@ -22,15 +22,14 @@ fn into_base_path(input: impl TryInto, } let host = uri.host().ok_or(ClientInitError::MissingHost)?; - let port = uri.port_u16().map(|x| format!(":{}", x)).unwrap_or_default(); - Ok(format!("{}://{}{}{}", scheme, host, port, uri.path().trim_end_matches('/'))) + let port = uri.port_u16().map(|x| format!(":{x}")).unwrap_or_default(); + Ok(format!("{scheme}://{host}{port}{}", uri.path().trim_end_matches('/'))) } /// A client that implements the API by making HTTP calls out to a server. pub struct Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -47,8 +46,7 @@ pub struct Client where impl fmt::Debug for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -60,8 +58,7 @@ impl fmt::Debug for Client where impl Clone for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -75,8 +72,19 @@ impl Clone for Client where } } -impl Client, C>, C> where - Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static, +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + Connector, + BoxBody + > + >, + C + >, + C +> where + Connector: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static, C: Clone + Send + Sync + 'static, { /// Create a client with a custom implementation of hyper::client::Connect. @@ -90,7 +98,7 @@ impl Client" /// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")` /// * `connector` - Implementation of `hyper::client::Connect` to use for the client pub fn try_new_with_connector( @@ -99,8 +107,8 @@ impl Client Result { - let client_service = hyper::client::Client::builder().build(connector); - let client_service = DropContextService::new(client_service); + let client_service = hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector); + let client_service = DropContextService::new(hyper_util::service::TowerToHyperService::new(client_service)); Ok(Self { client_service, @@ -110,28 +118,29 @@ impl Client; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HyperHttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + #[derive(Debug, Clone)] pub enum HyperClient { - Http(hyper::client::Client), - Https(hyper::client::Client), + Http(hyper_util::client::legacy::Client>), + #[cfg(feature = "client-tls")] + Https(hyper_util::client::legacy::Client>), } -impl Service> for HyperClient { - type Response = Response; - type Error = hyper::Error; - type Future = hyper::client::ResponseFuture; - - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - match self { - HyperClient::Http(client) => client.poll_ready(cx), - HyperClient::Https(client) => client.poll_ready(cx), - } - } +impl Service>> for HyperClient { + type Response = Response; + type Error = hyper_util::client::legacy::Error; + type Future = hyper_util::client::legacy::ResponseFuture; - fn call(&mut self, req: Request) -> Self::Future { + fn call(&self, req: Request>) -> Self::Future { match self { - HyperClient::Http(client) => client.call(req), - HyperClient::Https(client) => client.call(req) + HyperClient::Http(client) => client.request(req), + #[cfg(feature = "client-tls")] + HyperClient::Https(client) => client.request(req), } } } @@ -142,7 +151,7 @@ impl Client, C> where /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new( base_path: &str, ) -> Result { @@ -155,13 +164,19 @@ impl Client, C> where let client_service = match scheme.as_str() { "http" => { - HyperClient::Http(hyper::client::Client::builder().build(connector.build())) + HyperClient::Http(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector.build())) + }, + #[cfg(feature = "client-tls")] + "https" => { + let https_connector = connector + .https() + .build() + .map_err(ClientInitError::SslError)?; + HyperClient::Https(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(https_connector)) }, + #[cfg(not(feature = "client-tls"))] "https" => { - let connector = connector.https() - .build() - .map_err(ClientInitError::SslError)?; - HyperClient::Https(hyper::client::Client::builder().build(connector)) + return Err(ClientInitError::TlsNotEnabled); }, _ => { return Err(ClientInitError::InvalidScheme); @@ -178,13 +193,24 @@ impl Client, C> where } } -impl Client, C>, C> where +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + hyper_util::client::legacy::connect::HttpConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new_http( base_path: &str, ) -> Result { @@ -194,19 +220,46 @@ impl Client; - -#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] -type HttpsConnector = hyper_openssl::HttpsConnector; - -impl Client, C>, C> where +#[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] +type HttpsConnector = hyper_tls::HttpsConnector; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + +#[cfg(feature = "client-tls")] +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + HttpsConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { - /// Create a client with a TLS connection to the server + /// Create a client with a TLS connection to the server. + /// + /// # Arguments + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + pub fn try_new_https(base_path: &str) -> Result + { + let https_connector = Connector::builder() + .https() + .build() + .map_err(ClientInitError::SslError)?; + Self::try_new_with_connector(base_path, Some("https"), https_connector) + } + + /// Create a client with a TLS connection to the server using OpenSSL via swagger. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn try_new_https(base_path: &str) -> Result { let https_connector = Connector::builder() @@ -216,10 +269,10 @@ impl Client, C Self::try_new_with_connector(base_path, Some("https"), https_connector) } - /// Create a client with a TLS connection to the server using a pinned certificate + /// Create a client with a TLS connection to the server using a pinned certificate. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn try_new_https_pinned( @@ -240,7 +293,7 @@ impl Client, C /// Create a client with a mutually authenticated TLS connection to the server. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server /// * `client_key` - Path to the client private key /// * `client_certificate` - Path to the client's public certificate associated with the private key @@ -268,8 +321,7 @@ impl Client, C impl Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -303,12 +355,15 @@ pub enum ClientInitError { /// Missing Hostname MissingHost, + /// HTTPS requested but TLS features not enabled + TlsNotEnabled, + /// SSL Connection Error - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + #[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] SslError(native_tls::Error), /// SSL Connection Error - #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] SslError(openssl::error::ErrorStack), } @@ -331,28 +386,30 @@ impl Error for ClientInitError { } } +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + #[async_trait] -impl Api for Client where +impl Api for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C), + Response=Response> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Has {{#hasAuthMethods}}+ Has>{{/hasAuthMethods}} + Clone + Send + Sync + 'static, + B: hyper::body::Body + Send + 'static + Unpin, + B::Data: Send, + B::Error: Into>, { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - match self.client_service.clone().poll_ready(cx) { - Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())), - Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)), - Poll::Pending => Poll::Pending, - } - } {{#apiInfo}} {{#apis}} {{#operations}} {{#operation}} {{>client-operation}} + {{/operation}} {{/operations}} {{/apis}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/client-operation.mustache b/modules/openapi-generator/src/main/resources/rust-server/client-operation.mustache index f74833a77a51..d231cadd51a5 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/client-operation.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/client-operation.mustache @@ -1,32 +1,34 @@ - async fn {{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}( + #[allow(clippy::vec_init_then_push)] + async fn {{#exts}}{{{x-operation-id}}}{{/exts}}{{#exts.x-has-borrowed-params}}<'a>{{/exts.x-has-borrowed-params}}( &self, -{{#vendorExtensions}} +{{#exts}} {{#x-callback-params}} callback_{{.}}: String, {{/x-callback-params}} -{{/vendorExtensions}} +{{/exts}} {{#allParams}} - param_{{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{{dataType}}}{{^required}}>{{/required}}, + param_{{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{#exts.x-param-needs-lifetime}}'a {{/exts.x-param-needs-lifetime}}{{/isArray}}{{{dataType}}}{{^required}}>{{/required}}, {{/allParams}} context: &C) -> Result<{{{operationId}}}Response, ApiError> { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( {{#isCallbackRequest}} - "{{vendorExtensions.x-path-format-string}}" + "{{exts.x-path-format-string}}" {{/isCallbackRequest}} {{^isCallbackRequest}} - "{}{{^servers}}{{{basePathWithoutHost}}}{{/servers}}{{#servers.0}}{{{url}}}{{/servers.0}}{{vendorExtensions.x-path-format-string}}", + "{}{{^servers}}{{{basePathWithoutHost}}}{{/servers}}{{#servers.0}}{{{url}}}{{/servers.0}}{{exts.x-path-format-string}}", self.base_path {{/isCallbackRequest}} {{#pathParams}} ,{{{paramName}}}=utf8_percent_encode(¶m_{{{paramName}}}.to_string(), ID_ENCODE_SET) {{/pathParams}} -{{#vendorExtensions}} +{{#exts}} {{#x-callback-params}} ,{{.}}=callback_{{.}} {{/x-callback-params}} -{{/vendorExtensions}} +{{/exts}} ); // Query parameters @@ -37,11 +39,11 @@ if let Some(param_{{{paramName}}}) = param_{{{paramName}}} { {{/required}} query_string.append_pair("{{{baseName}}}", - {{#vendorExtensions}} + {{#exts}} {{#x-consumes-json}} &match serde_json::to_string(¶m_{{{paramName}}}) { Ok(str) => str, - Err(e) => return Err(ApiError(format!("Unable to serialize {{{paramName}}} to string: {}", e))), + Err(e) => return Err(ApiError(format!("Unable to serialize {{{paramName}}} to string: {e}"))), }); {{/x-consumes-json}} {{^x-consumes-json}} @@ -52,7 +54,7 @@ ¶m_{{{paramName}}}{{^isString}}.to_string(){{/isString}}); {{/isArray}} {{/x-consumes-json}} - {{/vendorExtensions}} + {{/exts}} {{^required}} } {{/required}} @@ -75,278 +77,76 @@ let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() - .method("{{{vendorExtensions.x-http-method}}}") + .method("{{{exts.x-http-method}}}") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; +{{>client-request-body-instance}} -{{#vendorExtensions}} - {{#x-consumes-multipart}} - let (body_string, multipart_header) = { - let mut multipart = Multipart::new(); - - {{#vendorExtensions}} - {{#formParams}} - {{#-first}} - // For each parameter, encode as appropriate and add to the multipart body as a stream. - {{/-first}} - - {{^isByteArray}} - {{#jsonSchema}} - let {{{paramName}}}_str = match serde_json::to_string(¶m_{{{paramName}}}) { - Ok(str) => str, - Err(e) => return Err(ApiError(format!("Unable to serialize {{{paramName}}} to string: {}", e))), - }; - - let {{{paramName}}}_vec = {{{paramName}}}_str.as_bytes().to_vec(); - let {{{paramName}}}_mime = mime_0_2::Mime::from_str("application/json").expect("impossible to fail to parse"); - let {{{paramName}}}_cursor = Cursor::new({{{paramName}}}_vec); - - multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, None as Option<&str>, Some({{{paramName}}}_mime)); - {{/jsonSchema}} - {{/isByteArray}} - - {{#isByteArray}} - let {{{paramName}}}_vec = param_{{{paramName}}}.to_vec(); - - let {{{paramName}}}_mime = match mime_0_2::Mime::from_str("application/octet-stream") { - Ok(mime) => mime, - Err(err) => return Err(ApiError(format!("Unable to get mime type: {:?}", err))), - }; - - let {{{paramName}}}_cursor = Cursor::new({{{paramName}}}_vec); - - let filename = None as Option<&str> ; - multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, filename, Some({{{paramName}}}_mime)); - {{/isByteArray}} - {{/formParams}} - {{/vendorExtensions}} - - let mut fields = match multipart.prepare() { - Ok(fields) => fields, - Err(err) => return Err(ApiError(format!("Unable to build request: {}", err))), - }; - - let mut body_string = String::new(); - - match fields.read_to_string(&mut body_string) { - Ok(_) => (), - Err(err) => return Err(ApiError(format!("Unable to build body: {}", err))), - } - - let boundary = fields.boundary(); - - let multipart_header = format!("multipart/form-data;boundary={}", boundary); - - (body_string, multipart_header) - }; - - *request.body_mut() = Body::from(body_string); - - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(&multipart_header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", multipart_header, e))) - }); - - {{/x-consumes-multipart}} - {{^x-consumes-multipart}} - {{#vendorExtensions}} - {{^x-consumes-multipart-related}} - {{#formParams}} - {{#-first}} - let params = &[ - {{/-first}} - ("{{{baseName}}}", {{#vendorExtensions}}{{#required}}Some({{#isString}}param_{{{paramName}}}{{/isString}}{{^isString}}format!("{:?}", param_{{{paramName}}}){{/isString}}){{/required}}{{^required}}{{#isString}}param_{{{paramName}}}{{/isString}}{{^isString}}param_{{{paramName}}}.map(|param| format!("{:?}", param)){{/isString}}{{/required}}{{/vendorExtensions}}), - {{#-last}} - ]; - let body = serde_urlencoded::to_string(params).expect("impossible to fail to serialize"); - - let header = "{{#consumes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/consumes}}{{^consumes}}application/json{{/consumes}}"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); - *request.body_mut() = Body::from(body.into_bytes()); - {{/-last}} - {{/formParams}} - {{/x-consumes-multipart-related}} - {{#x-consumes-multipart-related}} - {{#formParams}} - {{#-first}} - // Construct the Body for a multipart/related request. The mime 0.2.6 library - // does not parse quoted-string parameters correctly. The boundary doesn't - // need to be a quoted string if it does not contain a '/', hence ensure - // no such boundary is used. - let mut boundary = generate_boundary(); - for b in boundary.iter_mut() { - if b == &(b'/') { - *b = b'='; - } - } - - let mut body_parts = vec![]; - {{/-first}} - -{{#required}} - { -{{/required}} -{{^required}} - if let Some({{{paramName}}}) = param_{{{paramName}}} { -{{/required}} - let part = Node::Part(Part { - headers: { - let mut h = Headers::new(); - h.set(ContentType("{{{contentType}}}".parse().unwrap())); - h.set_raw("Content-ID", vec![b"{{{baseName}}}".to_vec()]); - h - }, - {{#isBinary}} - body: {{#required}}param_{{/required}}{{{paramName}}}.0, - {{/isBinary}} - {{^isBinary}} - body: serde_json::to_string(&{{{paramName}}}) - .expect("Impossible to fail to serialize") - .into_bytes(), - {{/isBinary}} - }); - body_parts.push(part); - } - {{#-last}} - - // Write the body into a vec. - let mut body: Vec = vec![]; - write_multipart(&mut body, &boundary, &body_parts) - .expect("Failed to write multipart body"); - - // Add the message body to the request object. - *request.body_mut() = Body::from(body); - - let header = "{{#consumes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/consumes}}{{^consumes}}application/json{{/consumes}}"; - request.headers_mut().insert(CONTENT_TYPE, - match HeaderValue::from_bytes( - &[header.as_bytes(), "; boundary=".as_bytes(), &boundary, "; type=\"application/json\"".as_bytes()].concat() - ) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); - - {{/-last}} - {{/formParams}} - {{/x-consumes-multipart-related}} -{{/vendorExtensions}} -{{#bodyParam}} - {{#-first}} - // Body parameter - {{/-first}} - {{#vendorExtensions}} - {{#x-consumes-plain-text}} - {{#isByteArray}} - let body = param_{{{paramName}}}.0; - {{/isByteArray}} - {{^isByteArray}} - let body = param_{{{paramName}}}; - {{/isByteArray}} - {{/x-consumes-plain-text}} - {{#required}} - {{#x-consumes-xml}} - let body = param_{{{paramName}}}.as_xml(); - {{/x-consumes-xml}} - {{#x-consumes-json}} - let body = serde_json::to_string(¶m_{{{paramName}}}).expect("impossible to fail to serialize"); - {{/x-consumes-json}} - {{/required}} - {{^required}} - let body = param_{{{paramName}}}.map(|ref body| { - {{#x-consumes-xml}} - body.as_xml() - {{/x-consumes-xml}} - {{#x-consumes-json}} - serde_json::to_string(body).expect("impossible to fail to serialize") - {{/x-consumes-json}} - }); - {{/required}} - {{/vendorExtensions}} - {{#-last}} - - {{/-last}} -{{/bodyParam}} -{{#bodyParam}} - {{^required}} - if let Some(body) = body { - {{/required}} - *request.body_mut() = Body::from(body); - {{^required}} - } - {{/required}} - - let header = "{{#consumes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/consumes}}{{^consumes}}application/json{{/consumes}}"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); - {{#-last}} - - {{/-last}} -{{/bodyParam}} -{{/x-consumes-multipart}} -{{/vendorExtensions}} let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); {{#hasAuthMethods}} #[allow(clippy::collapsible_match)] if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported + use headers::authorization::Credentials; #[allow(clippy::single_match, clippy::match_single_binding)] match auth_data { {{#authMethods}} {{#isBasicBasic}} - AuthData::Basic(basic_header) => { - let auth = swagger::auth::Header(basic_header.clone()); - let header = match HeaderValue::from_str(&format!("{}", auth)) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e))) - }; + AuthData::Basic(ref basic_user, ref basic_password) => { + let auth = headers::Authorization::basic(basic_user.as_str(), basic_password.as_str()); request.headers_mut().insert( hyper::header::AUTHORIZATION, - header); + auth.0.encode()); }, {{/isBasicBasic}} {{#isBasicBearer}} - AuthData::Bearer(bearer_header) => { - let auth = swagger::auth::Header(bearer_header.clone()); - let header = match HeaderValue::from_str(&format!("{}", auth)) { + AuthData::Bearer(ref bearer_header) => { + let header = match headers::Authorization::bearer(&bearer_header.to_string()) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {e}"))) }; request.headers_mut().insert( hyper::header::AUTHORIZATION, - header); + header.0.encode()); }, {{/isBasicBearer}} {{#isOAuth}} {{^isBasicBearer}} - AuthData::Bearer(bearer_header) => { - let auth = swagger::auth::Header(bearer_header.clone()); - let header = match HeaderValue::from_str(&format!("{}", auth)) { + AuthData::Bearer(ref bearer_header) => { + let header = match headers::Authorization::bearer(&bearer_header.to_string()) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {e}"))) }; request.headers_mut().insert( hyper::header::AUTHORIZATION, - header); + header.0.encode()); }, {{/isBasicBearer}} {{/isOAuth}} + {{#isApiKey}} + {{#isKeyInHeader}} + AuthData::ApiKey(ref api_key) => { + let header = match HeaderValue::from_str(api_key.as_str()) { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create header: {e}"))) + }; + request.headers_mut().insert( + HeaderName::from_static("{{#lambda.lowercase}}{{{keyParamName}}}{{/lambda.lowercase}}"), + header); + }, + {{/isKeyInHeader}} + {{/isApiKey}} {{/authMethods}} _ => {} } @@ -365,12 +165,12 @@ {{/required}} request.headers_mut().append( HeaderName::from_static("{{{nameInLowerCase}}}"), - #[allow(clippy::redundant_clone)] + #[allow(clippy::redundant_clone, clippy::clone_on_copy)] match header::IntoHeaderValue(param_{{{paramName}}}.clone()).try_into() { Ok(header) => header, Err(e) => { return Err(ApiError(format!( - "Invalid header {{{paramName}}} - {}", e))); + "Invalid header {{{paramName}}} - {e}"))); }, }); {{^required}} @@ -385,7 +185,7 @@ {{/headerParams}} let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { {{#responses}} @@ -397,7 +197,7 @@ let response_{{{name}}} = match TryInto::>::try_into(response_{{{name}}}) { Ok(value) => value, Err(e) => { - return Err(ApiError(format!("Invalid response header {{baseName}} for response {{code}} - {}", e))); + return Err(ApiError(format!("Invalid response header {{baseName}} for response {{code}} - {e}"))); }, }; {{#required}} @@ -418,33 +218,15 @@ {{/headers}} {{#dataType}} let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; -{{#vendorExtensions}} -{{#x-produces-bytes}} - let body = swagger::ByteArray(body.to_vec()); -{{/x-produces-bytes}} -{{^x-produces-bytes}} - let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - {{#x-produces-xml}} - // ToDo: this will move to swagger-rs and become a standard From conversion trait - // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream - let body = serde_xml_rs::from_str::<{{{dataType}}}>(body) - .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?; - {{/x-produces-xml}} - {{#x-produces-json}} - let body = serde_json::from_str::<{{{dataType}}}>(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; - {{/x-produces-json}} - {{#x-produces-plain-text}} - let body = body.to_string(); - {{/x-produces-plain-text}} -{{/x-produces-bytes}} -{{/vendorExtensions}} - Ok({{{operationId}}}Response::{{#vendorExtensions}}{{x-response-id}}{{/vendorExtensions}} + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + +{{>client-response-body-instance}} + + + Ok({{{operationId}}}Response::{{#exts}}{{x-response-id}}{{/exts}} {{^headers}} (body) {{/headers}} @@ -462,7 +244,7 @@ {{/dataType}} {{^dataType}} Ok( - {{{operationId}}}Response::{{#vendorExtensions}}{{x-response-id}}{{/vendorExtensions}} + {{{operationId}}}Response::{{#exts}}{{x-response-id}}{{/exts}} {{#headers}} {{#-first}} { @@ -478,18 +260,16 @@ {{/responses}} code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } diff --git a/modules/openapi-generator/src/main/resources/rust-server/client-request-body-instance.mustache b/modules/openapi-generator/src/main/resources/rust-server/client-request-body-instance.mustache new file mode 100644 index 000000000000..55806f12df72 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/rust-server/client-request-body-instance.mustache @@ -0,0 +1,111 @@ +{{#exts}} + {{#x-consumes-multipart-form}} + + // Consumes multipart/form body +{{>client-request-body-multipart-form}} + + {{/x-consumes-multipart-form}} + {{#x-consumes-multipart-related}} + + // Consumes multipart/related body + {{#formParams}} +{{>generate-multipart-related}} + + {{/formParams}} + + let header = "multipart/related"; + request.headers_mut().insert(CONTENT_TYPE, + match HeaderValue::from_bytes( + &[header.as_bytes(), "; boundary=".as_bytes(), &boundary, "; type=\"application/json\"".as_bytes()].concat() + ) { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create header: {header} - {e}"))) + }); + + // Add the message body to the request object. + *request.body_mut() = BoxBody::new(Full::new(Bytes::from(body))); + {{/x-consumes-multipart-related}} + {{#x-consumes-form}} + + // Consumes form body + {{#formParams}} + {{#-first}} + let mut params = vec![]; + {{/-first}} + {{^required}} + if let Some(param_{{{paramName}}}) = param_{{{paramName}}} { + {{/required}} + {{#isArray}} + // style=form,explode=true + for param_{{{paramName}}} in param_{{{paramName}}} { + {{/isArray}} + #[allow(clippy::uninlined_format_args)] + params.push(("{{{baseName}}}", + {{^isString}} + format!("{{{exts.x-format-string}}}", param_{{{paramName}}}) + {{/isString}} + {{#isString}} + {{#isArray}} + param_{{{paramName}}}.to_string() + {{/isArray}} + {{^isArray}} + param_{{{paramName}}} + {{/isArray}} + {{/isString}} + )); + {{#isArray}} + } + {{/isArray}} + {{^required}} + } + {{/required}} + {{#-last}} + + let body = serde_urlencoded::to_string(params).expect("impossible to fail to serialize"); + + *request.body_mut() = body_from_string(body); + + let header = "{{#consumes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/consumes}}{{^consumes}}application/json{{/consumes}}"; + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + {{/-last}} + {{/formParams}} + {{/x-consumes-form}} + {{#x-consumes-basic}} + + // Consumes basic body + {{#bodyParam}} + // Body parameter + {{^required}} + if let Some(param_{{{paramName}}}) = param_{{{paramName}}} { + {{/required}} + {{#exts}} + {{#x-consumes-plain-text}} + {{^isByteArray}} + {{^isBinary}} + let body = param_{{{paramName}}}; + {{/isBinary}} + {{/isByteArray}} + {{#isByteArray}} + let body = String::from_utf8(param_{{{paramName}}}.0).expect("Body was not valid UTF8"); + {{/isByteArray}} + {{#isBinary}} + let body = String::from_utf8(param_{{{paramName}}}.0).expect("Body was not valid UTF8"); + {{/isBinary}} + {{/x-consumes-plain-text}} + {{#x-consumes-xml}} + let body = param_{{{paramName}}}.as_xml(); + {{/x-consumes-xml}} + {{#x-consumes-json}} + let body = serde_json::to_string(¶m_{{{paramName}}}).expect("impossible to fail to serialize"); + {{/x-consumes-json}} + {{/exts}} + *request.body_mut() = body_from_string(body); + {{^required}} + } + {{/required}} + + let header = "{{#consumes}}{{#-first}}{{{mediaType}}}{{/-first}}{{/consumes}}{{^consumes}}application/json{{/consumes}}"; + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + {{/bodyParam}} + {{/x-consumes-basic}} +{{/exts}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/client-request-body-multipart-form.mustache b/modules/openapi-generator/src/main/resources/rust-server/client-request-body-multipart-form.mustache new file mode 100644 index 000000000000..c630a21eb43e --- /dev/null +++ b/modules/openapi-generator/src/main/resources/rust-server/client-request-body-multipart-form.mustache @@ -0,0 +1,65 @@ + let (body_bytes, multipart_header) = { + let mut multipart = Multipart::new(); + + {{#exts}} + {{#formParams}} + {{#-first}} + // For each parameter, encode as appropriate and add to the multipart body as a stream. + {{/-first}} + + {{^isByteArray}} + {{#jsonSchema}} + let {{{paramName}}}_str = match serde_json::to_string(¶m_{{{paramName}}}) { + Ok(str) => str, + Err(e) => return Err(ApiError(format!("Unable to serialize {{{paramName}}} to string: {e}"))), + }; + + let {{{paramName}}}_vec = {{{paramName}}}_str.as_bytes().to_vec(); + let {{{paramName}}}_mime = mime::Mime::from_str("application/json").expect("impossible to fail to parse"); + let {{{paramName}}}_cursor = Cursor::new({{{paramName}}}_vec); + + multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, None as Option<&str>, Some({{{paramName}}}_mime)); + {{/jsonSchema}} + {{/isByteArray}} + + {{#isByteArray}} + let {{{paramName}}}_vec = param_{{{paramName}}}.to_vec(); + + let {{{paramName}}}_mime = match mime::Mime::from_str("application/octet-stream") { + Ok(mime) => mime, + Err(err) => return Err(ApiError(format!("Unable to get mime type: {err:?}"))), + }; + + let {{{paramName}}}_cursor = Cursor::new({{{paramName}}}_vec); + + let filename = None as Option<&str> ; + multipart.add_stream("{{{paramName}}}", {{{paramName}}}_cursor, filename, Some({{{paramName}}}_mime)); + {{/isByteArray}} + {{/formParams}} + {{/exts}} + + let mut fields = match multipart.prepare() { + Ok(fields) => fields, + Err(err) => return Err(ApiError(format!("Unable to build request: {err}"))), + }; + + let mut body_bytes = Vec::new(); + + match fields.read_to_end(&mut body_bytes) { + Ok(_) => (), + Err(err) => return Err(ApiError(format!("Unable to build body: {err}"))), + } + + let boundary = fields.boundary(); + + let multipart_header = format!("multipart/form-data;boundary={boundary}"); + + (body_bytes, multipart_header) + }; + + *request.body_mut() = BoxBody::new(Full::new(Bytes::from(body_bytes))); + + request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(&multipart_header) { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create header: {multipart_header} - {e}"))) + }); diff --git a/modules/openapi-generator/src/main/resources/rust-server/client-response-body-instance.mustache b/modules/openapi-generator/src/main/resources/rust-server/client-response-body-instance.mustache new file mode 100644 index 000000000000..a560e6fe479d --- /dev/null +++ b/modules/openapi-generator/src/main/resources/rust-server/client-response-body-instance.mustache @@ -0,0 +1,22 @@ +{{#exts}} + {{#x-produces-bytes}} + let body = swagger::ByteArray(body.to_vec()); + {{/x-produces-bytes}} + {{^x-produces-bytes}} + let body = str::from_utf8(&body) + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + {{#x-produces-xml}} + // ToDo: this will move to swagger-rs and become a standard From conversion trait + // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream + let body = serde_xml_rs::from_str::<{{{dataType}}}>(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + {{/x-produces-xml}} + {{#x-produces-json}} + let body = serde_json::from_str::<{{{dataType}}}>(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + {{/x-produces-json}} + {{#x-produces-plain-text}} + let body = body.to_string(); + {{/x-produces-plain-text}} + {{/x-produces-bytes}} +{{/exts}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/client-response-body-multipart-related.mustache b/modules/openapi-generator/src/main/resources/rust-server/client-response-body-multipart-related.mustache new file mode 100644 index 000000000000..ee3352a30fff --- /dev/null +++ b/modules/openapi-generator/src/main/resources/rust-server/client-response-body-multipart-related.mustache @@ -0,0 +1,76 @@ +// Create headers from top-level content type header. +let multipart_headers = match swagger::multipart::related::create_multipart_headers(header.headers.get(CONTENT_TYPE)) { + Ok(headers) => headers, + Err(e) => { + return Err(ApiError(e)); + } +}; + +// &*body expresses the body as a byteslice, &mut provides a +// mutable reference to that byteslice. +let nodes = match read_multipart_body(&mut&*body, &multipart_headers, false) { + Ok(nodes) => nodes, + Err(e) => { + return Err(ApiError(format!("Could not read multipart body for {{operationId}}: {e}"))); + } +}; + +{{#formParams}} +let mut param_{{{paramName}}} = None; +{{/formParams}} + +for node in nodes { + if let Node::Part(part) = node { + let content_type = part.content_type().map(|x| format!("{x}")); + match content_type.as_ref().map(|x| x.as_str()) { +{{#formParams}} + {{^isBinary}} + Some("{{{contentType}}}") if param_{{{paramName}}}.is_none() => { + // Extract JSON part. + let deserializer = &mut serde_json::Deserializer::from_slice(part.body.as_slice()); + let json_data: {{{dataType}}} = match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in JSON part: {path}"); + }) { + Ok(json_data) => json_data, + Err(e) => return Err(ApiError(format!("Couldn't parse body parameter {{dataType}} - doesn't match schema: {e}"))) + }; + // Push JSON part to return object. + param_{{{paramName}}}.get_or_insert(json_data); + }, + {{/isBinary}} + {{#isBinary}} + Some("{{{contentType}}}") if param_{{{paramName}}}.is_none() => { + param_{{{paramName}}}.get_or_insert(swagger::ByteArray(part.body)); + }, + {{/isBinary}} +{{/formParams}} + Some(content_type) => { + warn!("Ignoring unexpected content type: {content_type}"); + }, + None => { + warn!("Missing content type"); + }, + } + } else { + return Err(ApiError(format!("Unexpected part in multipart body for {{operationId}}: {node:?}"))); + } +} +{{#formParams}} + {{#-first}} + +// Check that the required multipart chunks are present. + {{/-first}} + {{#required}} +let param_{{{paramName}}} = match param_{{{paramName}}} { + Some(x) => x, + None => return Err(ApiError("Missing required multipart/related parameter {{{paramName}}}")) +}; + {{/required}} +{{/formParams}} + {{^exts.x-consumes-basic}} + let body = {{{dataType}}} { + {{#formParams}} + {{{paramName}}}: param_{{{paramName}}}, + {{/formParams}} + }; + {{/exts.x-consumes-basic}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/context.mustache b/modules/openapi-generator/src/main/resources/rust-server/context.mustache index 061bd4fbf2d8..b9ac507eb5e2 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/context.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/context.mustache @@ -6,9 +6,9 @@ use std::default::Default; use std::io; use std::marker::PhantomData; use std::task::{Poll, Context}; -use swagger::auth::{AuthData, Authorization, Bearer, Scopes}; +use swagger::auth::{AuthData, Authorization, Scopes}; use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString}; -use crate::{Api, AuthenticationApi}; +use crate::Api; use log::error; pub struct MakeAddContext { @@ -16,11 +16,11 @@ pub struct MakeAddContext { marker: PhantomData, } -impl MakeAddContext +impl MakeAddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, + C: Send + 'static, { pub fn new(inner: T) -> MakeAddContext { MakeAddContext { @@ -30,27 +30,34 @@ where } } +impl Clone for MakeAddContext +where + T: Clone, +{ + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + // Make a service that adds context. -impl Service for +impl Service for MakeAddContext where Target: Send, A: Default + Push + Send, B: Push, Result = C>, - C: Push, Result = D>, - D: Send + 'static, + C: Send + 'static, T: Service + Send, T::Future: Send + 'static { type Error = T::Error; - type Response = AddContext; + type Response = AddContext; type Future = BoxFuture<'static, Result>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, target: Target) -> Self::Future { + fn call(&self, target: Target) -> Self::Future { let service = self.inner.call(target); Box::pin(async move { @@ -60,21 +67,17 @@ where } /// Middleware to add context data from the request -pub struct AddContext -where - A: Default + Push, - B: Push, Result = C>, - C: Push, Result = D> +#[derive(Debug, Clone)] +pub struct AddContext { inner: T, marker: PhantomData, } -impl AddContext +impl AddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, { pub fn new(inner: T) -> Self { AddContext { @@ -84,24 +87,18 @@ where } } -impl Service> for AddContext +impl Service> for AddContext where A: Default + Push, B: Push, Result=C>, - C: Push, Result=D>, - D: Send + 'static, - T: Service<(Request, D)> + AuthenticationApi + C: Send + 'static, + T: Service<(Request, C)> { type Error = T::Error; type Future = T::Future; type Response = T::Response; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - - fn call(&mut self, request: Request) -> Self::Future { + fn call(&self, request: Request) -> Self::Future { let context = A::default().push(XSpanIdString::get_or_generate(&request)); let headers = request.headers(); @@ -109,20 +106,9 @@ impl Service> for AddContext(headers) { - let authorization = self.inner.basic_authorization(&basic); - let auth_data = AuthData::Basic(basic); - - let context = context.push(Some(auth_data)); - let context = match authorization { - Ok(auth) => context.push(Some(auth)), - Err(err) => { - error!("Error during Authorization: {err:?}"); - context.push(None::) - } - }; + if let Some(auth) = swagger::auth::from_headers(headers) { + let context = context.push(Some(auth)); return self.inner.call((request, context)) } @@ -130,20 +116,10 @@ impl Service> for AddContext(headers) { - let authorization = self.inner.bearer_authorization(&bearer); - let auth_data = AuthData::Bearer(bearer); - - let context = context.push(Some(auth_data)); - let context = match authorization { - Ok(auth) => context.push(Some(auth)), - Err(err) => { - error!("Error during Authorization: {err:?}"); - context.push(None::) - } - }; + if let Some(bearer) = swagger::auth::from_headers(headers) { + let context = context.push(Some(bearer)); return self.inner.call((request, context)) } @@ -152,20 +128,10 @@ impl Service> for AddContext(headers) { - let authorization = self.inner.bearer_authorization(&bearer); - let auth_data = AuthData::Bearer(bearer); - - let context = context.push(Some(auth_data)); - let context = match authorization { - Ok(auth) => context.push(Some(auth)), - Err(err) => { - error!("Error during Authorization: {err:?}"); - context.push(None::) - } - }; + if let Some(bearer) = swagger::auth::from_headers(headers) { + let context = context.push(Some(bearer)); return self.inner.call((request, context)) } @@ -176,18 +142,9 @@ impl Service> for AddContext context.push(Some(auth)), - Err(err) => { - error!("Error during Authorization: {err:?}"); - context.push(None::) - } - }; return self.inner.call((request, context)) } @@ -200,18 +157,9 @@ impl Service> for AddContext context.push(Some(auth)), - Err(err) => { - error!("Error during Authorization: {err:?}"); - context.push(None::) - } - }; - return self.inner.call((request, context)) } } @@ -220,7 +168,6 @@ impl Service> for AddContext); - let context = context.push(None::); self.inner.call((request, context)) } diff --git a/modules/openapi-generator/src/main/resources/rust-server/example-client-main.mustache b/modules/openapi-generator/src/main/resources/rust-server/example-client-main.mustache index f452904d8459..30f515862c4d 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/example-client-main.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/example-client-main.mustache @@ -18,7 +18,7 @@ use {{{externCrateName}}}::{Api, ApiNoContext, Claims, Client, ContextWrapperExt {{/apis}} {{/apiInfo}} }; -use clap::{App, Arg}; +use clap::{Command, Arg}; // NOTE: Set environment variable RUST_LOG to the name of the executable (or "cargo run") to activate console logging for all loglevels. // See https://docs.rs/env_logger/latest/env_logger/ for more details @@ -41,37 +41,33 @@ use client_auth::build_token; fn main() { env_logger::init(); - let matches = App::new("client") - .arg(Arg::with_name("operation") + let matches = Command::new("client") + .arg(Arg::new("operation") .help("Sets the operation to run") - .possible_values(&[ + .value_parser(Vec::<&str>::from([ {{#apiInfo}} {{#apis}} {{#operations}} {{#operation}} - {{#vendorExtensions}} - {{^x-no-client-example}} - "{{{operationId}}}", - {{/x-no-client-example}} - {{/vendorExtensions}} + {{^exts.x-no-client-example}} + "{{{operationId}}}", + {{/exts.x-no-client-example}} {{/operation}} {{/operations}} {{/apis}} {{/apiInfo}} - ]) + ])) .required(true) .index(1)) - .arg(Arg::with_name("https") + .arg(Arg::new("https") .long("https") .help("Whether to use HTTPS or not")) - .arg(Arg::with_name("host") + .arg(Arg::new("host") .long("host") - .takes_value(true) .default_value("{{{serverHost}}}") .help("Hostname to contact")) - .arg(Arg::with_name("port") + .arg(Arg::new("port") .long("port") - .takes_value(true) .default_value("{{{serverPort}}}") .help("Port to contact")) .get_matches(); @@ -80,53 +76,74 @@ fn main() { // In a real (production) system this Bearer token should be obtained via an external Identity/Authentication-server // Ensure that you set the correct algorithm and encodingkey that matches what is used on the server side. // See https://github.com/Keats/jsonwebtoken for more information - let auth_token = build_token( Claims { - sub: "tester@acme.com".to_owned(), + sub: "tester@acme.com".to_owned(), company: "ACME".to_owned(), iss: "my_identity_provider".to_owned(), // added a very long expiry time aud: "org.acme.Resource_Server".to_string(), exp: 10000000000, // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ - {{#authMethods}} - {{#scopes}} + scopes: + {{#hasAuthScopes}} + [ + {{#authMethods}} + {{#scopes}} "{{{scope}}}", - {{/scopes}} - {{/authMethods}} - ].join(", ") - }, + {{/scopes}} + {{/authMethods}} + ].join::<&str>(", ") + {{/hasAuthScopes}} + {{^hasAuthScopes}} + "".to_owned() + {{/hasAuthScopes}} + }, b"secret").unwrap(); let auth_data = if !auth_token.is_empty() { - Some(AuthData::Bearer(swagger::auth::Bearer { token: auth_token})) + Some(AuthData::Bearer(auth_token)) } else { // No Bearer-token available, so return None None }; - let is_https = matches.is_present("https"); + let is_https = matches.contains_id("https"); let base_url = format!("{}://{}:{}", if is_https { "https" } else { "http" }, - matches.value_of("host").unwrap(), - matches.value_of("port").unwrap()); + matches.get_one::("host").unwrap(), + matches.get_one::("port").unwrap()); let context: ClientContext = swagger::make_context!(ContextBuilder, EmptyContext, auth_data, XSpanIdString::default()); - let mut client : Box> = if matches.is_present("https") { - // Using Simple HTTPS - let client = Box::new(Client::try_new_https(&base_url) - .expect("Failed to create HTTPS client")); - Box::new(client.with_context(context)) - } else { - // Using HTTP - let client = Box::new(Client::try_new_http( - &base_url) - .expect("Failed to create HTTP client")); - Box::new(client.with_context(context)) + let mut client : Box> = { + #[cfg(feature = "client-tls")] + { + if is_https { + // Using HTTPS with native-tls + let client = Box::new(Client::try_new_https(&base_url) + .expect("Failed to create HTTPS client")); + Box::new(client.with_context(context)) + } else { + // Using HTTP + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } + } + + #[cfg(not(feature = "client-tls"))] + { + if is_https { + panic!("HTTPS requested but TLS support not enabled. \ + Enable the 'client-tls' feature to use HTTPS."); + } + // Using HTTP only + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } }; let mut rt = tokio::runtime::Runtime::new().unwrap(); @@ -136,29 +153,29 @@ fn main() { rt.spawn(server::create("127.0.0.1:8081", false)); {{/hasCallbacks}} - match matches.value_of("operation") { + match matches.get_one::("operation").map(String::as_str) { {{#apiInfo}} {{#apis}} {{#operations}} {{#operation}} - {{#vendorExtensions}} + {{#exts}} {{#x-no-client-example}} /* Disabled because there's no example. {{/x-no-client-example}} - {{/vendorExtensions}} + {{/exts}} Some("{{{operationId}}}") => { - let result = rt.block_on(client.{{{vendorExtensions.x-operation-id}}}( + let result = rt.block_on(client.{{{exts.x-operation-id}}}( {{#allParams}} - {{{vendorExtensions.x-example}}}{{^-last}},{{/-last}} + {{{exts.x-example}}}{{^-last}},{{/-last}} {{/allParams}} )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, - {{#vendorExtensions}} + {{#exts}} {{#x-no-client-example}} */ {{/x-no-client-example}} - {{/vendorExtensions}} + {{/exts}} {{/operation}} {{/operations}} {{/apis}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/example-client-server.mustache b/modules/openapi-generator/src/main/resources/rust-server/example-client-server.mustache index 126af4cf7471..8dcc257086ca 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/example-client-server.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/example-client-server.mustache @@ -30,6 +30,7 @@ impl CallbackApi for Server where C: Has + Send + Sync {{#urls}} {{#requests}} {{>example-server-operation}} + {{/requests}} {{/urls}} {{/callbacks}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/example-server-auth.mustache b/modules/openapi-generator/src/main/resources/rust-server/example-server-auth.mustache index 148012048dd8..378d5b1a9a9a 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/example-server-auth.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/example-server-auth.mustache @@ -1,8 +1,8 @@ use swagger::{ ApiError, - auth::{Basic, Bearer}, - Has, + Has, XSpanIdString}; +use headers::authorization::{Basic, Bearer}; use {{{externCrateName}}}::{AuthenticationApi, Claims}; use crate::server::Server; use jsonwebtoken::{decode, errors as JwtError, decode_header, DecodingKey, TokenData, Validation}; @@ -15,29 +15,35 @@ use log::{error, debug}; /// Get a dummy claim with full permissions (all scopes) for testing purposes fn full_permission_claim() -> Claims { - Claims { - sub: "tester@acme.com".to_owned(), - company: "ACME".to_owned(), - iss: "mini-bank-IDP".to_owned(), - aud: "org.acme.Resource_Server".to_string(), - // added a very long expiry time - exp: 10000000000, - // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ - {{#authMethods}} - {{#scopes}} - "{{{scope}}}", - {{/scopes}} - {{/authMethods}} - ].join(", ") - } + // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. + Claims { + sub: "tester@acme.com".to_owned(), + company: "ACME".to_owned(), + iss: "mini-bank-IDP".to_owned(), + aud: "org.acme.Resource_Server".to_string(), + // added a very long expiry time + exp: 10000000000, + scopes: + {{#hasAuthScopes}} + [ + {{#authMethods}} + {{#scopes}} + "{{{scope}}}", + {{/scopes}} + {{/authMethods}} + ].join::<&str>(", ") + {{/hasAuthScopes}} + {{^hasAuthScopes}} + "".to_owned() + {{/hasAuthScopes}} + } } -/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. +/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. fn extract_token_data(token: &str, key: &[u8]) -> Result, JwtError::Error> { - + // Ensure that you set the correct algorithm and correct key. // See https://github.com/Keats/jsonwebtoken for more information. let header = decode_header(token)?; @@ -68,8 +74,8 @@ fn build_authorization(claims: Claims) -> Authorization { let scopes = swagger::auth::Scopes::Some(scopes); Authorization{ - subject: claims.sub, - scopes, + subject: claims.sub, + scopes, issuer: Some(claims.iss)} } @@ -92,7 +98,7 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn bearer_authorization(&self, bearer: &Bearer) -> Result { debug!("\tAuthorizationApi: Received Bearer-token, {bearer:#?}"); - match extract_token_data(&bearer.token, b"secret") { + match extract_token_data(&bearer.token(), b"secret") { Ok(auth_data) => { debug!("\tUnpack auth_data as: {auth_data:#?}"); let authorization = build_authorization(auth_data.claims); @@ -110,23 +116,22 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn apikey_authorization(&self, api_key: &str) -> Result { debug!("\tAuthorizationApi: Received api-key, {api_key:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } - + /// Implementation of the method to map a basic authentication (username and password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result { debug!("\tAuthorizationApi: Received Basic-token, {basic:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } -} - +} diff --git a/modules/openapi-generator/src/main/resources/rust-server/example-server-common.mustache b/modules/openapi-generator/src/main/resources/rust-server/example-server-common.mustache index b3a823d6eaa0..f69f727b2992 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/example-server-common.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/example-server-common.mustache @@ -4,8 +4,9 @@ use async_trait::async_trait; use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt}; -use hyper::server::conn::Http; -use hyper::service::Service; +use hyper::server::conn::http1; +use hyper_util::rt::TokioIo; +use hyper::service::{service_fn, Service}; use log::info; use std::future::Future; use std::marker::PhantomData; @@ -24,15 +25,13 @@ use {{{externCrateName}}}::models; /// Builds an SSL implementation for Simple HTTPS from some hard-coded file names pub async fn create(addr: &str, https: bool) { - let addr = addr.parse().expect("Failed to parse bind address"); + let addr: SocketAddr = addr.parse().expect("Failed to parse bind address"); + let listener = TcpListener::bind(&addr).await.unwrap(); let server = Server::new(); let service = MakeService::new(server); - - // This pushes a fourth layer of the middleware-stack even though Swagger assumes only three levels. - // This fourth layer creates an accept-all policy, hower the example-code already acchieves the same via a Bearer-token with full permissions, so next line is not needed (anymore). - // let service = MakeAllowAllAuthenticator::new(service, "cosmo"); + let service = MakeAllowAllAuthenticator::new(service, "cosmo"); #[allow(unused_mut)] let mut service = @@ -56,21 +55,19 @@ pub async fn create(addr: &str, https: bool) { ssl.check_private_key().expect("Failed to check private key"); let tls_acceptor = ssl.build(); - let tcp_listener = TcpListener::bind(&addr).await.unwrap(); info!("Starting a server (with https)"); loop { - if let Ok((tcp, _)) = tcp_listener.accept().await { + if let Ok((tcp, addr)) = listener.accept().await { let ssl = Ssl::new(tls_acceptor.context()).unwrap(); - let addr = tcp.peer_addr().expect("Unable to get remote address"); let service = service.call(addr); tokio::spawn(async move { let tls = tokio_openssl::SslStream::new(ssl, tcp).map_err(|_| ())?; let service = service.await.map_err(|_| ())?; - Http::new() - .serve_connection(tls, service) + http1::Builder::new() + .serve_connection(TokioIo::new(tls), service) .await .map_err(|_| ()) }); @@ -79,12 +76,40 @@ pub async fn create(addr: &str, https: bool) { } } else { info!("Starting a server (over http, so no TLS)"); - // Using HTTP - hyper::server::Server::bind(&addr).serve(service).await.unwrap() + println!("Listening on http://{}", addr); + + loop { + // When an incoming TCP connection is received grab a TCP stream for + // client<->server communication. + // + // Note, this is a .await point, this loop will loop forever but is not a busy loop. The + // .await point allows the Tokio runtime to pull the task off of the thread until the task + // has work to do. In this case, a connection arrives on the port we are listening on and + // the task is woken up, at which point the task is then put back on a thread, and is + // driven forward by the runtime, eventually yielding a TCP stream. + let (tcp_stream, addr) = listener.accept().await.expect("Failed to accept connection"); + + let service = service.call(addr).await.unwrap(); + let io = TokioIo::new(tcp_stream); + // Spin up a new task in Tokio so we can continue to listen for new TCP connection on the + // current task without waiting for the processing of the HTTP1 connection we just received + // to finish + tokio::task::spawn(async move { + // Handle the connection from the client using HTTP1 and pass any + // HTTP requests received on that connection to the `hello` function + let result = http1::Builder::new() + .serve_connection(io, service) + .await; + if let Err(err) = result + { + println!("Error serving connection: {err:?}"); + } + }); + } } } -#[derive(Copy, Clone)] +#[derive(Copy)] pub struct Server { marker: PhantomData, } @@ -94,3 +119,11 @@ impl Server { Server{marker: PhantomData} } } + +impl Clone for Server { + fn clone(&self) -> Self { + Self { + marker: PhantomData, + } + } +} diff --git a/modules/openapi-generator/src/main/resources/rust-server/example-server-main.mustache b/modules/openapi-generator/src/main/resources/rust-server/example-server-main.mustache index 58d6f9e2a65f..5e52ab4ffa2b 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/example-server-main.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/example-server-main.mustache @@ -3,26 +3,26 @@ #![allow(missing_docs)] - -use clap::{App, Arg}; +use clap::{Arg, Command}; mod server; mod server_auth; - /// Create custom server, wire it to the autogenerated router, /// and pass it to the web server. #[tokio::main] async fn main() { env_logger::init(); - let matches = App::new("server") - .arg(Arg::with_name("https") - .long("https") - .help("Whether to use HTTPS or not")) + let matches = Command::new("server") + .arg( + Arg::new("https") + .long("https") + .help("Whether to use HTTPS or not"), + ) .get_matches(); - let addr = "127.0.0.1:{{{serverPort}}}"; + let addr = "127.0.0.1:8080"; - server::create(addr, matches.is_present("https")).await; + server::create(addr, matches.contains_id("https")).await; } diff --git a/modules/openapi-generator/src/main/resources/rust-server/example-server-operation.mustache b/modules/openapi-generator/src/main/resources/rust-server/example-server-operation.mustache index aea5b6543760..dfe154824b82 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/example-server-operation.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/example-server-operation.mustache @@ -1,18 +1,18 @@ {{#summary}} /// {{{.}}} {{/summary}} - async fn {{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}( + async fn {{#exts}}{{{x-operation-id}}}{{/exts}}{{#exts.x-has-borrowed-params}}<'a>{{/exts.x-has-borrowed-params}}( &self, -{{#vendorExtensions}} +{{#exts}} {{#x-callback-params}} callback_{{.}}: String, {{/x-callback-params}} -{{/vendorExtensions}} +{{/exts}} {{#allParams}} - {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{{dataType}}}{{^required}}>{{/required}}, + {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{#exts.x-param-needs-lifetime}}'a {{/exts.x-param-needs-lifetime}}{{/isArray}}{{{dataType}}}{{^required}}>{{/required}}, {{/allParams}} context: &C) -> Result<{{{operationId}}}Response, ApiError> { - info!("{{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}({{#allParams}}{{#vendorExtensions}}{{{x-format-string}}}{{/vendorExtensions}}{{^-last}}, {{/-last}}{{/allParams}}) - X-Span-ID: {:?}"{{#allParams}}, {{{paramName}}}{{/allParams}}, context.get().0.clone()); + info!("{{#exts}}{{{x-operation-id}}}{{/exts}}({{#allParams}}{{#exts}}{{{x-format-string}}}{{/exts}}{{^-last}}, {{/-last}}{{/allParams}}) - X-Span-ID: {:?}"{{#allParams}}, {{{paramName}}}{{/allParams}}, context.get().0.clone()); Err(ApiError("Api-Error: Operation is NOT implemented".into())) } diff --git a/modules/openapi-generator/src/main/resources/rust-server/example-server-server.mustache b/modules/openapi-generator/src/main/resources/rust-server/example-server-server.mustache index bfa094f523c2..d52d90d8d1de 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/example-server-server.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/example-server-server.mustache @@ -30,6 +30,7 @@ impl Api for Server where C: Has + Send + Sync {{#operations}} {{#operation}} {{>example-server-operation}} + {{/operation}} {{/operations}} {{/apis}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/generate-multipart-related.mustache b/modules/openapi-generator/src/main/resources/rust-server/generate-multipart-related.mustache new file mode 100644 index 000000000000..9678b5d32da8 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/rust-server/generate-multipart-related.mustache @@ -0,0 +1,39 @@ +{{#-first}} + let boundary = swagger::multipart::related::generate_boundary(); + let mut body_parts = vec![]; + +{{/-first}} +{{#required}} + { +{{/required}} +{{^required}} + if let Some({{{paramName}}}) = param_{{{paramName}}} { +{{/required}} + let part = Node::Part(Part { + headers: { + let mut h = HeaderMap::new(); + h.insert(CONTENT_TYPE, HeaderValue::from_static("{{{contentType}}}")); + h.insert("Content-ID", HeaderValue::from_static("{{{baseName}}}")); + h + }, + {{#isBinary}} + body: {{#required}}param_{{/required}}{{{paramName}}}.0, + {{/isBinary}} + {{^isBinary}} + body: serde_json::to_string(&{{{paramName}}}) + .expect("Impossible to fail to serialize") + .into_bytes(), + {{/isBinary}} + }); + body_parts.push(part); + } +{{#-last}} + + // Write the body into a vec. + // RFC 13341 Section 7.2.1 suggests that the body should begin with a + // CRLF prior to the first boundary. The mime_multipart library doesn't + // do this, so we do it instead. + let mut body: Vec = vec![b'\r', b'\n']; + write_multipart(&mut body, &boundary, &body_parts) + .expect("Failed to write multipart body"); +{{/-last}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/header.mustache b/modules/openapi-generator/src/main/resources/rust-server/header.mustache index 5bc6ebe929b9..823d2779b31f 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/header.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/header.mustache @@ -31,11 +31,9 @@ macro_rules! ihv_generate { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse::<$t>() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse {} as a string: {}", - stringify!($t), e)), + Err(e) => Err(format!("Unable to parse {} as a string: {e}", stringify!($t))), }, - Err(e) => Err(format!("Unable to parse header {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header {hdr_value:?} as a string - {e}")), } } } @@ -76,8 +74,7 @@ impl TryFrom for IntoHeaderValue> { y => Some(y.to_string()), }) .collect())), - Err(e) => Err(format!("Unable to parse header: {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header: {hdr_value:?} as a string - {e}")), } } } @@ -88,8 +85,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(&hdr_value.0.join(", ")) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} into a header - {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} into a header - {e}")) } } } @@ -102,8 +98,7 @@ impl TryFrom for IntoHeaderValue { fn try_from(hdr_value: HeaderValue) -> Result { match hdr_value.to_str() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())), - Err(e) => Err(format!("Unable to convert header {:?} to {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to {e}")), } } } @@ -114,8 +109,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")) } } } @@ -128,11 +122,9 @@ impl TryFrom for IntoHeaderValue { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse bool from {} - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse bool from {hdr_value} - {e}")), }, - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")), } } } @@ -143,8 +135,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0.to_string()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert: {:?} into a header: {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert: {hdr_value:?} into a header: {e}")) } } } @@ -158,11 +149,9 @@ impl TryFrom for IntoHeaderValue> { match hdr_value.to_str() { Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) { Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))), - Err(e) => Err(format!("Unable to parse: {} as date - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse: {hdr_value} as date - {e}")), }, - Err(e) => Err(format!("Unable to convert header {:?} to string {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to string {e}")), } } } @@ -173,8 +162,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} to a header: {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} to a header: {e}")), } } } diff --git a/modules/openapi-generator/src/main/resources/rust-server/lib.mustache b/modules/openapi-generator/src/main/resources/rust-server/lib.mustache index e6d2bf190130..fe7e425608ce 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/lib.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/lib.mustache @@ -3,14 +3,15 @@ use async_trait::async_trait; use futures::Stream; +#[cfg(feature = "mock")] +use mockall::automock; use std::error::Error; use std::collections::BTreeSet; use std::task::{Poll, Context}; -use swagger::{ApiError, ContextWrapper}; +use swagger::{ApiError, ContextWrapper, auth::Authorization}; use serde::{Serialize, Deserialize}; -use crate::server::Authorization; - +#[cfg(any(feature = "client", feature = "server"))] type ServiceError = Box; pub const BASE_PATH: &str = "{{{basePathWithoutHost}}}"; @@ -27,18 +28,16 @@ pub use auth::{AuthenticationApi, Claims}; {{#operations}} {{#operation}} {{>response}} + {{/operation}} {{/operations}} {{/apis}} {{/apiInfo}} /// API +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait Api { - fn poll_ready(&self, _cx: &mut Context) -> Poll>> { - Poll::Ready(Ok(())) - } - {{#apiInfo}} {{#apis}} {{#operations}} @@ -46,10 +45,10 @@ pub trait Api { {{#summary}} /// {{{.}}} {{/summary}} - async fn {{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}( + async fn {{#exts}}{{{x-operation-id}}}{{/exts}}{{#exts.x-has-borrowed-params}}<'a>{{/exts.x-has-borrowed-params}}( &self, {{#allParams}} - {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{{dataType}}}{{^required}}>{{/required}}, + {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{#exts.x-param-needs-lifetime}}'a {{/exts.x-param-needs-lifetime}}{{/isArray}}{{{dataType}}}{{^required}}>{{/required}}, {{/allParams}} context: &C) -> Result<{{{operationId}}}Response, ApiError>; @@ -60,11 +59,14 @@ pub trait Api { } /// API where `Context` isn't passed on every API call +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait ApiNoContext { - - fn poll_ready(&self, _cx: &mut Context) -> Poll>>; + // The std::task::Context struct houses a reference to std::task::Waker with the lifetime <'a>. + // Adding an anonymous lifetime `'a` to allow mockall to create a mock object with the right lifetimes. + // This is needed because the compiler is unable to determine the lifetimes on F's trait bound + // where F is the closure created by mockall. We use higher-rank trait bounds here to get around this. fn context(&self) -> &C; @@ -75,10 +77,10 @@ pub trait ApiNoContext { {{#summary}} /// {{{.}}} {{/summary}} - async fn {{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}( + async fn {{#exts}}{{{x-operation-id}}}{{/exts}}{{#exts.x-has-borrowed-params}}<'a>{{/exts.x-has-borrowed-params}}( &self, {{#allParams}} - {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{{dataType}}}{{^required}}>{{/required}}, + {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{#exts.x-param-needs-lifetime}}'a {{/exts.x-param-needs-lifetime}}{{{dataType}}}{{^required}}>{{/required}}, {{/allParams}} ) -> Result<{{{operationId}}}Response, ApiError>; @@ -103,10 +105,6 @@ impl + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt for T #[async_trait] impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for ContextWrapper { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - self.api().poll_ready(cx) - } - fn context(&self) -> &C { ContextWrapper::context(self) } @@ -118,15 +116,15 @@ impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for Contex {{#summary}} /// {{{.}}} {{/summary}} - async fn {{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}( + async fn {{#exts}}{{{x-operation-id}}}{{/exts}}{{#exts.x-has-borrowed-params}}<'a>{{/exts.x-has-borrowed-params}}( &self, {{#allParams}} - {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{{dataType}}}{{^required}}>{{/required}}, + {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{#exts.x-param-needs-lifetime}}'a {{/exts.x-param-needs-lifetime}}{{{dataType}}}{{^required}}>{{/required}}, {{/allParams}} ) -> Result<{{{operationId}}}Response, ApiError> { let context = self.context().clone(); - self.api().{{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}({{#allParams}}{{{paramName}}}, {{/allParams}}&context).await + self.api().{{#exts}}{{{x-operation-id}}}{{/exts}}({{#allParams}}{{{paramName}}}, {{/allParams}}&context).await } {{/operation}} @@ -145,6 +143,7 @@ impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for Contex {{#urls}} {{#requests}} {{>response}} + {{/requests}} {{/urls}} {{/callbacks}} @@ -154,11 +153,9 @@ impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for Contex {{/apiInfo}} /// Callback API +#[cfg_attr(feature = "mock", automock)] #[async_trait] pub trait CallbackApi { - fn poll_ready(&self, _cx: &mut Context) -> Poll>> { - Poll::Ready(Ok(())) - } {{#apiInfo}} {{#apis}} @@ -170,15 +167,15 @@ pub trait CallbackApi { {{#summary}} /// {{{.}}} {{/summary}} - async fn {{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}( + async fn {{#exts}}{{{x-operation-id}}}{{/exts}}{{#exts.x-has-borrowed-params}}<'a>{{/exts.x-has-borrowed-params}}( &self, -{{#vendorExtensions}} +{{#exts}} {{#x-callback-params}} callback_{{.}}: String, {{/x-callback-params}} -{{/vendorExtensions}} +{{/exts}} {{#allParams}} - {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{{dataType}}}{{^required}}>{{/required}}, + {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{#exts.x-param-needs-lifetime}}'a {{/exts.x-param-needs-lifetime}}{{{dataType}}}{{^required}}>{{/required}}, {{/allParams}} context: &C) -> Result<{{{operationId}}}Response, ApiError>; @@ -192,9 +189,9 @@ pub trait CallbackApi { } /// Callback API without a `Context` +#[cfg_attr(feature = "mock", automock)] #[async_trait] pub trait CallbackApiNoContext { - fn poll_ready(&self, _cx: &mut Context) -> Poll>>; fn context(&self) -> &C; @@ -208,15 +205,15 @@ pub trait CallbackApiNoContext { {{#summary}} /// {{{.}}} {{/summary}} - async fn {{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}( + async fn {{#exts}}{{{x-operation-id}}}{{/exts}}{{#exts.x-has-borrowed-params}}<'a>{{/exts.x-has-borrowed-params}}( &self, -{{#vendorExtensions}} +{{#exts}} {{#x-callback-params}} callback_{{.}}: String, {{/x-callback-params}} -{{/vendorExtensions}} +{{/exts}} {{#allParams}} - {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{{dataType}}}{{^required}}>{{/required}}, + {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{#exts.x-param-needs-lifetime}}'a {{/exts.x-param-needs-lifetime}}{{{dataType}}}{{^required}}>{{/required}}, {{/allParams}} ) -> Result<{{{operationId}}}Response, ApiError>; @@ -243,9 +240,6 @@ impl + Send + Sync, C: Clone + Send + Sync> CallbackContextWra #[async_trait] impl + Send + Sync, C: Clone + Send + Sync> CallbackApiNoContext for ContextWrapper { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - self.api().poll_ready(cx) - } fn context(&self) -> &C { ContextWrapper::context(self) @@ -261,25 +255,25 @@ impl + Send + Sync, C: Clone + Send + Sync> CallbackApiNoConte {{#summary}} /// {{{.}}} {{/summary}} - async fn {{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}( + async fn {{#exts}}{{{x-operation-id}}}{{/exts}}{{#exts.x-has-borrowed-params}}<'a>{{/exts.x-has-borrowed-params}}( &self, -{{#vendorExtensions}} +{{#exts}} {{#x-callback-params}} callback_{{.}}: String, {{/x-callback-params}} -{{/vendorExtensions}} +{{/exts}} {{#allParams}} - {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{{dataType}}}{{^required}}>{{/required}}, + {{{paramName}}}: {{^required}}Option<{{/required}}{{#isArray}}&{{/isArray}}{{#exts.x-param-needs-lifetime}}'a {{/exts.x-param-needs-lifetime}}{{{dataType}}}{{^required}}>{{/required}}, {{/allParams}} ) -> Result<{{{operationId}}}Response, ApiError> { let context = self.context().clone(); - self.api().{{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}( -{{#vendorExtensions}} + self.api().{{#exts}}{{{x-operation-id}}}{{/exts}}( +{{#exts}} {{#x-callback-params}} callback_{{.}}, {{/x-callback-params}} -{{/vendorExtensions}} +{{/exts}} {{#allParams}} {{{paramName}}}, {{/allParams}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/models.mustache b/modules/openapi-generator/src/main/resources/rust-server/models.mustache index 12409addaf37..3073e56feaf5 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/models.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/models.mustache @@ -1,10 +1,21 @@ #![allow(unused_qualifications)] +{{^hasConflictingModelNames}} +#[cfg(not(feature = "validate"))] +use validator::Validate; +use crate::models; +#[cfg(any(feature = "client", feature = "server"))] +use crate::header; +#[cfg(feature = "validate")] +use serde_valid::Validate; +{{/hasConflictingModelNames}} +{{#hasConflictingModelNames}} use validator::Validate; use crate::models; #[cfg(any(feature = "client", feature = "server"))] use crate::header; +{{/hasConflictingModelNames}} {{! Don't "use" structs here - they can conflict with the names of models, and mean that the code won't compile }} {{#models}} {{#model}} @@ -17,21 +28,39 @@ use crate::header; /// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` /// which helps with FFI. #[allow(non_camel_case_types)] +{{#vendorExtensions.x-is-integer-enum}} +#[repr({{{vendorExtensions.x-rust-type}}})] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde_repr::Serialize_repr, serde_repr::Deserialize_repr, Hash)] +{{/vendorExtensions.x-is-integer-enum}} +{{^vendorExtensions.x-is-integer-enum}} #[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +{{/vendorExtensions.x-is-integer-enum}} +{{^hasConflictingModelNames}}{{^exts.x-skip-serde-valid}}#[cfg_attr(feature = "validate", derive(Validate))]{{/exts.x-skip-serde-valid}}{{/hasConflictingModelNames}} #[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))]{{#xmlName}} #[serde(rename = "{{{.}}}")]{{/xmlName}} pub enum {{{classname}}} { {{#allowableValues}} {{#enumVars}} + {{^vendorExtensions.x-is-integer-enum}} #[serde(rename = {{{value}}})] + {{/vendorExtensions.x-is-integer-enum}} + {{#numericDiscriminant}} + {{{name}}} = {{{numericDiscriminant}}}, + {{/numericDiscriminant}} + {{^numericDiscriminant}} {{{name}}}, + {{/numericDiscriminant}} {{/enumVars}} {{/allowableValues}} } impl std::fmt::Display for {{{classname}}} { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +{{#vendorExtensions.x-is-integer-enum}} + write!(f, "{}", *self as {{{vendorExtensions.x-rust-type}}}) +{{/vendorExtensions.x-is-integer-enum}} +{{^vendorExtensions.x-is-integer-enum}} match *self { {{#allowableValues}} {{#enumVars}} @@ -39,6 +68,7 @@ impl std::fmt::Display for {{{classname}}} { {{/enumVars}} {{/allowableValues}} } +{{/vendorExtensions.x-is-integer-enum}} } } @@ -46,51 +76,46 @@ impl std::str::FromStr for {{{classname}}} { type Err = String; fn from_str(s: &str) -> std::result::Result { +{{#vendorExtensions.x-is-integer-enum}} + match s.parse::<{{{vendorExtensions.x-rust-type}}}>() { +{{#allowableValues}} + {{#enumVars}} + std::result::Result::Ok({{{numericDiscriminant}}}) => std::result::Result::Ok({{{classname}}}::{{{name}}}), + {{/enumVars}} +{{/allowableValues}} + _ => std::result::Result::Err(format!("Value not valid: {s}")), + } +{{/vendorExtensions.x-is-integer-enum}} +{{^vendorExtensions.x-is-integer-enum}} match s { {{#allowableValues}} {{#enumVars}} {{{value}}} => std::result::Result::Ok({{{classname}}}::{{{name}}}), {{/enumVars}} {{/allowableValues}} - _ => std::result::Result::Err(format!("Value not valid: {}", s)), + _ => std::result::Result::Err(format!("Value not valid: {s}")), } +{{/vendorExtensions.x-is-integer-enum}} } } {{/isEnum}} {{^isEnum}} {{#dataType}} -{{#isMap}} -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] -{{/isMap}} -{{^isMap}} -#[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] -{{/isMap}} +#[derive(Debug, Clone, PartialEq, {{#exts.x-partial-ord}}PartialOrd, {{/exts.x-partial-ord}}serde::Serialize, serde::Deserialize)] +{{^hasConflictingModelNames}}{{^exts.x-skip-serde-valid}}#[cfg_attr(feature = "validate", derive(Validate))]{{/exts.x-skip-serde-valid}}{{/hasConflictingModelNames}} #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] {{#xmlName}} #[serde(rename = "{{{.}}}")] {{/xmlName}} -pub struct {{{classname}}}({{{dataType}}}); +pub struct {{{classname}}}( +{{>validate}} {{{dataType}}} +); impl std::convert::From<{{{dataType}}}> for {{{classname}}} { fn from(x: {{{dataType}}}) -> Self { {{{classname}}}(x) } } -{{#vendorExtensions.x-is-string}} - -impl std::string::ToString for {{{classname}}} { - fn to_string(&self) -> String { - self.0.to_string() - } -} - -impl std::str::FromStr for {{{classname}}} { - type Err = std::string::ParseError; - fn from_str(x: &str) -> std::result::Result { - std::result::Result::Ok({{{classname}}}(x.to_string())) - } -} -{{/vendorExtensions.x-is-string}} impl std::convert::From<{{{classname}}}> for {{{dataType}}} { fn from(x: {{{classname}}}) -> Self { @@ -111,51 +136,120 @@ impl std::ops::DerefMut for {{{classname}}} { } } -{{#additionalPropertiesType}} +{{^hasConflictingModelNames}} +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for {{{classname}}} { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for {{{classname}}} { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} +{{/hasConflictingModelNames}} +{{#exts.x-to-string-support}} +{{#exts.x-is-string}} +impl std::fmt::Display for {{{classname}}} { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.clone()) + } +} + +impl std::str::FromStr for {{{classname}}} { + type Err = ::std::convert::Infallible; + fn from_str(x: &str) -> std::result::Result { + std::result::Result::Ok({{{classname}}}(x.to_owned())) + } +} +{{/exts.x-is-string}} +{{^exts.x-is-string}} +/// Converts the {{{classname}}} value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for {{{classname}}} { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a {{{classname}}} value +/// as specified in +/// Should be implemented in a serde deserializer +impl ::std::str::FromStr for {{{classname}}} { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match std::str::FromStr::from_str(s) { + std::result::Result::Ok(r) => std::result::Result::Ok({{{classname}}}(r)), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {s} to {{{classname}}}: {e:?}")), + } + } +} +{{/exts.x-is-string}} +{{/exts.x-to-string-support}} +{{^exts.x-to-string-support}} /// Converts the {{{classname}}} value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl ::std::string::ToString for {{{classname}}} { - fn to_string(&self) -> String { - // Skipping additionalProperties in query parameter serialization - "".to_string() +impl std::fmt::Display for {{{classname}}} { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Display for this model is not supported + write!(f, "") } } /// Converts Query Parameters representation (style=form, explode=false) to a {{{classname}}} value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl ::std::str::FromStr for {{{classname}}} { type Err = &'static str; fn from_str(s: &str) -> std::result::Result { - std::result::Result::Err("Parsing additionalProperties for {{{classname}}} is not supported") + std::result::Result::Err("Parsing {{{classname}}} is not supported") } } -{{/additionalPropertiesType}} +{{/exts.x-to-string-support}} {{/dataType}} {{^dataType}} {{#arrayModelType}} -{{#vendorExtensions}}{{#x-item-xml-name}}// Utility function for wrapping list elements when serializing xml +{{#exts}}{{#x-item-xml-name}}// Utility function for wrapping list elements when serializing xml #[allow(non_snake_case)] -fn wrap_in_{{{x-item-xml-name}}}(item: &Vec<{{{arrayModelType}}}>, serializer: S) -> std::result::Result +fn wrap_in_{{{x-item-xml-name}}}(items: &Vec<{{{arrayModelType}}}>, serializer: S) -> std::result::Result where S: serde::ser::Serializer, { - serde_xml_rs::wrap_primitives(item, serializer, "{{{x-item-xml-name}}}") + use serde::ser::SerializeMap; + + let mut map = serializer.serialize_map(None)?; + for ref item in items { + map.serialize_key("{{{x-item-xml-name}}}")?; + map.serialize_value(item)?; + } + map.end() } {{/x-item-xml-name}} -{{/vendorExtensions}} +{{/exts}} {{! vec}} #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +{{^hasConflictingModelNames}}{{^exts.x-skip-serde-valid}}#[cfg_attr(feature = "validate", derive(Validate))]{{/exts.x-skip-serde-valid}}{{/hasConflictingModelNames}} #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct {{{classname}}}( -{{#vendorExtensions}} +{{#exts}} {{#x-item-xml-name}} #[serde(serialize_with = "wrap_in_{{{x-item-xml-name}}}")] {{/x-item-xml-name}} -{{/vendorExtensions}} +{{/exts}} Vec<{{{arrayModelType}}}> ); @@ -218,16 +312,16 @@ impl std::ops::DerefMut for {{{classname}}} { } /// Converts the {{{classname}}} value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for {{{classname}}} { - fn to_string(&self) -> String { - self.iter().map(|x| x.to_string()).collect::>().join(",") +impl std::fmt::Display for {{{classname}}} { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.iter().map(|x| x.to_string()).collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a {{{classname}}} value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for {{{classname}}} { type Err = <{{{arrayModelType}}} as std::str::FromStr>::Err; @@ -245,7 +339,7 @@ impl std::str::FromStr for {{{classname}}} { {{/arrayModelType}} {{^arrayModelType}} {{! general struct}} -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] {{#xmlName}} #[serde(rename = "{{{.}}}")] @@ -255,13 +349,18 @@ pub struct {{{classname}}} { {{/description}}{{#isEnum}} // Note: inline enums are not fully supported by openapi-generator {{/isEnum}} #[serde(rename = "{{{baseName}}}")] -{{#vendorExtensions}} +{{#exts}} {{#x-item-xml-name}} #[serde(serialize_with = "wrap_in_{{{x-item-xml-name}}}")] {{/x-item-xml-name}} -{{/vendorExtensions}} +{{/exts}} {{#hasValidation}} +{{^hasConflictingModelNames}} + #[cfg_attr(not(feature = "validate"), validate( +{{/hasConflictingModelNames}} +{{#hasConflictingModelNames}} #[validate( +{{/hasConflictingModelNames}} {{#maxLength}} {{#minLength}} length(min = {{minLength}}, max = {{maxLength}}), @@ -277,23 +376,23 @@ pub struct {{{classname}}} { {{/maxLength}} {{#pattern}} {{^isByteArray}} - regex = "RE_{{#lambda.uppercase}}{{{classname}}}_{{{name}}}{{/lambda.uppercase}}", + regex(path = *RE_{{#lambda.uppercase}}{{{classname}}}_{{{name}}}{{/lambda.uppercase}}), {{/isByteArray}} {{#isByteArray}} - custom ="validate_byte_{{#lambda.lowercase}}{{{classname}}}_{{{name}}}{{/lambda.lowercase}}" + custom(function = "validate_byte_{{#lambda.lowercase}}{{{classname}}}_{{{name}}}{{/lambda.lowercase}}") {{/isByteArray}} {{/pattern}} {{#maximum}} {{#minimum}} - range(min = {{minimum}}, max = {{maximum}}), + range(min = {{minimum}}{{dataType}}, max = {{maximum}}{{dataType}}), {{/minimum}} {{^minimum}} - range(max = {{maximum}}), + range(max = {{maximum}}{{dataType}}), {{/minimum}} {{/maximum}} {{#minimum}} {{^maximum}} - range(min = {{minimum}}), + range(min = {{minimum}}{{dataType}}), {{/maximum}} {{/minimum}} {{#maxItems}} @@ -309,23 +408,62 @@ pub struct {{{classname}}} { length(min = {{minItems}}), {{/minItems}} {{/maxItems}} +{{^hasConflictingModelNames}} + ))] +{{/hasConflictingModelNames}} +{{#hasConflictingModelNames}} )] +{{/hasConflictingModelNames}} {{/hasValidation}} {{#required}} - pub {{{name}}}: {{#isNullable}}swagger::Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}}, +{{^hasConflictingModelNames}}{{>validate}}{{/hasConflictingModelNames}} +{{^hasConflictingModelNames}} +{{#exts.x-needs-nested-validation}} + {{^minLength}}{{^maxLength}}{{^minItems}}{{^maxItems}}#[cfg_attr(feature = "validate", validate)]{{/maxItems}}{{/minItems}}{{/maxLength}}{{/minLength}} +{{/exts.x-needs-nested-validation}} +{{/hasConflictingModelNames}} + pub {{{name}}}: {{{dataType}}}, {{/required}} {{^required}} {{#isNullable}} #[serde(deserialize_with = "swagger::nullable_format::deserialize_optional_nullable")] #[serde(default = "swagger::nullable_format::default_optional_nullable")] {{/isNullable}} +{{^hasConflictingModelNames}}{{>validate}}{{/hasConflictingModelNames}} +{{^hasConflictingModelNames}} +{{#exts.x-needs-nested-validation}} + {{^minLength}}{{^maxLength}}{{^minItems}}{{^maxItems}}#[cfg_attr(feature = "validate", validate)]{{/maxItems}}{{/minItems}}{{/maxLength}}{{/minLength}} +{{/exts.x-needs-nested-validation}} +{{/hasConflictingModelNames}} #[serde(skip_serializing_if="Option::is_none")] - pub {{{name}}}: Option<{{#isNullable}}swagger::Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}}>, + pub {{{name}}}: Option<{{{dataType}}}>, {{/required}} {{/vars}} } +{{^hasConflictingModelNames}} +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for {{{classname}}} { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for {{{classname}}} { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} +{{/hasConflictingModelNames}} + {{#vars}} {{#hasValidation}} {{#pattern}} @@ -338,6 +476,7 @@ lazy_static::lazy_static! { lazy_static::lazy_static! { static ref RE_{{#lambda.uppercase}}{{{classname}}}_{{{name}}}{{/lambda.uppercase}}: regex::bytes::Regex = regex::bytes::Regex::new(r"{{ pattern }}").unwrap(); } +#[cfg(not(feature = "validate"))] fn validate_byte_{{#lambda.lowercase}}{{{classname}}}_{{{name}}}{{/lambda.lowercase}}( b: &swagger::ByteArray ) -> Result<(), validator::ValidationError> { @@ -353,7 +492,7 @@ fn validate_byte_{{#lambda.lowercase}}{{{classname}}}_{{{name}}}{{/lambda.lowerc impl {{{classname}}} { #[allow(clippy::new_without_default)] - pub fn new({{#vars}}{{^defaultValue}}{{{name}}}: {{#isNullable}}swagger::Nullable<{{/isNullable}}{{{dataType}}}{{#isNullable}}>{{/isNullable}}, {{/defaultValue}}{{/vars}}) -> {{{classname}}} { + pub fn new({{#vars}}{{^defaultValue}}{{{name}}}: {{{dataType}}}, {{/defaultValue}}{{/vars}}) -> {{{classname}}} { {{{classname}}} { {{#vars}} {{#defaultValue}}{{{name}}}: {{{defaultValue}}}{{/defaultValue}}{{^defaultValue}}{{{name}}}{{/defaultValue}}, {{/vars}} @@ -362,25 +501,28 @@ impl {{{classname}}} { } /// Converts the {{{classname}}} value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for {{{classname}}} { - fn to_string(&self) -> String { +impl std::fmt::Display for {{{classname}}} { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ {{#vars}} {{#isByteArray}} - // Skipping {{baseName}} in query parameter serialization + // Skipping byte array {{baseName}} in query parameter serialization {{/isByteArray}} +{{^isByteArray}} {{#isBinary}} - // Skipping {{baseName}} in query parameter serialization + // Skipping binary data {{baseName}} in query parameter serialization {{/isBinary}} +{{^isBinary}} {{#isMap}} - // Skipping {{baseName}} in query parameter serialization + // Skipping map {{baseName}} in query parameter serialization {{/isMap}} +{{^isMap}} {{^isPrimitiveType}} - // Skipping {{baseName}} in query parameter serialization + // Skipping non-primitive type {{baseName}} in query parameter serialization {{/isPrimitiveType}} -{{^isByteArray}}{{^isBinary}}{{^isMap}}{{#isPrimitiveType}} +{{#isPrimitiveType}} {{#required}} Some("{{{baseName}}}".to_string()), {{^isArray}} @@ -423,16 +565,19 @@ impl std::string::ToString for {{{classname}}} { ].join(",") }), {{/required}} -{{/isPrimitiveType}}{{/isMap}}{{/isBinary}}{{/isByteArray}} +{{/isPrimitiveType}} +{{/isMap}} +{{/isBinary}} +{{/isByteArray}} {{/vars}} ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a {{{classname}}} value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for {{{classname}}} { type Err = String; @@ -508,6 +653,8 @@ impl std::str::FromStr for {{{classname}}} { } } {{/arrayModelType}} +{{/dataType}} +{{/isEnum}} // Methods for converting between header::IntoHeaderValue<{{{classname}}}> and hyper::header::HeaderValue @@ -520,8 +667,7 @@ impl std::convert::TryFrom> for hyper:: match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for {{classname}} - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for {{classname}} - value: {hdr_value} is invalid {e}")) } } } @@ -536,19 +682,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match <{{{classname}}} as std::str::FromStr>::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into {{classname}} - {}", - value, err)) + format!("Unable to convert header value '{value}' into {{classname}} - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } -{{/dataType}} -{{/isEnum}} +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec<{{{classname}}}> = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match <{{{classname}}} as std::str::FromStr>::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into {{classname}} - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} {{#usesXml}} {{#usesXmlNamespaces}} {{#xmlNamespace}} @@ -567,10 +751,10 @@ impl {{{classname}}} { #[allow(dead_code)] pub(crate) fn as_xml(&self) -> String { {{#xmlNamespace}} - let mut namespaces = std::collections::BTreeMap::new(); // An empty string is used to indicate a global namespace in xmltree. - namespaces.insert("".to_string(), Self::NAMESPACE.to_string()); - serde_xml_rs::to_string_with_namespaces(&self, namespaces).expect("impossible to fail to serialize") + let config = serde_xml_rs::SerdeXml::new() + .namespace("", Self::NAMESPACE); + config.to_string(&self).expect("impossible to fail to serialize") {{/xmlNamespace}} {{^xmlNamespace}} serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") diff --git a/modules/openapi-generator/src/main/resources/rust-server/response.mustache b/modules/openapi-generator/src/main/resources/rust-server/response.mustache index ac74c0b4e2a3..7eef3b773b14 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/response.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/response.mustache @@ -1,14 +1,14 @@ #[derive(Debug, PartialEq, Serialize, Deserialize)] -{{#vendorExtensions.x-must-use-response}} +{{#exts.x-must-use-response}} #[must_use] -{{/vendorExtensions.x-must-use-response}} +{{/exts.x-must-use-response}} pub enum {{{operationId}}}Response { {{#responses}} {{#message}} /// {{{.}}}{{/message}} - {{#vendorExtensions}} + {{#exts}} {{{x-response-id}}} - {{/vendorExtensions}} + {{/exts}} {{^dataType}} {{#hasHeaders}} { @@ -16,25 +16,25 @@ pub enum {{{operationId}}}Response { {{/dataType}} {{#dataType}} {{^hasHeaders}} - {{#vendorExtensions}} + {{#exts}} {{#x-produces-plain-text}} (String) {{/x-produces-plain-text}} {{^x-produces-plain-text}} ({{{dataType}}}) {{/x-produces-plain-text}} - {{/vendorExtensions}} + {{/exts}} {{/hasHeaders}} {{#hasHeaders}} { - {{#vendorExtensions}} + {{#exts}} {{#x-produces-plain-text}} body: String, {{/x-produces-plain-text}} {{^x-produces-plain-text}} body: {{{dataType}}}, {{/x-produces-plain-text}} - {{/vendorExtensions}} + {{/exts}} {{/hasHeaders}} {{/dataType}} {{#headers}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-callbacks.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-callbacks.mustache index 2c95e530895d..bee6406d981c 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/server-callbacks.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/server-callbacks.mustache @@ -19,9 +19,8 @@ use crate::{{{operationId}}}Response; /// A client that implements the API by making HTTP calls out to a server. pub struct Client where S: Service< - (Request, C), - Response=Response, - Error=hyper::Error> + Clone + Send + Sync, + (Request>, C), + Response=Response> + Send + Sync + Clone, S::Future: Send + 'static, C: Clone + Send + Sync + 'static { @@ -34,9 +33,8 @@ pub struct Client where impl fmt::Debug for Client where S: Service< - (Request, C), - Response=Response, - Error=hyper::Error> + Clone + Send + Sync, + (Request>, C), + Response=Response> + Send + Sync + Clone, S::Future: Send + 'static, C: Clone + Send + Sync + 'static { @@ -47,9 +45,8 @@ impl fmt::Debug for Client where impl Clone for Client where S: Service< - (Request, C), - Response=Response, - Error=hyper::Error> + Clone + Send + Sync, + (Request>, C), + Response=Response> + Send + Sync + Clone, S::Future: Send + 'static, C: Clone + Send + Sync + 'static { @@ -61,8 +58,8 @@ impl Clone for Client where } } -impl Client, C>, C> where - Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static, +impl Client>>, C>, C> where + Connector: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static, C: Clone + Send + Sync + 'static { /// Create a client with a custom implementation of hyper::client::Connect. @@ -76,10 +73,11 @@ impl Client Self { - let client_service = hyper::client::Client::builder().build(connector); + let client_service = hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector); + let client_service = hyper_util::service::TowerToHyperService::new(client_service); let client_service = DropContextService::new(client_service); Self { @@ -89,7 +87,7 @@ impl Client Client, C>, C> where +impl Client>>, C>, C> where C: Clone + Send + Sync + 'static { /// Create an HTTP client. @@ -99,16 +97,17 @@ impl Client; +#[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] +type HttpsConnector = hyper_tls::HttpsConnector; -#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] -type HttpsConnector = hyper_openssl::HttpsConnector; +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HttpsConnector = hyper_openssl::client::legacy::HttpsConnector; -impl Client, C>, C> where +#[cfg(feature = "client-tls")] +impl Client>>, C>, C> where C: Clone + Send + Sync + 'static { - /// Create a client with a TLS connection to the server. + /// Create a client with a TLS connection to the server using native-tls. #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] pub fn new_https() -> Result { @@ -116,7 +115,7 @@ impl Client, C Ok(Self::new_with_connector(https_connector)) } - /// Create a client with a TLS connection to the server. + /// Create a client with a TLS connection to the server using OpenSSL. #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn new_https() -> Result { @@ -169,9 +168,8 @@ impl Client, C impl Client where S: Service< - (Request, C), - Response=Response, - Error=hyper::Error> + Clone + Send + Sync, + (Request>, C), + Response=Response> + Send + Sync + Clone, S::Future: Send + 'static, C: Clone + Send + Sync + 'static { @@ -191,20 +189,12 @@ impl Client where #[async_trait] impl CallbackApi for Client where S: Service< - (Request, C), - Response=Response, - Error=hyper::Error> + Clone + Send + Sync, + (Request>, C), + Response=Response> + Send + Sync + Clone, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Has {{#hasAuthMethods}}+ Has>{{/hasAuthMethods}} + Clone + Send + Sync, { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - match self.client_service.clone().poll_ready(cx) { - Poll::Ready(Err(e)) => Poll::Ready(Err(Box::new(e))), - Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)), - Poll::Pending => Poll::Pending, - } - } {{#apiInfo}} {{#apis}} @@ -214,6 +204,7 @@ impl CallbackApi for Client where {{#urls}} {{#requests}} {{>client-operation}} + {{/requests}} {{/urls}} {{/callbacks}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-imports.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-imports.mustache index be6effa720cd..a3d067497b26 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/server-imports.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/server-imports.mustache @@ -1,10 +1,14 @@ +use bytes::Bytes; use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt}; -use hyper::{Request, Response, StatusCode, Body, HeaderMap}; +use http_body_util::{combinators::BoxBody, Full}; +use hyper::{body::{Body, Incoming}, HeaderMap, Request, Response, StatusCode}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; use log::warn; +#[cfg(feature = "validate")] +use serde_valid::Validate; #[allow(unused_imports)] use std::convert::{TryFrom, TryInto}; -use std::error::Error; +use std::{convert::Infallible, error::Error}; use std::future::Future; use std::marker::PhantomData; use std::task::{Context, Poll}; @@ -13,13 +17,11 @@ pub use swagger::auth::Authorization; use swagger::auth::Scopes; use url::form_urlencoded; {{#apiUsesMultipartRelated}} -use hyper_0_10::header::{Headers, ContentType}; -use mime_0_2::{TopLevel, SubLevel, Mime as Mime2}; use mime_multipart::{read_multipart_body, Node, Part}; {{/apiUsesMultipartRelated}} {{#apiUsesMultipartFormData}} use multipart::server::Multipart; -use multipart::server::save::SaveResult; +use multipart::server::save::{PartialReason, SaveResult}; {{/apiUsesMultipartFormData}} #[allow(unused_imports)] @@ -27,4 +29,4 @@ use crate::{models, header, AuthenticationApi}; pub use crate::context; -type ServiceFuture = BoxFuture<'static, Result, crate::ServiceError>>; +type ServiceFuture = BoxFuture<'static, Result>, crate::ServiceError>>; diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-make-service.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-make-service.mustache index 5f5359de68a1..0df19c9af54f 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/server-make-service.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/server-make-service.mustache @@ -1,26 +1,71 @@ -pub struct MakeService where +pub struct MakeService +where T: Api + Clone + Send + 'static, C: Has {{#hasAuthMethods}}+ Has>{{/hasAuthMethods}} + Send + Sync + 'static { api_impl: T, +{{#apiUsesMultipartFormData}} + multipart_form_size_limit: Option, +{{/apiUsesMultipartFormData}} marker: PhantomData, + validation: bool } -impl MakeService where +impl MakeService +where T: Api + Clone + Send + 'static, C: Has {{#hasAuthMethods}}+ Has>{{/hasAuthMethods}} + Send + Sync + 'static { pub fn new(api_impl: T) -> Self { MakeService { api_impl, - marker: PhantomData +{{#apiUsesMultipartFormData}} + multipart_form_size_limit: Some(8 * 1024 * 1024), +{{/apiUsesMultipartFormData}} + marker: PhantomData, + validation: false } } +{{#apiUsesMultipartFormData}} + + /// Configure size limit when inspecting a multipart/form body. + /// + /// Default is 8 MiB. + /// + /// Set to None for no size limit, which presents a Denial of Service attack risk. + pub fn multipart_form_size_limit(mut self, multipart_form_size_limit: Option) -> Self { + self.multipart_form_size_limit = multipart_form_size_limit; + self + } +{{/apiUsesMultipartFormData}} + + // Turn on/off validation for the service being made. + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation; + } } +impl Clone for MakeService +where + T: Api + Clone + Send + 'static, + C: Has {{#hasAuthMethods}}+ Has>{{/hasAuthMethods}} + Send + Sync + 'static +{ + fn clone(&self) -> Self { + Self { + api_impl: self.api_impl.clone(), +{{#apiUsesMultipartFormData}} + multipart_form_size_limit: Some(8 * 1024 * 1024), +{{/apiUsesMultipartFormData}} + marker: PhantomData, + validation: self.validation + } + } +} -impl hyper::service::Service for MakeService where +impl hyper::service::Service for MakeService +where T: Api + Clone + Send + 'static, C: Has {{#hasAuthMethods}}+ Has>{{/hasAuthMethods}} + Send + Sync + 'static { @@ -28,13 +73,10 @@ impl hyper::service::Service for MakeService where type Error = crate::ServiceError; type Future = future::Ready>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } + fn call(&self, target: Target) -> Self::Future { + let service = Service::new(self.api_impl.clone(), self.validation){{^apiUsesMultipartFormData}};{{/apiUsesMultipartFormData}}{{#apiUsesMultipartFormData}} + .multipart_form_size_limit(self.multipart_form_size_limit);{{/apiUsesMultipartFormData}} - fn call(&mut self, target: Target) -> Self::Future { - future::ok(Service::new( - self.api_impl.clone(), - )) + future::ok(service) } } diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-mod.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-mod.mustache index 4111630d6e3f..fb888be8922b 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/server-mod.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/server-mod.mustache @@ -10,13 +10,17 @@ pub mod callbacks; {{/hasCallbacks}} {{>server-paths}} + {{>server-make-service}} + {{>server-service-header}} + {{#apiInfo}} {{#apis}} {{#operations}} {{#operation}} {{>server-operation}} + {{/operation}} {{/operations}} {{/apis}} @@ -25,6 +29,7 @@ pub mod callbacks; _ if path.matched(paths::ID_{{PATH_ID}}) => method_not_allowed(), {{/pathSet}} {{>server-service-footer}} + /// Request parser for `Api`. pub struct ApiRequestParser; impl RequestParser for ApiRequestParser { @@ -36,7 +41,7 @@ impl RequestParser for ApiRequestParser { {{#operations}} {{#operation}} // {{{operationId}}} - {{{httpMethod}}} {{{path}}} - hyper::Method::{{{vendorExtensions.x-http-method}}} if path.matched(paths::ID_{{{vendorExtensions.x-path-id}}}) => Some("{{{operationId}}}"), + hyper::Method::{{{exts.x-http-method}}} if path.matched(paths::ID_{{{exts.x-path-id}}}) => Some("{{{operationId}}}"), {{/operation}} {{/operations}} {{/apis}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-operation.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-operation.mustache index f0ba616a9abc..956e2a5baef6 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/server-operation.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/server-operation.mustache @@ -1,12 +1,12 @@ // {{{operationId}}} - {{{httpMethod}}} {{{path}}} - hyper::Method::{{vendorExtensions.x-http-method}} if path.matched(paths::ID_{{vendorExtensions.x-path-id}}) => { + hyper::Method::{{exts.x-http-method}} if path.matched(paths::ID_{{exts.x-path-id}}) => { {{#hasAuthMethods}} { let authorization = match *(&context as &dyn Has>).get() { Some(ref authorization) => authorization, None => return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) + .body(body_from_str("Unauthenticated")) .expect("Unable to create Authentication Forbidden response")), }; {{#authMethods}} @@ -24,9 +24,9 @@ let missing_scopes = required_scopes.difference(scopes); return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from(missing_scopes.fold( + .body(BoxBody::new(missing_scopes.fold( "Insufficient authorization, missing scopes".to_string(), - |s, scope| format!("{} {}", s, scope)) + |s, scope| format!("{s} {scope}")) )) .expect("Unable to create Authentication Insufficient response") ); @@ -37,17 +37,7 @@ } {{/hasAuthMethods}} -{{#vendorExtensions}} - {{#x-consumes-multipart}} - let boundary = match swagger::multipart::form::boundary(&headers) { - Some(boundary) => boundary.to_string(), - None => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from("Couldn't find valid multipart body".to_string())) - .expect("Unable to create Bad Request response for incorrect boundary")), - }; - - {{/x-consumes-multipart}} +{{#exts}} {{#x-has-path-params}} // Path parameters let path: &str = uri.path(); @@ -59,28 +49,28 @@ ); {{/x-has-path-params}} -{{/vendorExtensions}} +{{/exts}} {{#pathParams}} let param_{{{paramName}}} = match percent_encoding::percent_decode(path_params["{{{baseName}}}"].as_bytes()).decode_utf8() { Ok(param_{{{paramName}}}) => match param_{{{paramName}}}.parse::<{{{dataType}}}>() { Ok(param_{{{paramName}}}) => param_{{{paramName}}}, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse path parameter {{{baseName}}}: {}", e))) + .body(body_from_string(format!("Couldn't parse path parameter {{{baseName}}}: {e}"))) .expect("Unable to create Bad Request response for invalid path parameter")), }, Err(_) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["{{{baseName}}}"]))) + .body(body_from_string(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["{{{baseName}}}"]))) .expect("Unable to create Bad Request response for invalid percent decode")) }; {{/pathParams}} -{{#vendorExtensions}} +{{#exts}} {{#x-callback-params}} let callback_{{.}} = path_params["{{{.}}}"].to_string(); {{/x-callback-params}} -{{/vendorExtensions}} +{{/exts}} {{#headerParams}} {{#-first}} // Header parameters @@ -99,7 +89,7 @@ Err(err) => { return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Invalid header {{{baseName}}} - {}", err))) + .body(body_from_string(format!("Invalid header {{{baseName}}} - {err}"))) .expect("Unable to create Bad Request response for invalid header {{{baseName}}}")); }, @@ -108,7 +98,7 @@ {{#required}} return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required header {{{baseName}}}")) + .body(body_from_str("Missing required header {{{baseName}}}")) .expect("Unable to create Bad Request response for missing required header {{{baseName}}}")); {{/required}} {{^required}} @@ -127,7 +117,7 @@ {{/-first}} let param_{{{paramName}}} = query_params.iter().filter(|e| e.0 == "{{{baseName}}}").map(|e| e.1.clone()) {{#isArray}} - {{^vendorExtensions.x-consumes-json}} + {{^exts.x-consumes-json}} .filter_map(|param_{{{paramName}}}| param_{{{paramName}}}.parse().ok()) .collect::>(); {{^required}} @@ -137,8 +127,8 @@ None }; {{/required}} - {{/vendorExtensions.x-consumes-json}} - {{#vendorExtensions.x-consumes-json}} + {{/exts.x-consumes-json}} + {{#exts.x-consumes-json}} .next(); let param_{{{paramName}}} = match param_{{{paramName}}} { Some(param_{{{paramName}}}) => { @@ -149,7 +139,7 @@ Ok(param_{{{paramName}}}) => Some(param_{{{paramName}}}), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse query parameter {{{baseName}}} - doesn't match schema: {}", e))) + .body(body_from_string(format!("Couldn't parse query parameter {{{baseName}}} - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid query parameter {{{baseName}}}")), } }, @@ -160,29 +150,29 @@ Some(param_{{{paramName}}}) => param_{{{paramName}}}, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required query parameter {{{baseName}}}")) + .body(body_from_str("Missing required query parameter {{{baseName}}}")) .expect("Unable to create Bad Request response for missing query parameter {{{baseName}}}")), }; {{/required}} - {{/vendorExtensions.x-consumes-json}} + {{/exts.x-consumes-json}} {{/isArray}} {{^isArray}} .next(); let param_{{{paramName}}} = match param_{{{paramName}}} { Some(param_{{{paramName}}}) => { let param_{{{paramName}}} = - {{#vendorExtensions.x-consumes-json}} + {{#exts.x-consumes-json}} serde_json::from_str::<{{{dataType}}}> - {{/vendorExtensions.x-consumes-json}} - {{^vendorExtensions.x-consumes-json}} + {{/exts.x-consumes-json}} + {{^exts.x-consumes-json}} <{{{dataType}}} as std::str::FromStr>::from_str - {{/vendorExtensions.x-consumes-json}} + {{/exts.x-consumes-json}} (¶m_{{{paramName}}}); match param_{{{paramName}}} { Ok(param_{{{paramName}}}) => Some(param_{{{paramName}}}), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse query parameter {{{baseName}}} - doesn't match schema: {}", e))) + .body(body_from_string(format!("Couldn't parse query parameter {{{baseName}}} - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid query parameter {{{baseName}}}")), } }, @@ -193,321 +183,71 @@ Some(param_{{{paramName}}}) => param_{{{paramName}}}, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required query parameter {{{baseName}}}")) + .body(body_from_str("Missing required query parameter {{{baseName}}}")) .expect("Unable to create Bad Request response for missing query parameter {{{baseName}}}")), }; {{/required}} + {{#exts.x-can-validate}} + #[cfg(not(feature = "validate"))] + run_validation!(param_{{{paramName}}}, "{{{baseName}}}", validation); + {{/exts.x-can-validate}} {{/isArray}} {{#-last}} {{/-last}} {{/queryParams}} -{{#vendorExtensions}} -{{^x-consumes-multipart}} -{{#bodyParams}} -{{#-first}} - // Body parameters (note that non-required body parameters will ignore garbage +{{#exts.x-has-request-body}} + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { -{{#vendorExtensions}} -{{^x-consumes-plain-text}} - let mut unused_elements = Vec::new(); -{{/x-consumes-plain-text}} - let param_{{{paramName}}}: Option<{{{dataType}}}> = if !body.is_empty() { -{{#x-consumes-xml}} - let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); -{{/x-consumes-xml}} -{{#x-consumes-json}} - let deserializer = &mut serde_json::Deserializer::from_slice(&body); -{{/x-consumes-json}} -{{^x-consumes-plain-text}} - match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) { - Ok(param_{{{paramName}}}) => param_{{{paramName}}}, -{{#required}} - Err(e) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter {{{baseName}}} - doesn't match schema: {}", e))) - .expect("Unable to create Bad Request response for invalid body parameter {{{baseName}}} due to schema")), -{{/required}} -{{^required}} - Err(_) => None, -{{/required}} - } -{{/x-consumes-plain-text}} -{{#x-consumes-plain-text}} -{{#isByteArray}} - Some(swagger::ByteArray(body.to_vec())) -{{/isByteArray}} -{{#isString}} - match String::from_utf8(body.to_vec()) { - Ok(param_{{{paramName}}}) => Some(param_{{{paramName}}}), - Err(e) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter {{{baseName}}} - not valid UTF-8: {}", e))) - .expect("Unable to create Bad Request response for invalid body parameter {{{baseName}}} due to UTF-8")), - } -{{/isString}} -{{/x-consumes-plain-text}} -{{/vendorExtensions}} - } else { - None - }; -{{#required}} - let param_{{{paramName}}} = match param_{{{paramName}}} { - Some(param_{{{paramName}}}) => param_{{{paramName}}}, - None => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter {{{baseName}}}")) - .expect("Unable to create Bad Request response for missing body parameter {{{baseName}}}")), - }; -{{/required}} -{{/-first}} - {{#-last}} - - {{/-last}} -{{/bodyParams}} -{{/x-consumes-multipart}} -{{#x-consumes-multipart}} - {{^bodyParams}} - {{#vendorExtensions}} - // Form Body parameters (note that non-required body parameters will ignore garbage - // values, rather than causing a 400 response). Produce warning header and logs for - // any unused fields. - let result = body.into_raw(); - match result.await { - Ok(body) => { - use std::io::Read; - - // Read Form Parameters from body - let mut entries = match Multipart::with_body(&body.to_vec()[..], boundary).save().temp() { - SaveResult::Full(entries) => { - entries - }, - _ => { - return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from("Unable to process all message parts".to_string())) - .expect("Unable to create Bad Request response due to failure to process all message")) - }, - }; - {{#formParams}} - let field_{{{paramName}}} = entries.fields.remove("{{{paramName}}}"); - let param_{{{paramName}}} = match field_{{{paramName}}} { - Some(field) => { - let mut reader = field[0].data.readable().expect("Unable to read field for {{{paramName}}}"); - {{^required}} - Some({ - {{/required}} - {{#isByteArray}} - let mut data = vec![]; - reader.read_to_end(&mut data).expect("Reading saved binary data should never fail"); - swagger::ByteArray(data) - {{/isByteArray}} - {{^isByteArray}} - {{#jsonSchema}} - let mut data = String::new(); - reader.read_to_string(&mut data).expect("Reading saved String should never fail"); - let {{{paramName}}}_model: {{{dataType}}} = match serde_json::from_str(&data) { - Ok(model) => model, - Err(e) => { - return Ok( - Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("{{{paramName}}} data does not match API definition : {}", e))) - .expect("Unable to create Bad Request due to missing required form parameter {{{paramName}}}")) - } - }; - {{{paramName}}}_model - {{/jsonSchema}} - {{/isByteArray}} - {{^required}} - }) - {{/required}} - }, - None => { - {{#required}} - return Ok( - Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required form parameter {{{paramName}}}".to_string())) - .expect("Unable to create Bad Request due to missing required form parameter {{{paramName}}}")) - {{/required}} - {{^required}} - None - {{/required}} - } - }; - {{/formParams}} - {{/vendorExtensions}} - {{/bodyParams}} -{{/x-consumes-multipart}} -{{^x-consumes-multipart-related}} -{{^x-consumes-multipart}} -{{^bodyParams}} -{{#vendorExtensions}} -{{#formParams}} -{{#-first}} - // Form parameters -{{/-first}} - let param_{{{paramName}}} = {{^isContainer}}{{#vendorExtensions}}{{{x-example}}};{{/vendorExtensions}}{{/isContainer}}{{#isArray}}{{#required}}Vec::new();{{/required}}{{^required}}None;{{/required}}{{/isArray}}{{#isMap}}None;{{/isMap}} -{{#-last}} - -{{/-last}} -{{/formParams}} -{{/vendorExtensions}} -{{/bodyParams}} -{{/x-consumes-multipart}} -{{/x-consumes-multipart-related}} -{{#x-consumes-multipart-related}} - // Body parameters (note that non-required body parameters will ignore garbage - // values, rather than causing a 400 response). Produce warning header and logs for - // any unused fields. - let result = body.into_raw(); - match result.await { - Ok(body) => { - let mut unused_elements: Vec = vec![]; - - // Get multipart chunks. - - // Extract the top-level content type header. - let content_type_mime = headers - .get(CONTENT_TYPE) - .ok_or_else(|| "Missing content-type header".to_string()) - .and_then(|v| v.to_str().map_err(|e| format!("Couldn't read content-type header value for {{operationId}}: {}", e))) - .and_then(|v| v.parse::().map_err(|_e| "Couldn't parse content-type header value for {{operationId}}".to_string())); - - // Insert top-level content type header into a Headers object. - let mut multi_part_headers = Headers::new(); - match content_type_mime { - Ok(content_type_mime) => { - multi_part_headers.set(ContentType(content_type_mime)); - }, - Err(e) => { - return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(e)) - .expect("Unable to create Bad Request response due to unable to read content-type header for {{operationId}}")); - } - } - - // &*body expresses the body as a byteslice, &mut provides a - // mutable reference to that byteslice. - let nodes = match read_multipart_body(&mut&*body, &multi_part_headers, false) { - Ok(nodes) => nodes, - Err(e) => { - return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Could not read multipart body for {{operationId}}: {}", e))) - .expect("Unable to create Bad Request response due to unable to read multipart body for {{operationId}}")); - } - }; - - {{#formParams}} - let mut param_{{{paramName}}} = None; - {{/formParams}} - - for node in nodes { - if let Node::Part(part) = node { - let content_type = part.content_type().map(|x| format!("{}",x)); - match content_type.as_deref() { -{{#formParams}} - {{^isBinary}} - Some("{{{contentType}}}") if param_{{{paramName}}}.is_none() => { - // Extract JSON part. - let deserializer = &mut serde_json::Deserializer::from_slice(part.body.as_slice()); - let json_data: {{dataType}} = match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in JSON part: {}", path); - unused_elements.push(path.to_string()); - }) { - Ok(json_data) => json_data, - Err(e) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter {{dataType}} - doesn't match schema: {}", e))) - .expect("Unable to create Bad Request response for invalid body parameter {{dataType}} due to schema")) - }; - // Push JSON part to return object. - param_{{{paramName}}}.get_or_insert(json_data); - }, -{{/isBinary}} -{{#isBinary}} - Some("{{{contentType}}}") if param_{{{paramName}}}.is_none() => { - param_{{{paramName}}}.get_or_insert(swagger::ByteArray(part.body)); - }, -{{/isBinary}} -{{/formParams}} - Some(content_type) => { - warn!("Ignoring unexpected content type: {}", content_type); - unused_elements.push(content_type.to_string()); - }, - None => { - warn!("Missing content type"); - }, - } - } else { - unimplemented!("No support for handling unexpected parts"); - // unused_elements.push(); - } - } + Ok(body) => { + {{^exts.x-consumes-multipart-form}} + {{^exts.x-consumes-form}} + {{^bodyParam.exts.x-consumes-plain-text}} + let mut unused_elements : Vec = vec![]; + {{/bodyParam.exts.x-consumes-plain-text}} + {{/exts.x-consumes-form}} + {{/exts.x-consumes-multipart-form}} +{{>server-request-body-instance}} -{{#formParams}} -{{#-first}} - // Check that the required multipart chunks are present. -{{/-first}} -{{#required}} - let param_{{{paramName}}} = match param_required_binary_field { - Some(x) => x, - None => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required multipart/related parameter {{{paramName}}}".to_string())) - .expect("Unable to create Bad Request response for missing multipart/related parameter {{{paramName}}} due to schema")) - }; -{{/required}} -{{#-last}} - -{{/-last}} -{{/formParams}} -{{/x-consumes-multipart-related}} -{{/vendorExtensions}} - let result = api_impl.{{#vendorExtensions}}{{{x-operation-id}}}{{/vendorExtensions}}( - {{#vendorExtensions}} +{{/exts.x-has-request-body}} + let result = api_impl.{{#exts}}{{{x-operation-id}}}{{/exts}}( + {{#exts}} {{#x-callback-params}} callback_{{.}}, {{/x-callback-params}} - {{/vendorExtensions}} + {{/exts}} {{#allParams}} param_{{{paramName}}}{{#isArray}}.as_ref(){{/isArray}}, {{/allParams}} &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) .expect("Unable to create X-Span-ID header value")); -{{#bodyParams}} -{{#vendorExtensions}} -{{^x-consumes-plain-text}} +{{#exts.x-has-request-body}} + {{^exts.x-consumes-multipart-form}} + {{^exts.x-consumes-form}} + {{^bodyParam.exts.x-consumes-plain-text}} if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - -{{/x-consumes-plain-text}} -{{/vendorExtensions}} -{{/bodyParams}} + {{/bodyParam.exts.x-consumes-plain-text}} + {{/exts.x-consumes-form}} + {{/exts.x-consumes-multipart-form}} +{{/exts.x-has-request-body}} match result { Ok(rsp) => match rsp { {{#responses}} - {{{operationId}}}Response::{{#vendorExtensions}}{{x-response-id}}{{/vendorExtensions}} + {{{operationId}}}Response::{{#exts}}{{x-response-id}}{{/exts}} {{#dataType}} {{^headers}} (body) @@ -535,7 +275,9 @@ {{/headers}} {{/dataType}} => { + *response.status_mut() = StatusCode::from_u16({{{code}}}).expect("Unable to turn {{{code}}} into a StatusCode"); {{#headers}} + {{^required}} if let Some({{{name}}}) = {{{name}}} { {{/required}} @@ -544,7 +286,7 @@ Err(e) => { return Ok(Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Body::from(format!("An internal server error occurred handling {{name}} header - {}", e))) + .body(body_from_string(format!("An internal server error occurred handling {{name}} header - {e}"))) .expect("Unable to create Internal Server Error for invalid response header")) } }; @@ -557,45 +299,8 @@ } {{/required}} {{/headers}} - *response.status_mut() = StatusCode::from_u16({{{code}}}).expect("Unable to turn {{{code}}} into a StatusCode"); -{{#produces}} -{{#-first}} -{{#dataType}} -{{#vendorExtensions}} - response.headers_mut().insert( - CONTENT_TYPE, - HeaderValue::from_str("{{{x-mime-type}}}") - .expect("Unable to create Content-Type header for {{{x-uppercase-operation-id}}}_{{x-uppercase-response-id}}")); -{{/vendorExtensions}} -{{/dataType}} -{{/-first}} -{{/produces}} -{{#dataType}} -{{#vendorExtensions}} -{{#x-produces-xml}} -{{^x-has-namespace}} - let body_content = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); -{{/x-has-namespace}} -{{#x-has-namespace}} - let mut namespaces = std::collections::BTreeMap::new(); +{{>server-response-body-instance}} - // An empty string is used to indicate a global namespace in xmltree. - namespaces.insert("".to_string(), {{{dataType}}}::NAMESPACE.to_string()); - let body_content = serde_xml_rs::to_string_with_namespaces(&body, namespaces).expect("impossible to fail to serialize"); -{{/x-has-namespace}} -{{/x-produces-xml}} -{{#x-produces-json}} - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); -{{/x-produces-json}} -{{#x-produces-bytes}} - let body_content = body.0; -{{/x-produces-bytes}} -{{#x-produces-plain-text}} - let body_content = body; -{{/x-produces-plain-text}} -{{/vendorExtensions}} - *response.body_mut() = Body::from(body_content); -{{/dataType}} }, {{/responses}} }, @@ -603,49 +308,17 @@ // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } Ok(response) -{{#vendorExtensions}} -{{^x-consumes-multipart}} -{{^bodyParams}} -{{#vendorExtensions}} -{{#x-consumes-multipart-related}} - }, - Err(e) => Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter {{{baseName}}}: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter {{{baseName}}}")), - } -{{/x-consumes-multipart-related}} -{{/vendorExtensions}} -{{/bodyParams}} -{{/x-consumes-multipart}} -{{/vendorExtensions}} -{{#bodyParams}} -{{#-first}} - }, - Err(e) => Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter {{{baseName}}}: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter {{{baseName}}}")), - } -{{/-first}} -{{/bodyParams}} -{{#vendorExtensions}} -{{#x-consumes-multipart}} -{{^bodyParams}} -{{#vendorExtensions}} +{{#exts.x-has-request-body}} }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Couldn't read multipart body".to_string())) - .expect("Unable to create Bad Request response due to unable read multipart body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } -{{/vendorExtensions}} -{{/bodyParams}} -{{/x-consumes-multipart}} -{{/vendorExtensions}} +{{/exts.x-has-request-body}} }, diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-request-body-basic.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-request-body-basic.mustache new file mode 100644 index 000000000000..a0a856623de0 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/rust-server/server-request-body-basic.mustache @@ -0,0 +1,63 @@ + {{#exts}} + let param_{{{paramName}}}: Option<{{{dataType}}}> = if !body.is_empty() { + {{#x-consumes-xml}} + let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); + {{/x-consumes-xml}} + {{#x-consumes-json}} + let deserializer = &mut serde_json::Deserializer::from_slice(&body); + {{/x-consumes-json}} + {{^x-consumes-plain-text}} + {{#required}} + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {path}"); + unused_elements.push(path.to_string()); + }) { + Ok(param_{{{paramName}}}) => param_{{{paramName}}}, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new(format!("Couldn't parse body parameter {{{baseName}}} - doesn't match schema: {e}"))) + .expect("Unable to create Bad Request response for invalid body parameter {{{baseName}}} due to schema")), + } + {{/required}} + {{^required}} + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {path}"); + unused_elements.push(path.to_string()); + }).unwrap_or_default() + {{/required}} + + {{/x-consumes-plain-text}} + {{#x-consumes-plain-text}} + {{#isBinary}} + Some(swagger::ByteArray(body.to_vec())) + {{/isBinary}} + {{#isByteArray}} + Some(swagger::ByteArray(body.to_vec())) + {{/isByteArray}} + {{#isString}} + match String::from_utf8(body.to_vec()) { + Ok(param_{{{paramName}}}) => Some(param_{{{paramName}}}), + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new(format!("Couldn't parse body parameter {{{baseName}}} - not valid UTF-8: {e}"))) + .expect("Unable to create Bad Request response for invalid body parameter {{{baseName}}} due to UTF-8")), + } + {{/isString}} + {{/x-consumes-plain-text}} + {{/exts}} + } else { + None + }; + {{#required}} + let param_{{{paramName}}} = match param_{{{paramName}}} { + Some(param_{{{paramName}}}) => param_{{{paramName}}}, + None => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Missing required body parameter {{{baseName}}}".to_string())) + .expect("Unable to create Bad Request response for missing body parameter {{{baseName}}}")), + }; + {{/required}} + {{#exts.x-can-validate}} + #[cfg(not(feature = "validate"))] + run_validation!(param_{{{paramName}}}, "{{{baseName}}}", validation); + {{/exts.x-can-validate}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-request-body-form.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-request-body-form.mustache new file mode 100644 index 000000000000..abf46a82ab95 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/rust-server/server-request-body-form.mustache @@ -0,0 +1,24 @@ +{{#exts}} + {{#formParams}} + {{#-first}} + // Form parameters + {{/-first}} + let param_{{{paramName}}} = + {{^isContainer}} + {{#exts}} + {{{x-example}}}; + {{/exts}} + {{/isContainer}} + {{#isArray}} + {{#required}} + Vec::new(); + {{/required}} + {{^required}} + None; + {{/required}} + {{/isArray}} + {{#isMap}} + None; + {{/isMap}} + {{/formParams}} +{{/exts}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-request-body-instance.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-request-body-instance.mustache new file mode 100644 index 000000000000..2c2f7a4306ad --- /dev/null +++ b/modules/openapi-generator/src/main/resources/rust-server/server-request-body-instance.mustache @@ -0,0 +1,24 @@ +{{#exts}} + {{#x-consumes-multipart}} + {{#x-consumes-multipart-related}} +{{>server-request-body-multipart-related}} + + {{/x-consumes-multipart-related}} + {{^x-consumes-multipart-related}} + {{^bodyParams}} +{{>server-request-body-multipart-form}} + + {{/bodyParams}} + {{/x-consumes-multipart-related}} + {{/x-consumes-multipart}} + {{^x-consumes-multipart}} + {{#bodyParams}} +{{>server-request-body-basic}} + + {{/bodyParams}} + {{^bodyParams}} +{{>server-request-body-form}} + + {{/bodyParams}} + {{/x-consumes-multipart}} +{{/exts}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-request-body-multipart-form.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-request-body-multipart-form.mustache new file mode 100644 index 000000000000..79ba09b5ac42 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/rust-server/server-request-body-multipart-form.mustache @@ -0,0 +1,98 @@ + let boundary = match swagger::multipart::form::boundary(&headers) { + Some(boundary) => boundary.to_string(), + None => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Couldn't find valid multipart body".to_string())) + .expect("Unable to create Bad Request response for incorrect boundary")), + }; + + use std::io::Read; + + // Read Form Parameters from body + let mut entries = match Multipart::with_body(&body.to_vec()[..], boundary) + .save() + .size_limit(multipart_form_size_limit) + .temp() + { + SaveResult::Full(entries) => { + entries + }, + SaveResult::Partial(_, PartialReason::CountLimit) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Unable to process message part due to excessive parts".to_string())) + .expect("Unable to create Bad Request response due to excessive parts")) + }, + SaveResult::Partial(_, PartialReason::SizeLimit) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Unable to process message part due to excessive data".to_string())) + .expect("Unable to create Bad Request response due to excessive data")) + }, + SaveResult::Partial(_, PartialReason::Utf8Error(_)) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Unable to process message part due to invalid data".to_string())) + .expect("Unable to create Bad Request response due to invalid data")) + }, + SaveResult::Partial(_, PartialReason::IoError(_)) => { + return Ok(Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(BoxBody::new("Failed to process message part due an internal error".to_string())) + .expect("Unable to create Internal Server Error response due to an internal error")) + }, + SaveResult::Error(e) => { + return Ok(Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(BoxBody::new("Failed to process all message parts due to an internal error".to_string())) + .expect("Unable to create Internal Server Error response due to an internal error")) + }, + }; + {{#formParams}} + let field_{{{paramName}}} = entries.fields.remove("{{{paramName}}}"); + let param_{{{paramName}}} = match field_{{{paramName}}} { + Some(field) => { + let mut reader = field[0].data.readable().expect("Unable to read field for {{{paramName}}}"); + {{^required}} + Some({ + {{/required}} + {{#isByteArray}} + let mut data = vec![]; + reader.read_to_end(&mut data).expect("Reading saved binary data should never fail"); + swagger::ByteArray(data) + {{/isByteArray}} + {{^isByteArray}} + {{#jsonSchema}} + let mut data = String::new(); + reader.read_to_string(&mut data).expect("Reading saved String should never fail"); + let {{{paramName}}}_model: {{{dataType}}} = match serde_json::from_str(&data) { + Ok(model) => model, + Err(e) => { + return Ok( + Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new(format!("{{{paramName}}} data does not match API definition : {e}"))) + .expect("Unable to create Bad Request due to missing required form parameter {{{paramName}}}")) + } + }; + {{{paramName}}}_model + {{/jsonSchema}} + {{/isByteArray}} + {{^required}} + }) + {{/required}} + }, + None => { + {{#required}} + return Ok( + Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Missing required form parameter {{{paramName}}}".to_string())) + .expect("Unable to create Bad Request due to missing required form parameter {{{paramName}}}")) + {{/required}} + {{^required}} + None + {{/required}} + } + }; + {{/formParams}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-request-body-multipart-related.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-request-body-multipart-related.mustache new file mode 100644 index 000000000000..9d72305b32dd --- /dev/null +++ b/modules/openapi-generator/src/main/resources/rust-server/server-request-body-multipart-related.mustache @@ -0,0 +1,86 @@ + // Get multipart chunks. + + // Create headers from top-level content type header. + let multipart_headers = match swagger::multipart::related::create_multipart_headers(headers.get(CONTENT_TYPE)) { + Ok(headers) => headers, + Err(e) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new(e.to_string())) + .expect("Unable to create Bad Request response due to unable to read content-type header for {{operationId}}")); + } + }; + + // &*body expresses the body as a byteslice, &mut provides a + // mutable reference to that byteslice. + let nodes = match read_multipart_body(&mut&*body, &multipart_headers, false) { + Ok(nodes) => nodes, + Err(e) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new(format!("Could not read multipart body for {{operationId}}: {e}"))) + .expect("Unable to create Bad Request response due to unable to read multipart body for {{operationId}}")); + } + }; + +{{#formParams}} + let mut param_{{{paramName}}} = None; +{{/formParams}} + + for node in nodes { + if let Node::Part(part) = node { + let content_type = part.content_type().map(|x| format!("{x}")); + match content_type.as_deref() { +{{#formParams}} + {{^isBinary}} + Some("{{{contentType}}}") if param_{{{paramName}}}.is_none() => { + // Extract JSON part. + let deserializer = &mut serde_json::Deserializer::from_slice(part.body.as_slice()); + let json_data: {{dataType}} = match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in JSON part: {path}"); + unused_elements.push(path.to_string()); + }) { + Ok(json_data) => json_data, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new(format!("Couldn't parse body parameter {{dataType}} - doesn't match schema: {e}"))) + .expect("Unable to create Bad Request response for invalid body parameter {{dataType}} due to schema")) + }; + // Push JSON part to return object. + param_{{{paramName}}}.get_or_insert(json_data); + }, + {{/isBinary}} + {{#isBinary}} + Some("{{{contentType}}}") if param_{{{paramName}}}.is_none() => { + param_{{{paramName}}}.get_or_insert(swagger::ByteArray(part.body)); + }, + {{/isBinary}} +{{/formParams}} + Some(content_type) => { + warn!("Ignoring unexpected content type: {content_type}"); + unused_elements.push(content_type.to_string()); + }, + None => { + warn!("Missing content type"); + }, + } + } else { + unimplemented!("No support for handling unexpected parts"); + // unused_elements.push(); + } + } +{{#formParams}} + {{#-first}} + + // Check that the required multipart chunks are present. + {{/-first}} + {{#required}} + let param_{{{paramName}}} = match param_{{{paramName}}} { + Some(x) => x, + None => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Missing required multipart/related parameter {{{paramName}}}".to_string())) + .expect("Unable to create Bad Request response for missing multipart/related parameter {{{paramName}}} due to schema")) + }; + {{/required}} +{{/formParams}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-response-body-instance.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-response-body-instance.mustache new file mode 100644 index 000000000000..11753849ca62 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/rust-server/server-response-body-instance.mustache @@ -0,0 +1,53 @@ +{{#dataType}} + {{#exts}} + {{^x-produces-multipart-related}} + response.headers_mut().insert( + CONTENT_TYPE, + HeaderValue::from_static("{{{x-mime-type}}}")); + {{/x-produces-multipart-related}} + {{#x-produces-xml}} + // XML Body + {{^x-has-namespace}} + let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); + {{/x-has-namespace}} + {{#x-has-namespace}} + // An empty string is used to indicate a global namespace in xmltree. + let config = serde_xml_rs::SerdeXml::new() + .namespace("", {{{dataType}}}::NAMESPACE); + let body = config.to_string(&body).expect("impossible to fail to serialize"); + {{/x-has-namespace}} + {{/x-produces-xml}} + {{#x-produces-json}} + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + {{/x-produces-json}} + {{#x-produces-bytes}} + // Binary Body + *response.body_mut() = BoxBody::new(Full::new(Bytes::from(body.0))); + {{/x-produces-bytes}} + {{#x-produces-plain-text}} + // Plain text Body + {{/x-produces-plain-text}} + {{#x-produces-multipart-related}} + // multipart/related Body + {{#formParams}} + let param_{{{paramName}}} = body.{{{paramName}}}; + {{/formParams}} + {{#formParams}} +{{>generate-multipart-related}} + + let header = "multipart/related"; + response.headers_mut().insert(CONTENT_TYPE, + HeaderValue::from_bytes( + &["multipart/related; boundary=".as_bytes(), &boundary].concat()) + .expect("Unable to create Content-Type header for multipart/related")); + {{/formParams}} + *response.body_mut() = BoxBody::new(Full::new(Bytes::from(body.0))); + {{/x-produces-multipart-related}} + {{^x-produces-bytes}} + {{^x-produces-multipart-related}} + *response.body_mut() = body_from_string(body); + {{/x-produces-multipart-related}} + {{/x-produces-bytes}} + {{/exts}} +{{/dataType}} diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-server_auth.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-server_auth.mustache index ba78eb2f3f5d..21b1d7babd03 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/server-server_auth.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/server-server_auth.mustache @@ -1,11 +1,12 @@ use super::Service; use crate::{Api, AuthenticationApi}; +use headers::authorization::{Basic, Bearer}; use swagger::{ ApiError, - Authorization, - auth::{Basic, Bearer}, - Has, - XSpanIdString}; + Authorization, + Has, + XSpanIdString +}; impl AuthenticationApi for Service where T: Api + Clone + Send + 'static + AuthenticationApi, diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-service-footer.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-service-footer.mustache index 25e9c12a5b3e..74a0d6847805 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/server-service-footer.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/server-service-footer.mustache @@ -1,6 +1,13 @@ - _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) - .body(Body::empty()) - .expect("Unable to create Not Found response")) + _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) + .body(BoxBody::new(http_body_util::Empty::new())) + .expect("Unable to create Not Found response")) + } } - } Box::pin(run(self.api_impl.clone(), req)) } + Box::pin(run( + self.api_impl.clone(), + req, + self.validation{{#apiUsesMultipartFormData}}, + self.multipart_form_size_limit{{/apiUsesMultipartFormData}} + )) + } } diff --git a/modules/openapi-generator/src/main/resources/rust-server/server-service-header.mustache b/modules/openapi-generator/src/main/resources/rust-server/server-service-header.mustache index 01fde31fa1e4..983d37ffb5f1 100644 --- a/modules/openapi-generator/src/main/resources/rust-server/server-service-header.mustache +++ b/modules/openapi-generator/src/main/resources/rust-server/server-service-header.mustache @@ -1,29 +1,80 @@ -fn method_not_allowed() -> Result, crate::ServiceError> { +fn method_not_allowed() -> Result>, crate::ServiceError> { Ok( Response::builder().status(StatusCode::METHOD_NOT_ALLOWED) - .body(Body::empty()) + .body(BoxBody::new(http_body_util::Empty::new())) .expect("Unable to create Method Not Allowed response") ) } +#[allow(unused_macros)] +#[cfg(not(feature = "validate"))] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => (); +} + +#[allow(unused_macros)] +#[cfg(feature = "validate")] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => { + let $parameter = if $validation { + match $parameter.validate() { + Ok(()) => $parameter, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .header(CONTENT_TYPE, mime::TEXT_PLAIN.as_ref()) + .body(BoxBody::new(format!("Invalid value in body parameter {}: {}", $base_name, e))) + .expect(&format!("Unable to create Bad Request response for invalid value in body parameter {}", $base_name))), + } + } else { + $parameter + }; + } +} + pub struct Service where T: Api + Clone + Send + 'static, C: Has {{#hasAuthMethods}}+ Has>{{/hasAuthMethods}} + Send + Sync + 'static { api_impl: T, +{{#apiUsesMultipart}} + multipart_form_size_limit: Option, +{{/apiUsesMultipart}} marker: PhantomData, + // Enable regex pattern validation of received JSON models + validation: bool, } impl Service where T: Api + Clone + Send + 'static, C: Has {{#hasAuthMethods}}+ Has>{{/hasAuthMethods}} + Send + Sync + 'static { - pub fn new(api_impl: T) -> Self { + pub fn new(api_impl: T, validation: bool) -> Self { Service { api_impl, - marker: PhantomData +{{#apiUsesMultipart}} + multipart_form_size_limit: Some(8 * 1024 * 1024), +{{/apiUsesMultipart}} + marker: PhantomData, + validation, } } + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation + } + +{{#apiUsesMultipart}} + + /// Configure size limit when extracting a multipart/form body. + /// + /// Default is 8 MiB. + /// + /// Set to None for no size limit, which presents a Denial of Service attack risk. + pub fn multipart_form_size_limit(mut self, multipart_form_size_limit: Option) -> Self { + self.multipart_form_size_limit = multipart_form_size_limit; + self + } +{{/apiUsesMultipart}} } impl Clone for Service where @@ -33,34 +84,58 @@ impl Clone for Service where fn clone(&self) -> Self { Service { api_impl: self.api_impl.clone(), +{{#apiUsesMultipart}} + multipart_form_size_limit: Some(8 * 1024 * 1024), +{{/apiUsesMultipart}} marker: self.marker, + validation: self.validation, } } } -impl hyper::service::Service<(Request, C)> for Service where +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + +fn body_from_str(s: &str) -> BoxBody { + BoxBody::new(Full::new(Bytes::copy_from_slice(s.as_bytes()))) +} + +impl hyper::service::Service<(Request, C)> for Service where T: Api + Clone + Send + Sync + 'static, - C: Has {{#hasAuthMethods}}+ Has>{{/hasAuthMethods}} + Send + Sync + 'static + C: Has {{#hasAuthMethods}}+ Has>{{/hasAuthMethods}} + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, { - type Response = Response; + type Response = Response>; type Error = crate::ServiceError; type Future = ServiceFuture; - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - self.api_impl.poll_ready(cx) - } - - fn call(&mut self, req: (Request, C)) -> Self::Future { async fn run(mut api_impl: T, req: (Request, C)) -> Result, crate::ServiceError> where - T: Api + Clone + Send + 'static, - C: Has {{#hasAuthMethods}}+ Has>{{/hasAuthMethods}} + Send + Sync + 'static - { - let (request, context) = req; - let (parts, body) = request.into_parts(); - let (method, uri, headers) = (parts.method, parts.uri, parts.headers); - let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); + fn call(&self, req: (Request, C)) -> Self::Future { + async fn run( + mut api_impl: T, + req: (Request, C), + validation: bool, +{{#apiUsesMultipartFormData}} + multipart_form_size_limit: Option, +{{/apiUsesMultipartFormData}} + ) -> Result>, crate::ServiceError> + where + T: Api + Clone + Send + 'static, + C: Has {{#hasAuthMethods}}+ Has>{{/hasAuthMethods}} + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, + { + let (request, context) = req; + let (parts, body) = request.into_parts(); + let (method, uri, headers) = (parts.method, parts.uri, parts.headers); + let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); - {{! - This match statement is duplicated below in `parse_operation_id()`. - Please update both places if changing how this code is autogenerated. - }} - match method { + {{! + This match statement is duplicated below in `parse_operation_id()`. + Please update both places if changing how this code is autogenerated. + }} + match method { diff --git a/modules/openapi-generator/src/main/resources/rust-server/validate.mustache b/modules/openapi-generator/src/main/resources/rust-server/validate.mustache new file mode 100644 index 000000000000..696b6aa7a8cd --- /dev/null +++ b/modules/openapi-generator/src/main/resources/rust-server/validate.mustache @@ -0,0 +1,60 @@ +{{#exts.x-true-type}} +{{#minimum}} + {{#exclusiveMinimum}} + #[cfg_attr(feature = "validate", validate(exclusive_minimum = {{{minimum}}}{{{exts.x-true-type}}}))] + {{/exclusiveMinimum}} + {{^exclusiveMinimum}} + #[cfg_attr(feature = "validate", validate(minimum = {{{minimum}}}{{{exts.x-true-type}}}))] + {{/exclusiveMinimum}} +{{/minimum}} +{{#maximum}} + {{#exclusiveMaximum}} + #[cfg_attr(feature = "validate", validate(exclusive_maximum = {{{maximum}}}{{{exts.x-true-type}}}))] + {{/exclusiveMaximum}} + {{^exclusiveMaximum}} + #[cfg_attr(feature = "validate", validate(maximum = {{{maximum}}}{{{exts.x-true-type}}}))] + {{/exclusiveMaximum}} +{{/maximum}} +{{/exts.x-true-type}} +{{^exts.x-true-type}} +{{#minimum}} + {{#exclusiveMinimum}} + #[cfg_attr(feature = "validate", validate(exclusive_minimum = {{{minimum}}}{{{dataType}}}))] + {{/exclusiveMinimum}} + {{^exclusiveMinimum}} + #[cfg_attr(feature = "validate", validate(minimum = {{{minimum}}}{{{dataType}}}))] + {{/exclusiveMinimum}} +{{/minimum}} +{{#maximum}} + {{#exclusiveMaximum}} + #[cfg_attr(feature = "validate", validate(exclusive_maximum = {{{maximum}}}{{{dataType}}}))] + {{/exclusiveMaximum}} + {{^exclusiveMaximum}} + #[cfg_attr(feature = "validate", validate(maximum = {{{maximum}}}{{{dataType}}}))] + {{/exclusiveMaximum}} +{{/maximum}} +{{/exts.x-true-type}} +{{#minLength}} + #[cfg_attr(feature = "validate", validate(min_length = {{{minLength}}}))] +{{/minLength}} +{{#maxLength}} + #[cfg_attr(feature = "validate", validate(max_length = {{{maxLength}}}))] +{{/maxLength}} +{{#pattern}} +{{^isByteArray}} + #[cfg_attr(feature = "validate", validate(pattern = r"{{{pattern}}}"))] +{{/isByteArray}} +{{/pattern}} +{{#minItems}} + #[cfg_attr(feature = "validate", validate(min_length = {{{minItems}}}))] +{{/minItems}} +{{#maxItems}} + #[cfg_attr(feature = "validate", validate(max_length = {{{maxItems}}}))] +{{/maxItems}} +{{#isEnum}} + {{#allowableValues}} + {{#isString}} + #[cfg_attr(feature = "validate", validate(enumerate({{#enumVars}}{{{value}}}, {{/enumVars}})))] + {{/isString}} + {{/allowableValues}} +{{/isEnum}} diff --git a/samples/server/petstore/rust-server/output/multipart-v3/.cargo/config.toml b/samples/server/petstore/rust-server/output/multipart-v3/.cargo/config.toml new file mode 100644 index 000000000000..df91f0f117f3 --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/.cargo/config.toml @@ -0,0 +1,19 @@ +[build] +rustflags = [ + "-W", "missing_docs", # detects missing documentation for public members + + "-W", "trivial_casts", # detects trivial casts which could be removed + + "-W", "trivial_numeric_casts", # detects trivial casts of numeric types which could be removed + + # unsafe is used in `TokioIo` bridging code copied from `hyper`. + # "-W", "unsafe_code", # usage of `unsafe` code + + "-W", "unused_qualifications", # detects unnecessarily qualified names + + "-W", "unused_extern_crates", # extern crates that are never used + + "-W", "unused_import_braces", # unnecessary braces around an imported item + + "-D", "warnings", # all warnings should be denied +] diff --git a/samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator/FILES b/samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator/FILES index c4ea8aa36655..422fe9b45d10 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator/FILES +++ b/samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator/FILES @@ -1,8 +1,9 @@ -.cargo/config +.cargo/config.toml .gitignore Cargo.toml README.md api/openapi.yaml +bin/cli.rs docs/MultipartRelatedRequest.md docs/MultipartRequestObjectField.md docs/MultipleIdenticalMimeTypesPostRequest.md diff --git a/samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator/VERSION b/samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator/VERSION index f1358e30d8ae..f7962df3e243 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator/VERSION +++ b/samples/server/petstore/rust-server/output/multipart-v3/.openapi-generator/VERSION @@ -1 +1 @@ -8.0.0-SNAPSHOT +7.22.0-SNAPSHOT diff --git a/samples/server/petstore/rust-server/output/multipart-v3/Cargo.toml b/samples/server/petstore/rust-server/output/multipart-v3/Cargo.toml index 2dec3ee847fa..9712bd2a7c2c 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/Cargo.toml +++ b/samples/server/petstore/rust-server/output/multipart-v3/Cargo.toml @@ -8,84 +8,128 @@ license = "Unlicense" edition = "2018" [features] -default = ["client", "server"] +default = ["client", "server", "client-tls"] client = [ - "mime_0_2", "multipart", "multipart/client", "swagger/multipart_form", - "hyper_0_10", "mime_multipart", - "hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url" + "mime_multipart", "swagger/multipart_related", + "hyper", "percent-encoding", "hyper-util/http1", "hyper-util/http2", "url" +] +# TLS support - automatically selects backend based on target OS: +# - macOS/Windows/iOS: native-tls via hyper-tls +# - Other platforms: OpenSSL via hyper-openssl +# Dependencies are in target-specific sections below +client-tls = [ + "client", + "dep:native-tls", + "dep:hyper-tls", + "dep:openssl", + "dep:hyper-openssl", + "swagger/tls" ] server = [ - "mime_0_2", "multipart", "multipart/server", "swagger/multipart_form", - "hyper_0_10", "mime_multipart", - "serde_ignored", "hyper", "regex", "percent-encoding", "url", "lazy_static" + "mime_multipart", "swagger/multipart_related", + "serde_ignored", "hyper", "percent-encoding", "url", + +] +cli = [ + "anyhow", "clap", "clap-verbosity-flag", "simple_logger", "tokio" ] conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"] -[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] -native-tls = { version = "0.2", optional = true } -hyper-tls = { version = "0.5", optional = true } - -[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] -hyper-openssl = { version = "0.9", optional = true } -openssl = {version = "0.10", optional = true } +mock = ["mockall"] +validate = [ "serde_valid", "swagger/serdevalid"] [dependencies] # Common -async-trait = "0.1.24" +async-trait = "0.1.89" chrono = { version = "0.4", features = ["serde"] } futures = "0.3" -swagger = { version = "6.1", features = ["serdejson", "server", "client", "tls", "tcp"] } -log = "0.4.0" +swagger = { version = "7.0.0", features = ["serdejson", "server", "client"] } +headers = "0.4.1" +log = "0.4.29" + mime = "0.3" +mockall = { version = "0.14", optional = true } +lazy_static = "1.5" +regex = "1.12" + serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -validator = { version = "0.16", features = ["derive"] } +serde_valid = { version = "2.0", optional = true } + +validator = { version = "0.20", features = ["derive"] } # Crates included if required by the API definition -mime_0_2 = { package = "mime", version = "0.2.6", optional = true } -multipart = { version = "0.16", default-features = false, optional = true } +multipart = { version = "0.18", default-features = false, optional = true } # Common between server and client features -hyper = {version = "0.14", features = ["full"], optional = true} -mime_multipart = {version = "0.5", optional = true} -hyper_0_10 = {package = "hyper", version = "0.10", default-features = false, optional=true} -serde_ignored = {version = "0.1.1", optional = true} -url = {version = "2.1", optional = true} +bytes = "1.11" +http-body-util = "0.1.3" +hyper = { version = "1.9.0", features = ["full"], optional = true } +hyper-util = { version = "0.1.20", features = ["service"] } +mime_multipart = { version = "0.10", optional = true, package = "mime-multipart-hyper1" } +serde_ignored = { version = "0.1.14", optional = true } +url = { version = "2.5", optional = true } # Client-specific +tower-service = "0.3.3" # Server, and client callback-specific -lazy_static = { version = "1.4", optional = true } -percent-encoding = {version = "2.1.0", optional = true} -regex = {version = "1.3", optional = true} +percent-encoding = { version = "2.3.2", optional = true } + +# CLI-specific +anyhow = { version = "1", optional = true } +clap = { version = "4.6.0", features = ["env"], optional = true } +clap-verbosity-flag = { version = "3.0", optional = true } +simple_logger = { version = "5.2.0", features = ["stderr"], optional = true } +tokio = { version = "1.50.0", features = ["rt-multi-thread", "macros"], optional = true } # Conversion -frunk = { version = "0.3.0", optional = true } -frunk_derives = { version = "0.3.0", optional = true } -frunk_core = { version = "0.3.0", optional = true } -frunk-enum-derive = { version = "0.2.0", optional = true } -frunk-enum-core = { version = "0.2.0", optional = true } +frunk = { version = "0.4.4", optional = true } +frunk_derives = { version = "0.4.4", optional = true } +frunk_core = { version = "0.4.4", optional = true } +frunk-enum-derive = { version = "0.3.0", optional = true } +frunk-enum-core = { version = "0.3.0", optional = true } -# Bearer authentication -jsonwebtoken = { version = "9.3.0", optional = false } +# TLS dependencies - platform-specific backends +# On macOS/Windows/iOS, use native-tls via hyper-tls +[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] +native-tls = { version = "0.2", optional = true } +hyper-tls = { version = "0.6", optional = true } + +# On other platforms (Linux, etc.), use OpenSSL via hyper-openssl +[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] +openssl = { version = "0.10", optional = true } +hyper-openssl = { version = "0.10", optional = true } [dev-dependencies] -clap = "2.25" -env_logger = "0.7" -tokio = { version = "1.14", features = ["full"] } +always_send = "0.1.1" +clap = "4.6.0" +env_logger = "0.11" +tokio = { version = "1.50.0", features = ["full"] } native-tls = "0.2" +pin-project = "1.1.11" + +# Bearer authentication, used in examples +jsonwebtoken = {version = "10.3.0", features = ["rust_crypto"]} [target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies] -tokio-openssl = "0.6" openssl = "0.10" +tokio-openssl = "0.6" [[example]] -name = "client" +name = "multipart-v3-client" +path = "examples/client/main.rs" required-features = ["client"] [[example]] -name = "server" +name = "multipart-v3-server" +path = "examples/server/main.rs" required-features = ["server"] + +[[bin]] +name = "multipart-v3" +path = "bin/cli.rs" +required-features = ["client", "cli"] diff --git a/samples/server/petstore/rust-server/output/multipart-v3/README.md b/samples/server/petstore/rust-server/output/multipart-v3/README.md index a0e8b66418fc..cb851e1825dd 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/README.md +++ b/samples/server/petstore/rust-server/output/multipart-v3/README.md @@ -14,7 +14,7 @@ To see how to make this your own, look here: [README]((https://openapi-generator.tech)) - API version: 1.0.7 -- Generator version: 8.0.0-SNAPSHOT +- Generator version: 7.22.0-SNAPSHOT @@ -23,6 +23,7 @@ This autogenerated project defines an API crate `multipart-v3` which contains: * Data types representing the underlying data model. * A `Client` type which implements `Api` and issues HTTP requests for each operation. * A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. +* A CLI tool to drive basic API operations from the command line. It also contains an example server and client which make use of `multipart-v3`: @@ -34,43 +35,67 @@ It also contains an example server and client which make use of `multipart-v3`: arguments on the command line. You can use the example server and client as a basis for your own code. -See below for [more detail on implementing a server](#writing-a-server). +See below for [more detail on the examples](#using-the-generated-library). + +## CLI + +Run the included CLI tool with: + +``` +cargo run --bin cli --features=cli +``` + +To pass in arguments, put them after `--`, for example: + +``` +cargo run --bin cli --features=cli -- --help +``` + +See the help text for available options. + +To build a standalone tool, use: + +``` +cargo build --bin cli --features=cli --release +``` + +You'll find the binary at `target/release/cli`. ## Examples Run examples with: ``` -cargo run --example +cargo run --example multipart-v3- ``` To pass in arguments to the examples, put them after `--`, for example: ``` -cargo run --example client -- --help +cargo run --example multipart-v3-client -- --help ``` ### Running the example server To run the server, follow these simple steps: ``` -cargo run --example server +cargo run --example multipart-v3-server ``` ### Running the example client To run a client, follow one of the following simple steps: ``` -cargo run --example client MultipartRelatedRequestPost -cargo run --example client MultipartRequestPost -cargo run --example client MultipleIdenticalMimeTypesPost +cargo run --example multipart-v3-client MultipartRelatedRequestPost +cargo run --example multipart-v3-client MultipartRequestPost +cargo run --example multipart-v3-client MultipleIdenticalMimeTypesPost ``` ### HTTPS The examples can be run in HTTPS mode by passing in the flag `--https`, for example: ``` -cargo run --example server -- --https +cargo run --example multipart-v3-server -- --https ``` This will use the keys/certificates from the examples directory. Note that the @@ -86,8 +111,36 @@ The generated library has a few optional features that can be activated through * `client` * This defaults to enabled and creates the basic skeleton of a client implementation based on hyper * The constructed client implements the API trait by making remote API call. +* `client-tls` + * This default to enabled and provides HTTPS support with automatic TLS backend selection: + - macOS/Windows/iOS: native-tls + hyper-tls + - Linux/Unix/others: OpenSSL + hyper-openssl * `conversions` * This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types. +* `cli` + * This defaults to disabled and is required for building the included CLI tool. +* `validate` + * This defaults to disabled and allows JSON Schema validation of received data using `MakeService::set_validation` or `Service::set_validation`. + * Note, enabling validation will have a performance penalty, especially if the API heavily uses regex based checks. + +### HTTPS/TLS Support + +HTTPS support is included by default. To disable it (for example, to reduce dependencies), you can: + +```toml +[dependencies] +multipart-v3 = { version = "1.0.7", default-features = false, features = ["client", "server"] } +``` + +**For server with callbacks that need HTTPS:** +```toml +[dependencies] +multipart-v3 = { version = "1.0.7", features = ["server", "client-tls"] } +``` + +The TLS backend is automatically selected based on your target platform: +- **macOS, Windows, iOS**: Uses `native-tls` (system TLS libraries) +- **Linux, Unix, other platforms**: Uses `openssl` See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`. diff --git a/samples/server/petstore/rust-server/output/multipart-v3/api/openapi.yaml b/samples/server/petstore/rust-server/output/multipart-v3/api/openapi.yaml index e116dfb47251..07e72037ff58 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/api/openapi.yaml +++ b/samples/server/petstore/rust-server/output/multipart-v3/api/openapi.yaml @@ -12,7 +12,7 @@ paths: content: multipart/form-data: schema: - $ref: '#/components/schemas/multipart_request' + $ref: "#/components/schemas/multipart_request" required: true responses: "201": @@ -45,7 +45,7 @@ paths: style: simple style: form schema: - $ref: '#/components/schemas/multipart_related_request' + $ref: "#/components/schemas/multipart_related_request" required: true responses: "201": @@ -63,7 +63,7 @@ paths: contentType: application/octet-stream style: form schema: - $ref: '#/components/schemas/_multiple_identical_mime_types_post_request' + $ref: "#/components/schemas/_multiple_identical_mime_types_post_request" required: true responses: "200": @@ -77,7 +77,7 @@ components: optional_string_field: type: string object_field: - $ref: '#/components/schemas/multipart_request_object_field' + $ref: "#/components/schemas/multipart_request_object_field" binary_field: format: byte type: string @@ -88,7 +88,7 @@ components: multipart_related_request: properties: object_field: - $ref: '#/components/schemas/multipart_request_object_field' + $ref: "#/components/schemas/multipart_request_object_field" optional_binary_field: format: binary type: string diff --git a/samples/server/petstore/rust-server/output/multipart-v3/bin/cli.rs b/samples/server/petstore/rust-server/output/multipart-v3/bin/cli.rs new file mode 100644 index 000000000000..df88edb242f5 --- /dev/null +++ b/samples/server/petstore/rust-server/output/multipart-v3/bin/cli.rs @@ -0,0 +1,223 @@ +//! CLI tool driving the API client +use anyhow::{anyhow, Context, Result}; +use clap::Parser; +use log::{debug, info}; +// models may be unused if all inputs are primitive types +#[allow(unused_imports)] +use multipart_v3::{ + models, ApiNoContext, Client, ContextWrapperExt, + MultipartRelatedRequestPostResponse, + MultipartRequestPostResponse, + MultipleIdenticalMimeTypesPostResponse, +}; +use simple_logger::SimpleLogger; +use swagger::{AuthData, ContextBuilder, EmptyContext, Push, XSpanIdString}; + +type ClientContext = swagger::make_context_ty!( + ContextBuilder, + EmptyContext, + Option, + XSpanIdString +); + +#[derive(Parser, Debug)] +#[clap( + name = "Multipart OpenAPI V3 Rust Server Test", + version = "1.0.7", + about = "CLI access to Multipart OpenAPI V3 Rust Server Test" +)] +struct Cli { + #[clap(subcommand)] + operation: Operation, + + /// Address or hostname of the server hosting this API, including optional port + #[clap(short = 'a', long, default_value = "http://localhost")] + server_address: String, + + /// Path to the client private key if using client-side TLS authentication + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_certificate", "server_certificate"]))] + client_key: Option, + + /// Path to the client's public certificate associated with the private key + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_key", "server_certificate"]))] + client_certificate: Option, + + /// Path to CA certificate used to authenticate the server + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long)] + server_certificate: Option, + + /// If set, write output to file instead of stdout + #[clap(short, long)] + output_file: Option, + + #[command(flatten)] + verbosity: clap_verbosity_flag::Verbosity, +} + +#[derive(Parser, Debug)] +enum Operation { + MultipartRelatedRequestPost { + #[clap(value_parser = parse_json::)] + required_binary_field: swagger::ByteArray, + #[clap(value_parser = parse_json::)] + object_field: Option, + #[clap(value_parser = parse_json::)] + optional_binary_field: Option, + }, + MultipartRequestPost { + string_field: String, + #[clap(value_parser = parse_json::)] + binary_field: swagger::ByteArray, + optional_string_field: Option, + #[clap(value_parser = parse_json::)] + object_field: Option, + }, + MultipleIdenticalMimeTypesPost { + #[clap(value_parser = parse_json::)] + binary1: Option, + #[clap(value_parser = parse_json::)] + binary2: Option, + }, +} + +// On Linux/Unix with OpenSSL (client-tls feature), support certificate pinning and mutual TLS +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + if args.client_certificate.is_some() { + debug!("Using mutual TLS"); + let client = Client::try_new_https_mutual( + &args.server_address, + args.server_certificate.clone().unwrap(), + args.client_key.clone().unwrap(), + args.client_certificate.clone().unwrap(), + ) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else if args.server_certificate.is_some() { + debug!("Using TLS with pinned server certificate"); + let client = + Client::try_new_https_pinned(&args.server_address, args.server_certificate.clone().unwrap()) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else { + debug!("Using client without certificates"); + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) + } +} + +// On macOS/Windows/iOS or without client-tls feature, use simple client (no cert pinning/mutual TLS) +#[cfg(any( + not(feature = "client-tls"), + all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")) +))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + // Client::try_new() automatically detects the URL scheme (http:// or https://) + // and creates the appropriate client. + // Note: Certificate pinning and mutual TLS are only available on Linux/Unix with OpenSSL + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) +} + +#[tokio::main] +async fn main() -> Result<()> { + let args = Cli::parse(); + if let Some(log_level) = args.verbosity.log_level() { + SimpleLogger::new().with_level(log_level.to_level_filter()).init()?; + } + + debug!("Arguments: {:?}", &args); + + let auth_data: Option = None; + + #[allow(trivial_casts)] + let context = swagger::make_context!( + ContextBuilder, + EmptyContext, + auth_data, + XSpanIdString::default() + ); + + let client = create_client(&args, context)?; + + let result = match args.operation { + Operation::MultipartRelatedRequestPost { + required_binary_field, + object_field, + optional_binary_field, + } => { + info!("Performing a MultipartRelatedRequestPost request"); + + let result = client.multipart_related_request_post( + required_binary_field, + object_field, + optional_binary_field, + ).await?; + debug!("Result: {:?}", result); + + match result { + MultipartRelatedRequestPostResponse::OK + => "OK\n".to_string() + , + } + } + Operation::MultipartRequestPost { + string_field, + binary_field, + optional_string_field, + object_field, + } => { + info!("Performing a MultipartRequestPost request"); + + let result = client.multipart_request_post( + string_field, + binary_field, + optional_string_field, + object_field, + ).await?; + debug!("Result: {:?}", result); + + match result { + MultipartRequestPostResponse::OK + => "OK\n".to_string() + , + } + } + Operation::MultipleIdenticalMimeTypesPost { + binary1, + binary2, + } => { + info!("Performing a MultipleIdenticalMimeTypesPost request"); + + let result = client.multiple_identical_mime_types_post( + binary1, + binary2, + ).await?; + debug!("Result: {:?}", result); + + match result { + MultipleIdenticalMimeTypesPostResponse::OK + => "OK\n".to_string() + , + } + } + }; + + if let Some(output_file) = args.output_file { + std::fs::write(output_file, result)? + } else { + println!("{}", result); + } + Ok(()) +} + +// May be unused if all inputs are primitive types +#[allow(dead_code)] +fn parse_json(json_string: &str) -> Result { + serde_json::from_str(json_string).map_err(|err| anyhow!("Error parsing input: {}", err)) +} diff --git a/samples/server/petstore/rust-server/output/multipart-v3/examples/client/main.rs b/samples/server/petstore/rust-server/output/multipart-v3/examples/client/main.rs index 104343c50f48..9357df4ab57a 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/examples/client/main.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/examples/client/main.rs @@ -9,7 +9,7 @@ use multipart_v3::{Api, ApiNoContext, Claims, Client, ContextWrapperExt, models, MultipartRequestPostResponse, MultipleIdenticalMimeTypesPostResponse, }; -use clap::{App, Arg}; +use clap::{Command, Arg}; // NOTE: Set environment variable RUST_LOG to the name of the executable (or "cargo run") to activate console logging for all loglevels. // See https://docs.rs/env_logger/latest/env_logger/ for more details @@ -32,27 +32,25 @@ use client_auth::build_token; fn main() { env_logger::init(); - let matches = App::new("client") - .arg(Arg::with_name("operation") + let matches = Command::new("client") + .arg(Arg::new("operation") .help("Sets the operation to run") - .possible_values(&[ - "MultipartRelatedRequestPost", - "MultipartRequestPost", - "MultipleIdenticalMimeTypesPost", - ]) + .value_parser(Vec::<&str>::from([ + "MultipartRelatedRequestPost", + "MultipartRequestPost", + "MultipleIdenticalMimeTypesPost", + ])) .required(true) .index(1)) - .arg(Arg::with_name("https") + .arg(Arg::new("https") .long("https") .help("Whether to use HTTPS or not")) - .arg(Arg::with_name("host") + .arg(Arg::new("host") .long("host") - .takes_value(true) .default_value("localhost") .help("Hostname to contact")) - .arg(Arg::with_name("port") + .arg(Arg::new("port") .long("port") - .takes_value(true) .default_value("8080") .help("Port to contact")) .get_matches(); @@ -61,53 +59,68 @@ fn main() { // In a real (production) system this Bearer token should be obtained via an external Identity/Authentication-server // Ensure that you set the correct algorithm and encodingkey that matches what is used on the server side. // See https://github.com/Keats/jsonwebtoken for more information - let auth_token = build_token( Claims { - sub: "tester@acme.com".to_owned(), + sub: "tester@acme.com".to_owned(), company: "ACME".to_owned(), iss: "my_identity_provider".to_owned(), // added a very long expiry time aud: "org.acme.Resource_Server".to_string(), exp: 10000000000, // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ - ].join(", ") - }, + scopes: + "".to_owned() + }, b"secret").unwrap(); let auth_data = if !auth_token.is_empty() { - Some(AuthData::Bearer(swagger::auth::Bearer { token: auth_token})) + Some(AuthData::Bearer(auth_token)) } else { // No Bearer-token available, so return None None }; - let is_https = matches.is_present("https"); + let is_https = matches.contains_id("https"); let base_url = format!("{}://{}:{}", if is_https { "https" } else { "http" }, - matches.value_of("host").unwrap(), - matches.value_of("port").unwrap()); + matches.get_one::("host").unwrap(), + matches.get_one::("port").unwrap()); let context: ClientContext = swagger::make_context!(ContextBuilder, EmptyContext, auth_data, XSpanIdString::default()); - let mut client : Box> = if matches.is_present("https") { - // Using Simple HTTPS - let client = Box::new(Client::try_new_https(&base_url) - .expect("Failed to create HTTPS client")); - Box::new(client.with_context(context)) - } else { - // Using HTTP - let client = Box::new(Client::try_new_http( - &base_url) - .expect("Failed to create HTTP client")); - Box::new(client.with_context(context)) + let mut client : Box> = { + #[cfg(feature = "client-tls")] + { + if is_https { + // Using HTTPS with native-tls + let client = Box::new(Client::try_new_https(&base_url) + .expect("Failed to create HTTPS client")); + Box::new(client.with_context(context)) + } else { + // Using HTTP + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } + } + + #[cfg(not(feature = "client-tls"))] + { + if is_https { + panic!("HTTPS requested but TLS support not enabled. \ + Enable the 'client-tls' feature to use HTTPS."); + } + // Using HTTP only + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } }; let mut rt = tokio::runtime::Runtime::new().unwrap(); - match matches.value_of("operation") { + match matches.get_one::("operation").map(String::as_str) { Some("MultipartRelatedRequestPost") => { let result = rt.block_on(client.multipart_related_request_post( swagger::ByteArray(Vec::from("BINARY_DATA_HERE")), diff --git a/samples/server/petstore/rust-server/output/multipart-v3/examples/server/main.rs b/samples/server/petstore/rust-server/output/multipart-v3/examples/server/main.rs index a0b4755e80c1..bb29d967957c 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/examples/server/main.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/examples/server/main.rs @@ -3,26 +3,26 @@ #![allow(missing_docs)] - -use clap::{App, Arg}; +use clap::{Arg, Command}; mod server; mod server_auth; - /// Create custom server, wire it to the autogenerated router, /// and pass it to the web server. #[tokio::main] async fn main() { env_logger::init(); - let matches = App::new("server") - .arg(Arg::with_name("https") - .long("https") - .help("Whether to use HTTPS or not")) + let matches = Command::new("server") + .arg( + Arg::new("https") + .long("https") + .help("Whether to use HTTPS or not"), + ) .get_matches(); let addr = "127.0.0.1:8080"; - server::create(addr, matches.is_present("https")).await; + server::create(addr, matches.contains_id("https")).await; } diff --git a/samples/server/petstore/rust-server/output/multipart-v3/examples/server/server.rs b/samples/server/petstore/rust-server/output/multipart-v3/examples/server/server.rs index 8eecc09eb2f4..29377f99bde5 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/examples/server/server.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/examples/server/server.rs @@ -4,8 +4,9 @@ use async_trait::async_trait; use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt}; -use hyper::server::conn::Http; -use hyper::service::Service; +use hyper::server::conn::http1; +use hyper_util::rt::TokioIo; +use hyper::service::{service_fn, Service}; use log::info; use std::future::Future; use std::marker::PhantomData; @@ -24,15 +25,13 @@ use multipart_v3::models; /// Builds an SSL implementation for Simple HTTPS from some hard-coded file names pub async fn create(addr: &str, https: bool) { - let addr = addr.parse().expect("Failed to parse bind address"); + let addr: SocketAddr = addr.parse().expect("Failed to parse bind address"); + let listener = TcpListener::bind(&addr).await.unwrap(); let server = Server::new(); let service = MakeService::new(server); - - // This pushes a fourth layer of the middleware-stack even though Swagger assumes only three levels. - // This fourth layer creates an accept-all policy, hower the example-code already acchieves the same via a Bearer-token with full permissions, so next line is not needed (anymore). - // let service = MakeAllowAllAuthenticator::new(service, "cosmo"); + let service = MakeAllowAllAuthenticator::new(service, "cosmo"); #[allow(unused_mut)] let mut service = @@ -56,21 +55,19 @@ pub async fn create(addr: &str, https: bool) { ssl.check_private_key().expect("Failed to check private key"); let tls_acceptor = ssl.build(); - let tcp_listener = TcpListener::bind(&addr).await.unwrap(); info!("Starting a server (with https)"); loop { - if let Ok((tcp, _)) = tcp_listener.accept().await { + if let Ok((tcp, addr)) = listener.accept().await { let ssl = Ssl::new(tls_acceptor.context()).unwrap(); - let addr = tcp.peer_addr().expect("Unable to get remote address"); let service = service.call(addr); tokio::spawn(async move { let tls = tokio_openssl::SslStream::new(ssl, tcp).map_err(|_| ())?; let service = service.await.map_err(|_| ())?; - Http::new() - .serve_connection(tls, service) + http1::Builder::new() + .serve_connection(TokioIo::new(tls), service) .await .map_err(|_| ()) }); @@ -79,12 +76,40 @@ pub async fn create(addr: &str, https: bool) { } } else { info!("Starting a server (over http, so no TLS)"); - // Using HTTP - hyper::server::Server::bind(&addr).serve(service).await.unwrap() + println!("Listening on http://{}", addr); + + loop { + // When an incoming TCP connection is received grab a TCP stream for + // client<->server communication. + // + // Note, this is a .await point, this loop will loop forever but is not a busy loop. The + // .await point allows the Tokio runtime to pull the task off of the thread until the task + // has work to do. In this case, a connection arrives on the port we are listening on and + // the task is woken up, at which point the task is then put back on a thread, and is + // driven forward by the runtime, eventually yielding a TCP stream. + let (tcp_stream, addr) = listener.accept().await.expect("Failed to accept connection"); + + let service = service.call(addr).await.unwrap(); + let io = TokioIo::new(tcp_stream); + // Spin up a new task in Tokio so we can continue to listen for new TCP connection on the + // current task without waiting for the processing of the HTTP1 connection we just received + // to finish + tokio::task::spawn(async move { + // Handle the connection from the client using HTTP1 and pass any + // HTTP requests received on that connection to the `hello` function + let result = http1::Builder::new() + .serve_connection(io, service) + .await; + if let Err(err) = result + { + println!("Error serving connection: {err:?}"); + } + }); + } } } -#[derive(Copy, Clone)] +#[derive(Copy)] pub struct Server { marker: PhantomData, } @@ -95,6 +120,14 @@ impl Server { } } +impl Clone for Server { + fn clone(&self) -> Self { + Self { + marker: PhantomData, + } + } +} + use jsonwebtoken::{decode, encode, errors::Error as JwtError, Algorithm, DecodingKey, EncodingKey, Header, TokenData, Validation}; use serde::{Deserialize, Serialize}; diff --git a/samples/server/petstore/rust-server/output/multipart-v3/examples/server/server_auth.rs b/samples/server/petstore/rust-server/output/multipart-v3/examples/server/server_auth.rs index e12846a950b4..4e1903155914 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/examples/server/server_auth.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/examples/server/server_auth.rs @@ -1,8 +1,8 @@ use swagger::{ ApiError, - auth::{Basic, Bearer}, - Has, + Has, XSpanIdString}; +use headers::authorization::{Basic, Bearer}; use multipart_v3::{AuthenticationApi, Claims}; use crate::server::Server; use jsonwebtoken::{decode, errors as JwtError, decode_header, DecodingKey, TokenData, Validation}; @@ -15,24 +15,24 @@ use log::{error, debug}; /// Get a dummy claim with full permissions (all scopes) for testing purposes fn full_permission_claim() -> Claims { - Claims { - sub: "tester@acme.com".to_owned(), - company: "ACME".to_owned(), - iss: "mini-bank-IDP".to_owned(), - aud: "org.acme.Resource_Server".to_string(), - // added a very long expiry time - exp: 10000000000, - // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ - ].join(", ") - } + // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. + Claims { + sub: "tester@acme.com".to_owned(), + company: "ACME".to_owned(), + iss: "mini-bank-IDP".to_owned(), + aud: "org.acme.Resource_Server".to_string(), + // added a very long expiry time + exp: 10000000000, + scopes: + "".to_owned() + } } -/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. +/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. fn extract_token_data(token: &str, key: &[u8]) -> Result, JwtError::Error> { - + // Ensure that you set the correct algorithm and correct key. // See https://github.com/Keats/jsonwebtoken for more information. let header = decode_header(token)?; @@ -63,8 +63,8 @@ fn build_authorization(claims: Claims) -> Authorization { let scopes = swagger::auth::Scopes::Some(scopes); Authorization{ - subject: claims.sub, - scopes, + subject: claims.sub, + scopes, issuer: Some(claims.iss)} } @@ -87,7 +87,7 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn bearer_authorization(&self, bearer: &Bearer) -> Result { debug!("\tAuthorizationApi: Received Bearer-token, {bearer:#?}"); - match extract_token_data(&bearer.token, b"secret") { + match extract_token_data(&bearer.token(), b"secret") { Ok(auth_data) => { debug!("\tUnpack auth_data as: {auth_data:#?}"); let authorization = build_authorization(auth_data.claims); @@ -105,23 +105,22 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn apikey_authorization(&self, api_key: &str) -> Result { debug!("\tAuthorizationApi: Received api-key, {api_key:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } - + /// Implementation of the method to map a basic authentication (username and password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result { debug!("\tAuthorizationApi: Received Basic-token, {basic:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } -} - +} diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/auth.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/auth.rs index cbaba3dca7c6..a6a39f79450f 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/src/auth.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/auth.rs @@ -1,8 +1,7 @@ use std::collections::BTreeSet; -use crate::server::Authorization; use serde::{Deserialize, Serialize}; -use swagger::{ApiError, auth::{Basic, Bearer}}; - +use swagger::{ApiError, auth::Authorization}; +use headers::authorization::{Basic, Bearer}; #[derive(Debug, Serialize, Deserialize)] pub struct Claims { pub sub: String, @@ -24,7 +23,7 @@ pub trait AuthenticationApi { /// Method should be implemented (see example-code) to map Basic (Username:password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result; -} +} // Implement it for AllowAllAuthenticator (dummy is needed, but should not used as we have Bearer authorization) use swagger::auth::{AllowAllAuthenticator, RcBound, Scopes}; @@ -34,7 +33,7 @@ fn dummy_authorization() -> Authorization { // However, if you want to use it anyway this can not be unimplemented, so dummy implementation added. // unimplemented!() Authorization{ - subject: "Dummmy".to_owned(), + subject: "Dummy".to_owned(), scopes: Scopes::Some(BTreeSet::new()), // create an empty scope, as this should not be used issuer: None } diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/client/mod.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/client/mod.rs index eaea306af10e..7d7dffb7ab88 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/src/client/mod.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/client/mod.rs @@ -1,10 +1,12 @@ use async_trait::async_trait; +use bytes::Bytes; use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt}; +use http_body_util::{combinators::BoxBody, Full}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; -use hyper::{Body, Request, Response, service::Service, Uri}; +use hyper::{body::{Body, Incoming}, Request, Response, service::Service, Uri}; use percent_encoding::{utf8_percent_encode, AsciiSet}; use std::borrow::Cow; -use std::convert::TryInto; +use std::convert::{TryInto, Infallible}; use std::io::{ErrorKind, Read}; use std::error::Error; use std::future::Future; @@ -18,12 +20,13 @@ use std::string::ToString; use std::task::{Context, Poll}; use swagger::{ApiError, AuthData, BodyExt, Connector, DropContextService, Has, XSpanIdString}; use url::form_urlencoded; +use tower_service::Service as _; use mime::Mime; use std::io::Cursor; use multipart::client::lazy::Multipart; -use hyper_0_10::header::{Headers, ContentType}; -use mime_multipart::{Node, Part, generate_boundary, write_multipart}; +use hyper::header::HeaderMap; +use mime_multipart::{Node, Part, write_multipart}; use crate::models; use crate::header; @@ -61,15 +64,14 @@ fn into_base_path(input: impl TryInto, } let host = uri.host().ok_or(ClientInitError::MissingHost)?; - let port = uri.port_u16().map(|x| format!(":{}", x)).unwrap_or_default(); - Ok(format!("{}://{}{}{}", scheme, host, port, uri.path().trim_end_matches('/'))) + let port = uri.port_u16().map(|x| format!(":{x}")).unwrap_or_default(); + Ok(format!("{scheme}://{host}{port}{}", uri.path().trim_end_matches('/'))) } /// A client that implements the API by making HTTP calls out to a server. pub struct Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -86,8 +88,7 @@ pub struct Client where impl fmt::Debug for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -99,8 +100,7 @@ impl fmt::Debug for Client where impl Clone for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -114,8 +114,19 @@ impl Clone for Client where } } -impl Client, C>, C> where - Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static, +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + Connector, + BoxBody + > + >, + C + >, + C +> where + Connector: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static, C: Clone + Send + Sync + 'static, { /// Create a client with a custom implementation of hyper::client::Connect. @@ -129,7 +140,7 @@ impl Client" /// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")` /// * `connector` - Implementation of `hyper::client::Connect` to use for the client pub fn try_new_with_connector( @@ -138,8 +149,8 @@ impl Client Result { - let client_service = hyper::client::Client::builder().build(connector); - let client_service = DropContextService::new(client_service); + let client_service = hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector); + let client_service = DropContextService::new(hyper_util::service::TowerToHyperService::new(client_service)); Ok(Self { client_service, @@ -149,28 +160,29 @@ impl Client; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HyperHttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + #[derive(Debug, Clone)] pub enum HyperClient { - Http(hyper::client::Client), - Https(hyper::client::Client), + Http(hyper_util::client::legacy::Client>), + #[cfg(feature = "client-tls")] + Https(hyper_util::client::legacy::Client>), } -impl Service> for HyperClient { - type Response = Response; - type Error = hyper::Error; - type Future = hyper::client::ResponseFuture; - - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - match self { - HyperClient::Http(client) => client.poll_ready(cx), - HyperClient::Https(client) => client.poll_ready(cx), - } - } +impl Service>> for HyperClient { + type Response = Response; + type Error = hyper_util::client::legacy::Error; + type Future = hyper_util::client::legacy::ResponseFuture; - fn call(&mut self, req: Request) -> Self::Future { + fn call(&self, req: Request>) -> Self::Future { match self { - HyperClient::Http(client) => client.call(req), - HyperClient::Https(client) => client.call(req) + HyperClient::Http(client) => client.request(req), + #[cfg(feature = "client-tls")] + HyperClient::Https(client) => client.request(req), } } } @@ -181,7 +193,7 @@ impl Client, C> where /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new( base_path: &str, ) -> Result { @@ -194,13 +206,19 @@ impl Client, C> where let client_service = match scheme.as_str() { "http" => { - HyperClient::Http(hyper::client::Client::builder().build(connector.build())) + HyperClient::Http(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector.build())) + }, + #[cfg(feature = "client-tls")] + "https" => { + let https_connector = connector + .https() + .build() + .map_err(ClientInitError::SslError)?; + HyperClient::Https(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(https_connector)) }, + #[cfg(not(feature = "client-tls"))] "https" => { - let connector = connector.https() - .build() - .map_err(ClientInitError::SslError)?; - HyperClient::Https(hyper::client::Client::builder().build(connector)) + return Err(ClientInitError::TlsNotEnabled); }, _ => { return Err(ClientInitError::InvalidScheme); @@ -217,13 +235,24 @@ impl Client, C> where } } -impl Client, C>, C> where +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + hyper_util::client::legacy::connect::HttpConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new_http( base_path: &str, ) -> Result { @@ -233,19 +262,46 @@ impl Client; - -#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] -type HttpsConnector = hyper_openssl::HttpsConnector; - -impl Client, C>, C> where +#[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] +type HttpsConnector = hyper_tls::HttpsConnector; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + +#[cfg(feature = "client-tls")] +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + HttpsConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { - /// Create a client with a TLS connection to the server + /// Create a client with a TLS connection to the server. + /// + /// # Arguments + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + pub fn try_new_https(base_path: &str) -> Result + { + let https_connector = Connector::builder() + .https() + .build() + .map_err(ClientInitError::SslError)?; + Self::try_new_with_connector(base_path, Some("https"), https_connector) + } + + /// Create a client with a TLS connection to the server using OpenSSL via swagger. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn try_new_https(base_path: &str) -> Result { let https_connector = Connector::builder() @@ -255,10 +311,10 @@ impl Client, C Self::try_new_with_connector(base_path, Some("https"), https_connector) } - /// Create a client with a TLS connection to the server using a pinned certificate + /// Create a client with a TLS connection to the server using a pinned certificate. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn try_new_https_pinned( @@ -279,7 +335,7 @@ impl Client, C /// Create a client with a mutually authenticated TLS connection to the server. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server /// * `client_key` - Path to the client private key /// * `client_certificate` - Path to the client's public certificate associated with the private key @@ -307,8 +363,7 @@ impl Client, C impl Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -342,12 +397,15 @@ pub enum ClientInitError { /// Missing Hostname MissingHost, + /// HTTPS requested but TLS features not enabled + TlsNotEnabled, + /// SSL Connection Error - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + #[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] SslError(native_tls::Error), /// SSL Connection Error - #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] SslError(openssl::error::ErrorStack), } @@ -370,23 +428,25 @@ impl Error for ClientInitError { } } +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + #[async_trait] -impl Api for Client where +impl Api for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C), + Response=Response> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Has + Clone + Send + Sync + 'static, + B: hyper::body::Body + Send + 'static + Unpin, + B::Data: Send, + B::Error: Into>, { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - match self.client_service.clone().poll_ready(cx) { - Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())), - Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)), - Poll::Pending => Poll::Pending, - } - } + #[allow(clippy::vec_init_then_push)] async fn multipart_related_request_post( &self, param_required_binary_field: swagger::ByteArray, @@ -395,6 +455,7 @@ impl Api for Client where context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/multipart_related_request", self.base_path @@ -412,36 +473,27 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - // Construct the Body for a multipart/related request. The mime 0.2.6 library - // does not parse quoted-string parameters correctly. The boundary doesn't - // need to be a quoted string if it does not contain a '/', hence ensure - // no such boundary is used. - let mut boundary = generate_boundary(); - for b in boundary.iter_mut() { - if b == &(b'/') { - *b = b'='; - } - } - + // Consumes multipart/related body + let boundary = swagger::multipart::related::generate_boundary(); let mut body_parts = vec![]; if let Some(object_field) = param_object_field { let part = Node::Part(Part { headers: { - let mut h = Headers::new(); - h.set(ContentType("application/json".parse().unwrap())); - h.set_raw("Content-ID", vec![b"object_field".to_vec()]); + let mut h = HeaderMap::new(); + h.insert(CONTENT_TYPE, HeaderValue::from_static("application/json")); + h.insert("Content-ID", HeaderValue::from_static("object_field")); h }, body: serde_json::to_string(&object_field) @@ -454,9 +506,9 @@ impl Api for Client where if let Some(optional_binary_field) = param_optional_binary_field { let part = Node::Part(Part { headers: { - let mut h = Headers::new(); - h.set(ContentType("application/zip".parse().unwrap())); - h.set_raw("Content-ID", vec![b"optional_binary_field".to_vec()]); + let mut h = HeaderMap::new(); + h.insert(CONTENT_TYPE, HeaderValue::from_static("application/zip")); + h.insert("Content-ID", HeaderValue::from_static("optional_binary_field")); h }, body: optional_binary_field.0, @@ -467,9 +519,9 @@ impl Api for Client where { let part = Node::Part(Part { headers: { - let mut h = Headers::new(); - h.set(ContentType("image/png".parse().unwrap())); - h.set_raw("Content-ID", vec![b"required_binary_field".to_vec()]); + let mut h = HeaderMap::new(); + h.insert(CONTENT_TYPE, HeaderValue::from_static("image/png")); + h.insert("Content-ID", HeaderValue::from_static("required_binary_field")); h }, body: param_required_binary_field.0, @@ -478,12 +530,13 @@ impl Api for Client where } // Write the body into a vec. - let mut body: Vec = vec![]; + // RFC 13341 Section 7.2.1 suggests that the body should begin with a + // CRLF prior to the first boundary. The mime_multipart library doesn't + // do this, so we do it instead. + let mut body: Vec = vec![b'\r', b'\n']; write_multipart(&mut body, &boundary, &body_parts) .expect("Failed to write multipart body"); - // Add the message body to the request object. - *request.body_mut() = Body::from(body); let header = "multipart/related"; request.headers_mut().insert(CONTENT_TYPE, @@ -491,17 +544,20 @@ impl Api for Client where &[header.as_bytes(), "; boundary=".as_bytes(), &boundary, "; type=\"application/json\"".as_bytes()].concat() ) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) + Err(e) => return Err(ApiError(format!("Unable to create header: {header} - {e}"))) }); + // Add the message body to the request object. + *request.body_mut() = BoxBody::new(Full::new(Bytes::from(body))); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 201 => { @@ -511,24 +567,23 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn multipart_request_post( &self, param_string_field: String, @@ -538,6 +593,7 @@ impl Api for Client where context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/multipart_request", self.base_path @@ -555,29 +611,30 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let (body_string, multipart_header) = { + // Consumes multipart/form body + let (body_bytes, multipart_header) = { let mut multipart = Multipart::new(); // For each parameter, encode as appropriate and add to the multipart body as a stream. let string_field_str = match serde_json::to_string(¶m_string_field) { Ok(str) => str, - Err(e) => return Err(ApiError(format!("Unable to serialize string_field to string: {}", e))), + Err(e) => return Err(ApiError(format!("Unable to serialize string_field to string: {e}"))), }; let string_field_vec = string_field_str.as_bytes().to_vec(); - let string_field_mime = mime_0_2::Mime::from_str("application/json").expect("impossible to fail to parse"); + let string_field_mime = mime::Mime::from_str("application/json").expect("impossible to fail to parse"); let string_field_cursor = Cursor::new(string_field_vec); multipart.add_stream("string_field", string_field_cursor, None as Option<&str>, Some(string_field_mime)); @@ -585,11 +642,11 @@ impl Api for Client where let optional_string_field_str = match serde_json::to_string(¶m_optional_string_field) { Ok(str) => str, - Err(e) => return Err(ApiError(format!("Unable to serialize optional_string_field to string: {}", e))), + Err(e) => return Err(ApiError(format!("Unable to serialize optional_string_field to string: {e}"))), }; let optional_string_field_vec = optional_string_field_str.as_bytes().to_vec(); - let optional_string_field_mime = mime_0_2::Mime::from_str("application/json").expect("impossible to fail to parse"); + let optional_string_field_mime = mime::Mime::from_str("application/json").expect("impossible to fail to parse"); let optional_string_field_cursor = Cursor::new(optional_string_field_vec); multipart.add_stream("optional_string_field", optional_string_field_cursor, None as Option<&str>, Some(optional_string_field_mime)); @@ -597,11 +654,11 @@ impl Api for Client where let object_field_str = match serde_json::to_string(¶m_object_field) { Ok(str) => str, - Err(e) => return Err(ApiError(format!("Unable to serialize object_field to string: {}", e))), + Err(e) => return Err(ApiError(format!("Unable to serialize object_field to string: {e}"))), }; let object_field_vec = object_field_str.as_bytes().to_vec(); - let object_field_mime = mime_0_2::Mime::from_str("application/json").expect("impossible to fail to parse"); + let object_field_mime = mime::Mime::from_str("application/json").expect("impossible to fail to parse"); let object_field_cursor = Cursor::new(object_field_vec); multipart.add_stream("object_field", object_field_cursor, None as Option<&str>, Some(object_field_mime)); @@ -610,9 +667,9 @@ impl Api for Client where let binary_field_vec = param_binary_field.to_vec(); - let binary_field_mime = match mime_0_2::Mime::from_str("application/octet-stream") { + let binary_field_mime = match mime::Mime::from_str("application/octet-stream") { Ok(mime) => mime, - Err(err) => return Err(ApiError(format!("Unable to get mime type: {:?}", err))), + Err(err) => return Err(ApiError(format!("Unable to get mime type: {err:?}"))), }; let binary_field_cursor = Cursor::new(binary_field_vec); @@ -622,38 +679,39 @@ impl Api for Client where let mut fields = match multipart.prepare() { Ok(fields) => fields, - Err(err) => return Err(ApiError(format!("Unable to build request: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build request: {err}"))), }; - let mut body_string = String::new(); + let mut body_bytes = Vec::new(); - match fields.read_to_string(&mut body_string) { + match fields.read_to_end(&mut body_bytes) { Ok(_) => (), - Err(err) => return Err(ApiError(format!("Unable to build body: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build body: {err}"))), } let boundary = fields.boundary(); - let multipart_header = format!("multipart/form-data;boundary={}", boundary); + let multipart_header = format!("multipart/form-data;boundary={boundary}"); - (body_string, multipart_header) - }; + (body_bytes, multipart_header) + }; - *request.body_mut() = Body::from(body_string); + *request.body_mut() = BoxBody::new(Full::new(Bytes::from(body_bytes))); request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(&multipart_header) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", multipart_header, e))) + Err(e) => return Err(ApiError(format!("Unable to create header: {multipart_header} - {e}"))) }); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 201 => { @@ -663,24 +721,23 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn multiple_identical_mime_types_post( &self, param_binary1: Option, @@ -688,6 +745,7 @@ impl Api for Client where context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/multiple-identical-mime-types", self.base_path @@ -705,36 +763,27 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - // Construct the Body for a multipart/related request. The mime 0.2.6 library - // does not parse quoted-string parameters correctly. The boundary doesn't - // need to be a quoted string if it does not contain a '/', hence ensure - // no such boundary is used. - let mut boundary = generate_boundary(); - for b in boundary.iter_mut() { - if b == &(b'/') { - *b = b'='; - } - } - + // Consumes multipart/related body + let boundary = swagger::multipart::related::generate_boundary(); let mut body_parts = vec![]; if let Some(binary1) = param_binary1 { let part = Node::Part(Part { headers: { - let mut h = Headers::new(); - h.set(ContentType("application/octet-stream".parse().unwrap())); - h.set_raw("Content-ID", vec![b"binary1".to_vec()]); + let mut h = HeaderMap::new(); + h.insert(CONTENT_TYPE, HeaderValue::from_static("application/octet-stream")); + h.insert("Content-ID", HeaderValue::from_static("binary1")); h }, body: binary1.0, @@ -745,9 +794,9 @@ impl Api for Client where if let Some(binary2) = param_binary2 { let part = Node::Part(Part { headers: { - let mut h = Headers::new(); - h.set(ContentType("application/octet-stream".parse().unwrap())); - h.set_raw("Content-ID", vec![b"binary2".to_vec()]); + let mut h = HeaderMap::new(); + h.insert(CONTENT_TYPE, HeaderValue::from_static("application/octet-stream")); + h.insert("Content-ID", HeaderValue::from_static("binary2")); h }, body: binary2.0, @@ -756,12 +805,13 @@ impl Api for Client where } // Write the body into a vec. - let mut body: Vec = vec![]; + // RFC 13341 Section 7.2.1 suggests that the body should begin with a + // CRLF prior to the first boundary. The mime_multipart library doesn't + // do this, so we do it instead. + let mut body: Vec = vec![b'\r', b'\n']; write_multipart(&mut body, &boundary, &body_parts) .expect("Failed to write multipart body"); - // Add the message body to the request object. - *request.body_mut() = Body::from(body); let header = "multipart/related"; request.headers_mut().insert(CONTENT_TYPE, @@ -769,17 +819,20 @@ impl Api for Client where &[header.as_bytes(), "; boundary=".as_bytes(), &boundary, "; type=\"application/json\"".as_bytes()].concat() ) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) + Err(e) => return Err(ApiError(format!("Unable to create header: {header} - {e}"))) }); + // Add the message body to the request object. + *request.body_mut() = BoxBody::new(Full::new(Bytes::from(body))); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -789,18 +842,16 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/context.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/context.rs index ee8e118587bb..45180a543112 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/src/context.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/context.rs @@ -6,9 +6,9 @@ use std::default::Default; use std::io; use std::marker::PhantomData; use std::task::{Poll, Context}; -use swagger::auth::{AuthData, Authorization, Bearer, Scopes}; +use swagger::auth::{AuthData, Authorization, Scopes}; use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString}; -use crate::{Api, AuthenticationApi}; +use crate::Api; use log::error; pub struct MakeAddContext { @@ -16,11 +16,11 @@ pub struct MakeAddContext { marker: PhantomData, } -impl MakeAddContext +impl MakeAddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, + C: Send + 'static, { pub fn new(inner: T) -> MakeAddContext { MakeAddContext { @@ -30,27 +30,34 @@ where } } +impl Clone for MakeAddContext +where + T: Clone, +{ + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + // Make a service that adds context. -impl Service for +impl Service for MakeAddContext where Target: Send, A: Default + Push + Send, B: Push, Result = C>, - C: Push, Result = D>, - D: Send + 'static, + C: Send + 'static, T: Service + Send, T::Future: Send + 'static { type Error = T::Error; - type Response = AddContext; + type Response = AddContext; type Future = BoxFuture<'static, Result>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, target: Target) -> Self::Future { + fn call(&self, target: Target) -> Self::Future { let service = self.inner.call(target); Box::pin(async move { @@ -60,21 +67,17 @@ where } /// Middleware to add context data from the request -pub struct AddContext -where - A: Default + Push, - B: Push, Result = C>, - C: Push, Result = D> +#[derive(Debug, Clone)] +pub struct AddContext { inner: T, marker: PhantomData, } -impl AddContext +impl AddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, { pub fn new(inner: T) -> Self { AddContext { @@ -84,30 +87,23 @@ where } } -impl Service> for AddContext +impl Service> for AddContext where A: Default + Push, B: Push, Result=C>, - C: Push, Result=D>, - D: Send + 'static, - T: Service<(Request, D)> + AuthenticationApi + C: Send + 'static, + T: Service<(Request, C)> { type Error = T::Error; type Future = T::Future; type Response = T::Response; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - - fn call(&mut self, request: Request) -> Self::Future { + fn call(&self, request: Request) -> Self::Future { let context = A::default().push(XSpanIdString::get_or_generate(&request)); let headers = request.headers(); let context = context.push(None::); - let context = context.push(None::); self.inner.call((request, context)) } diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/header.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/header.rs index 5bc6ebe929b9..823d2779b31f 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/src/header.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/header.rs @@ -31,11 +31,9 @@ macro_rules! ihv_generate { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse::<$t>() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse {} as a string: {}", - stringify!($t), e)), + Err(e) => Err(format!("Unable to parse {} as a string: {e}", stringify!($t))), }, - Err(e) => Err(format!("Unable to parse header {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header {hdr_value:?} as a string - {e}")), } } } @@ -76,8 +74,7 @@ impl TryFrom for IntoHeaderValue> { y => Some(y.to_string()), }) .collect())), - Err(e) => Err(format!("Unable to parse header: {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header: {hdr_value:?} as a string - {e}")), } } } @@ -88,8 +85,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(&hdr_value.0.join(", ")) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} into a header - {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} into a header - {e}")) } } } @@ -102,8 +98,7 @@ impl TryFrom for IntoHeaderValue { fn try_from(hdr_value: HeaderValue) -> Result { match hdr_value.to_str() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())), - Err(e) => Err(format!("Unable to convert header {:?} to {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to {e}")), } } } @@ -114,8 +109,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")) } } } @@ -128,11 +122,9 @@ impl TryFrom for IntoHeaderValue { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse bool from {} - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse bool from {hdr_value} - {e}")), }, - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")), } } } @@ -143,8 +135,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0.to_string()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert: {:?} into a header: {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert: {hdr_value:?} into a header: {e}")) } } } @@ -158,11 +149,9 @@ impl TryFrom for IntoHeaderValue> { match hdr_value.to_str() { Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) { Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))), - Err(e) => Err(format!("Unable to parse: {} as date - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse: {hdr_value} as date - {e}")), }, - Err(e) => Err(format!("Unable to convert header {:?} to string {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to string {e}")), } } } @@ -173,8 +162,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} to a header: {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} to a header: {e}")), } } } diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/lib.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/lib.rs index 8c41db6313c6..43c3b8fb6e35 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/src/lib.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/lib.rs @@ -3,14 +3,15 @@ use async_trait::async_trait; use futures::Stream; +#[cfg(feature = "mock")] +use mockall::automock; use std::error::Error; use std::collections::BTreeSet; use std::task::{Poll, Context}; -use swagger::{ApiError, ContextWrapper}; +use swagger::{ApiError, ContextWrapper, auth::Authorization}; use serde::{Serialize, Deserialize}; -use crate::server::Authorization; - +#[cfg(any(feature = "client", feature = "server"))] type ServiceError = Box; pub const BASE_PATH: &str = ""; @@ -39,13 +40,10 @@ pub enum MultipleIdenticalMimeTypesPostResponse { } /// API +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait Api { - fn poll_ready(&self, _cx: &mut Context) -> Poll>> { - Poll::Ready(Ok(())) - } - async fn multipart_related_request_post( &self, required_binary_field: swagger::ByteArray, @@ -70,11 +68,14 @@ pub trait Api { } /// API where `Context` isn't passed on every API call +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait ApiNoContext { - - fn poll_ready(&self, _cx: &mut Context) -> Poll>>; + // The std::task::Context struct houses a reference to std::task::Waker with the lifetime <'a>. + // Adding an anonymous lifetime `'a` to allow mockall to create a mock object with the right lifetimes. + // This is needed because the compiler is unable to determine the lifetimes on F's trait bound + // where F is the closure created by mockall. We use higher-rank trait bounds here to get around this. fn context(&self) -> &C; @@ -116,10 +117,6 @@ impl + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt for T #[async_trait] impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for ContextWrapper { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - self.api().poll_ready(cx) - } - fn context(&self) -> &C { ContextWrapper::context(self) } diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/models.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/models.rs index ea0267cbe021..60eefc819d75 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/src/models.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/models.rs @@ -1,27 +1,53 @@ #![allow(unused_qualifications)] - +#[cfg(not(feature = "validate"))] use validator::Validate; use crate::models; #[cfg(any(feature = "client", feature = "server"))] use crate::header; +#[cfg(feature = "validate")] +use serde_valid::Validate; -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct MultipartRelatedRequest { #[serde(rename = "object_field")] + + #[cfg_attr(feature = "validate", validate)] #[serde(skip_serializing_if="Option::is_none")] pub object_field: Option, #[serde(rename = "optional_binary_field")] + #[serde(skip_serializing_if="Option::is_none")] pub optional_binary_field: Option, #[serde(rename = "required_binary_field")] + pub required_binary_field: swagger::ByteArray, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for MultipartRelatedRequest { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for MultipartRelatedRequest { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl MultipartRelatedRequest { #[allow(clippy::new_without_default)] @@ -35,27 +61,22 @@ impl MultipartRelatedRequest { } /// Converts the MultipartRelatedRequest value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for MultipartRelatedRequest { - fn to_string(&self) -> String { +impl std::fmt::Display for MultipartRelatedRequest { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - // Skipping object_field in query parameter serialization - - // Skipping optional_binary_field in query parameter serialization - // Skipping optional_binary_field in query parameter serialization - - // Skipping required_binary_field in query parameter serialization - // Skipping required_binary_field in query parameter serialization - + // Skipping non-primitive type object_field in query parameter serialization + // Skipping binary data optional_binary_field in query parameter serialization + // Skipping binary data required_binary_field in query parameter serialization ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a MultipartRelatedRequest value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for MultipartRelatedRequest { type Err = String; @@ -117,8 +138,7 @@ impl std::convert::TryFrom> for match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for MultipartRelatedRequest - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for MultipartRelatedRequest - value: {hdr_value} is invalid {e}")) } } } @@ -133,30 +153,92 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into MultipartRelatedRequest - {}", - value, err)) + format!("Unable to convert header value '{value}' into MultipartRelatedRequest - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into MultipartRelatedRequest - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct MultipartRequestObjectField { #[serde(rename = "field_a")] + pub field_a: String, #[serde(rename = "field_b")] + #[serde(skip_serializing_if="Option::is_none")] pub field_b: Option>, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for MultipartRequestObjectField { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for MultipartRequestObjectField { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl MultipartRequestObjectField { #[allow(clippy::new_without_default)] @@ -169,31 +251,27 @@ impl MultipartRequestObjectField { } /// Converts the MultipartRequestObjectField value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for MultipartRequestObjectField { - fn to_string(&self) -> String { +impl std::fmt::Display for MultipartRequestObjectField { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - Some("field_a".to_string()), Some(self.field_a.to_string()), - - self.field_b.as_ref().map(|field_b| { [ "field_b".to_string(), field_b.iter().map(|x| x.to_string()).collect::>().join(","), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a MultipartRequestObjectField value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for MultipartRequestObjectField { type Err = String; @@ -252,8 +330,7 @@ impl std::convert::TryFrom> match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for MultipartRequestObjectField - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for MultipartRequestObjectField - value: {hdr_value} is invalid {e}")) } } } @@ -268,31 +345,93 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into MultipartRequestObjectField - {}", - value, err)) + format!("Unable to convert header value '{value}' into MultipartRequestObjectField - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into MultipartRequestObjectField - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct MultipleIdenticalMimeTypesPostRequest { #[serde(rename = "binary1")] + #[serde(skip_serializing_if="Option::is_none")] pub binary1: Option, #[serde(rename = "binary2")] + #[serde(skip_serializing_if="Option::is_none")] pub binary2: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for MultipleIdenticalMimeTypesPostRequest { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for MultipleIdenticalMimeTypesPostRequest { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl MultipleIdenticalMimeTypesPostRequest { #[allow(clippy::new_without_default)] @@ -305,25 +444,21 @@ impl MultipleIdenticalMimeTypesPostRequest { } /// Converts the MultipleIdenticalMimeTypesPostRequest value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for MultipleIdenticalMimeTypesPostRequest { - fn to_string(&self) -> String { +impl std::fmt::Display for MultipleIdenticalMimeTypesPostRequest { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - // Skipping binary1 in query parameter serialization - // Skipping binary1 in query parameter serialization - - // Skipping binary2 in query parameter serialization - // Skipping binary2 in query parameter serialization - + // Skipping binary data binary1 in query parameter serialization + // Skipping binary data binary2 in query parameter serialization ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a MultipleIdenticalMimeTypesPostRequest value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for MultipleIdenticalMimeTypesPostRequest { type Err = String; @@ -381,8 +516,7 @@ impl std::convert::TryFrom std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for MultipleIdenticalMimeTypesPostRequest - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for MultipleIdenticalMimeTypesPostRequest - value: {hdr_value} is invalid {e}")) } } } @@ -397,14 +531,54 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into MultipleIdenticalMimeTypesPostRequest - {}", - value, err)) + format!("Unable to convert header value '{value}' into MultipleIdenticalMimeTypesPostRequest - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into MultipleIdenticalMimeTypesPostRequest - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/server/mod.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/server/mod.rs index d8e45aac7115..0401d842dc72 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/src/server/mod.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/server/mod.rs @@ -1,10 +1,14 @@ +use bytes::Bytes; use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt}; -use hyper::{Request, Response, StatusCode, Body, HeaderMap}; +use http_body_util::{combinators::BoxBody, Full}; +use hyper::{body::{Body, Incoming}, HeaderMap, Request, Response, StatusCode}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; use log::warn; +#[cfg(feature = "validate")] +use serde_valid::Validate; #[allow(unused_imports)] use std::convert::{TryFrom, TryInto}; -use std::error::Error; +use std::{convert::Infallible, error::Error}; use std::future::Future; use std::marker::PhantomData; use std::task::{Context, Poll}; @@ -12,18 +16,16 @@ use swagger::{ApiError, BodyExt, Has, RequestParser, XSpanIdString}; pub use swagger::auth::Authorization; use swagger::auth::Scopes; use url::form_urlencoded; -use hyper_0_10::header::{Headers, ContentType}; -use mime_0_2::{TopLevel, SubLevel, Mime as Mime2}; use mime_multipart::{read_multipart_body, Node, Part}; use multipart::server::Multipart; -use multipart::server::save::SaveResult; +use multipart::server::save::{PartialReason, SaveResult}; #[allow(unused_imports)] use crate::{models, header, AuthenticationApi}; pub use crate::context; -type ServiceFuture = BoxFuture<'static, Result, crate::ServiceError>>; +type ServiceFuture = BoxFuture<'static, Result>, crate::ServiceError>>; use crate::{Api, MultipartRelatedRequestPostResponse, @@ -50,28 +52,65 @@ mod paths { } -pub struct MakeService where +pub struct MakeService +where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { api_impl: T, + multipart_form_size_limit: Option, marker: PhantomData, + validation: bool } -impl MakeService where +impl MakeService +where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { pub fn new(api_impl: T) -> Self { MakeService { api_impl, - marker: PhantomData + multipart_form_size_limit: Some(8 * 1024 * 1024), + marker: PhantomData, + validation: false } } + + /// Configure size limit when inspecting a multipart/form body. + /// + /// Default is 8 MiB. + /// + /// Set to None for no size limit, which presents a Denial of Service attack risk. + pub fn multipart_form_size_limit(mut self, multipart_form_size_limit: Option) -> Self { + self.multipart_form_size_limit = multipart_form_size_limit; + self + } + + // Turn on/off validation for the service being made. + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation; + } } +impl Clone for MakeService +where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static +{ + fn clone(&self) -> Self { + Self { + api_impl: self.api_impl.clone(), + multipart_form_size_limit: Some(8 * 1024 * 1024), + marker: PhantomData, + validation: self.validation + } + } +} -impl hyper::service::Service for MakeService where +impl hyper::service::Service for MakeService +where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { @@ -79,43 +118,85 @@ impl hyper::service::Service for MakeService where type Error = crate::ServiceError; type Future = future::Ready>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } + fn call(&self, target: Target) -> Self::Future { + let service = Service::new(self.api_impl.clone(), self.validation) + .multipart_form_size_limit(self.multipart_form_size_limit); - fn call(&mut self, target: Target) -> Self::Future { - future::ok(Service::new( - self.api_impl.clone(), - )) + future::ok(service) } } -fn method_not_allowed() -> Result, crate::ServiceError> { +fn method_not_allowed() -> Result>, crate::ServiceError> { Ok( Response::builder().status(StatusCode::METHOD_NOT_ALLOWED) - .body(Body::empty()) + .body(BoxBody::new(http_body_util::Empty::new())) .expect("Unable to create Method Not Allowed response") ) } +#[allow(unused_macros)] +#[cfg(not(feature = "validate"))] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => (); +} + +#[allow(unused_macros)] +#[cfg(feature = "validate")] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => { + let $parameter = if $validation { + match $parameter.validate() { + Ok(()) => $parameter, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .header(CONTENT_TYPE, mime::TEXT_PLAIN.as_ref()) + .body(BoxBody::new(format!("Invalid value in body parameter {}: {}", $base_name, e))) + .expect(&format!("Unable to create Bad Request response for invalid value in body parameter {}", $base_name))), + } + } else { + $parameter + }; + } +} + pub struct Service where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { api_impl: T, + multipart_form_size_limit: Option, marker: PhantomData, + // Enable regex pattern validation of received JSON models + validation: bool, } impl Service where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { - pub fn new(api_impl: T) -> Self { + pub fn new(api_impl: T, validation: bool) -> Self { Service { api_impl, - marker: PhantomData + multipart_form_size_limit: Some(8 * 1024 * 1024), + marker: PhantomData, + validation, } } + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation + } + + + /// Configure size limit when extracting a multipart/form body. + /// + /// Default is 8 MiB. + /// + /// Set to None for no size limit, which presents a Denial of Service attack risk. + pub fn multipart_form_size_limit(mut self, multipart_form_size_limit: Option) -> Self { + self.multipart_form_size_limit = multipart_form_size_limit; + self + } } impl Clone for Service where @@ -125,75 +206,84 @@ impl Clone for Service where fn clone(&self) -> Self { Service { api_impl: self.api_impl.clone(), + multipart_form_size_limit: Some(8 * 1024 * 1024), marker: self.marker, + validation: self.validation, } } } -impl hyper::service::Service<(Request, C)> for Service where +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + +fn body_from_str(s: &str) -> BoxBody { + BoxBody::new(Full::new(Bytes::copy_from_slice(s.as_bytes()))) +} + +impl hyper::service::Service<(Request, C)> for Service where T: Api + Clone + Send + Sync + 'static, - C: Has + Send + Sync + 'static + C: Has + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, { - type Response = Response; + type Response = Response>; type Error = crate::ServiceError; type Future = ServiceFuture; - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - self.api_impl.poll_ready(cx) - } - - fn call(&mut self, req: (Request, C)) -> Self::Future { async fn run(mut api_impl: T, req: (Request, C)) -> Result, crate::ServiceError> where - T: Api + Clone + Send + 'static, - C: Has + Send + Sync + 'static - { - let (request, context) = req; - let (parts, body) = request.into_parts(); - let (method, uri, headers) = (parts.method, parts.uri, parts.headers); - let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); - - match method { + fn call(&self, req: (Request, C)) -> Self::Future { + async fn run( + mut api_impl: T, + req: (Request, C), + validation: bool, + multipart_form_size_limit: Option, + ) -> Result>, crate::ServiceError> + where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, + { + let (request, context) = req; + let (parts, body) = request.into_parts(); + let (method, uri, headers) = (parts.method, parts.uri, parts.headers); + let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); + + match method { // MultipartRelatedRequestPost - POST /multipart_related_request hyper::Method::POST if path.matched(paths::ID_MULTIPART_RELATED_REQUEST) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw(); - match result.await { - Ok(body) => { - let mut unused_elements: Vec = vec![]; - + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); + match result { + Ok(body) => { + let mut unused_elements : Vec = vec![]; // Get multipart chunks. - // Extract the top-level content type header. - let content_type_mime = headers - .get(CONTENT_TYPE) - .ok_or_else(|| "Missing content-type header".to_string()) - .and_then(|v| v.to_str().map_err(|e| format!("Couldn't read content-type header value for MultipartRelatedRequestPost: {}", e))) - .and_then(|v| v.parse::().map_err(|_e| "Couldn't parse content-type header value for MultipartRelatedRequestPost".to_string())); - - // Insert top-level content type header into a Headers object. - let mut multi_part_headers = Headers::new(); - match content_type_mime { - Ok(content_type_mime) => { - multi_part_headers.set(ContentType(content_type_mime)); - }, + // Create headers from top-level content type header. + let multipart_headers = match swagger::multipart::related::create_multipart_headers(headers.get(CONTENT_TYPE)) { + Ok(headers) => headers, Err(e) => { return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(e)) + .body(BoxBody::new(e.to_string())) .expect("Unable to create Bad Request response due to unable to read content-type header for MultipartRelatedRequestPost")); } - } + }; // &*body expresses the body as a byteslice, &mut provides a // mutable reference to that byteslice. - let nodes = match read_multipart_body(&mut&*body, &multi_part_headers, false) { + let nodes = match read_multipart_body(&mut&*body, &multipart_headers, false) { Ok(nodes) => nodes, Err(e) => { return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Could not read multipart body for MultipartRelatedRequestPost: {}", e))) + .body(BoxBody::new(format!("Could not read multipart body for MultipartRelatedRequestPost: {e}"))) .expect("Unable to create Bad Request response due to unable to read multipart body for MultipartRelatedRequestPost")); } }; @@ -204,20 +294,20 @@ impl hyper::service::Service<(Request, C)> for Service where for node in nodes { if let Node::Part(part) = node { - let content_type = part.content_type().map(|x| format!("{}",x)); + let content_type = part.content_type().map(|x| format!("{x}")); match content_type.as_deref() { Some("application/json") if param_object_field.is_none() => { // Extract JSON part. let deserializer = &mut serde_json::Deserializer::from_slice(part.body.as_slice()); let json_data: models::MultipartRequestObjectField = match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in JSON part: {}", path); + warn!("Ignoring unknown field in JSON part: {path}"); unused_elements.push(path.to_string()); }) { Ok(json_data) => json_data, Err(e) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter models::MultipartRequestObjectField - doesn't match schema: {}", e))) - .expect("Unable to create Bad Request response for invalid body parameter models::MultipartRequestObjectField due to schema")) + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new(format!("Couldn't parse body parameter models::MultipartRequestObjectField - doesn't match schema: {e}"))) + .expect("Unable to create Bad Request response for invalid body parameter models::MultipartRequestObjectField due to schema")) }; // Push JSON part to return object. param_object_field.get_or_insert(json_data); @@ -229,7 +319,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_required_binary_field.get_or_insert(swagger::ByteArray(part.body)); }, Some(content_type) => { - warn!("Ignoring unexpected content type: {}", content_type); + warn!("Ignoring unexpected content type: {content_type}"); unused_elements.push(content_type.to_string()); }, None => { @@ -246,35 +336,43 @@ impl hyper::service::Service<(Request, C)> for Service where let param_required_binary_field = match param_required_binary_field { Some(x) => x, None => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required multipart/related parameter required_binary_field".to_string())) - .expect("Unable to create Bad Request response for missing multipart/related parameter required_binary_field due to schema")) + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Missing required multipart/related parameter required_binary_field".to_string())) + .expect("Unable to create Bad Request response for missing multipart/related parameter required_binary_field due to schema")) }; + let result = api_impl.multipart_related_request_post( param_required_binary_field, param_object_field, param_optional_binary_field, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) .expect("Unable to create X-Span-ID header value")); + if !unused_elements.is_empty() { + response.headers_mut().insert( + HeaderName::from_static("warning"), + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) + .expect("Unable to create Warning header value")); + } match result { Ok(rsp) => match rsp { MultipartRelatedRequestPostResponse::OK => { *response.status_mut() = StatusCode::from_u16(201).expect("Unable to turn 201 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -282,39 +380,67 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter Default: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter Default")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, // MultipartRequestPost - POST /multipart_request hyper::Method::POST if path.matched(paths::ID_MULTIPART_REQUEST) => { - let boundary = match swagger::multipart::form::boundary(&headers) { - Some(boundary) => boundary.to_string(), - None => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from("Couldn't find valid multipart body".to_string())) - .expect("Unable to create Bad Request response for incorrect boundary")), - }; - - // Form Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw(); - match result.await { - Ok(body) => { + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); + match result { + Ok(body) => { + let boundary = match swagger::multipart::form::boundary(&headers) { + Some(boundary) => boundary.to_string(), + None => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Couldn't find valid multipart body".to_string())) + .expect("Unable to create Bad Request response for incorrect boundary")), + }; + use std::io::Read; // Read Form Parameters from body - let mut entries = match Multipart::with_body(&body.to_vec()[..], boundary).save().temp() { + let mut entries = match Multipart::with_body(&body.to_vec()[..], boundary) + .save() + .size_limit(multipart_form_size_limit) + .temp() + { SaveResult::Full(entries) => { entries }, - _ => { + SaveResult::Partial(_, PartialReason::CountLimit) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Unable to process message part due to excessive parts".to_string())) + .expect("Unable to create Bad Request response due to excessive parts")) + }, + SaveResult::Partial(_, PartialReason::SizeLimit) => { return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Unable to process all message parts".to_string())) - .expect("Unable to create Bad Request response due to failure to process all message")) + .body(BoxBody::new("Unable to process message part due to excessive data".to_string())) + .expect("Unable to create Bad Request response due to excessive data")) + }, + SaveResult::Partial(_, PartialReason::Utf8Error(_)) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Unable to process message part due to invalid data".to_string())) + .expect("Unable to create Bad Request response due to invalid data")) + }, + SaveResult::Partial(_, PartialReason::IoError(_)) => { + return Ok(Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(BoxBody::new("Failed to process message part due an internal error".to_string())) + .expect("Unable to create Internal Server Error response due to an internal error")) + }, + SaveResult::Error(e) => { + return Ok(Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(BoxBody::new("Failed to process all message parts due to an internal error".to_string())) + .expect("Unable to create Internal Server Error response due to an internal error")) }, }; let field_string_field = entries.fields.remove("string_field"); @@ -329,7 +455,7 @@ impl hyper::service::Service<(Request, C)> for Service where return Ok( Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("string_field data does not match API definition : {}", e))) + .body(BoxBody::new(format!("string_field data does not match API definition : {e}"))) .expect("Unable to create Bad Request due to missing required form parameter string_field")) } }; @@ -339,7 +465,7 @@ impl hyper::service::Service<(Request, C)> for Service where return Ok( Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required form parameter string_field".to_string())) + .body(BoxBody::new("Missing required form parameter string_field".to_string())) .expect("Unable to create Bad Request due to missing required form parameter string_field")) } }; @@ -356,7 +482,7 @@ impl hyper::service::Service<(Request, C)> for Service where return Ok( Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("optional_string_field data does not match API definition : {}", e))) + .body(BoxBody::new(format!("optional_string_field data does not match API definition : {e}"))) .expect("Unable to create Bad Request due to missing required form parameter optional_string_field")) } }; @@ -380,7 +506,7 @@ impl hyper::service::Service<(Request, C)> for Service where return Ok( Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("object_field data does not match API definition : {}", e))) + .body(BoxBody::new(format!("object_field data does not match API definition : {e}"))) .expect("Unable to create Bad Request due to missing required form parameter object_field")) } }; @@ -403,10 +529,12 @@ impl hyper::service::Service<(Request, C)> for Service where return Ok( Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required form parameter binary_field".to_string())) + .body(BoxBody::new("Missing required form parameter binary_field".to_string())) .expect("Unable to create Bad Request due to missing required form parameter binary_field")) } }; + + let result = api_impl.multipart_request_post( param_string_field, param_binary_field, @@ -414,7 +542,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_object_field, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -425,13 +553,14 @@ impl hyper::service::Service<(Request, C)> for Service where MultipartRequestPostResponse::OK => { *response.status_mut() = StatusCode::from_u16(201).expect("Unable to turn 201 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -439,52 +568,41 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Couldn't read multipart body".to_string())) - .expect("Unable to create Bad Request response due to unable read multipart body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, // MultipleIdenticalMimeTypesPost - POST /multiple-identical-mime-types hyper::Method::POST if path.matched(paths::ID_MULTIPLE_IDENTICAL_MIME_TYPES) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw(); - match result.await { - Ok(body) => { - let mut unused_elements: Vec = vec![]; - + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); + match result { + Ok(body) => { + let mut unused_elements : Vec = vec![]; // Get multipart chunks. - // Extract the top-level content type header. - let content_type_mime = headers - .get(CONTENT_TYPE) - .ok_or_else(|| "Missing content-type header".to_string()) - .and_then(|v| v.to_str().map_err(|e| format!("Couldn't read content-type header value for MultipleIdenticalMimeTypesPost: {}", e))) - .and_then(|v| v.parse::().map_err(|_e| "Couldn't parse content-type header value for MultipleIdenticalMimeTypesPost".to_string())); - - // Insert top-level content type header into a Headers object. - let mut multi_part_headers = Headers::new(); - match content_type_mime { - Ok(content_type_mime) => { - multi_part_headers.set(ContentType(content_type_mime)); - }, + // Create headers from top-level content type header. + let multipart_headers = match swagger::multipart::related::create_multipart_headers(headers.get(CONTENT_TYPE)) { + Ok(headers) => headers, Err(e) => { return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(e)) + .body(BoxBody::new(e.to_string())) .expect("Unable to create Bad Request response due to unable to read content-type header for MultipleIdenticalMimeTypesPost")); } - } + }; // &*body expresses the body as a byteslice, &mut provides a // mutable reference to that byteslice. - let nodes = match read_multipart_body(&mut&*body, &multi_part_headers, false) { + let nodes = match read_multipart_body(&mut&*body, &multipart_headers, false) { Ok(nodes) => nodes, Err(e) => { return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Could not read multipart body for MultipleIdenticalMimeTypesPost: {}", e))) + .body(BoxBody::new(format!("Could not read multipart body for MultipleIdenticalMimeTypesPost: {e}"))) .expect("Unable to create Bad Request response due to unable to read multipart body for MultipleIdenticalMimeTypesPost")); } }; @@ -494,7 +612,7 @@ impl hyper::service::Service<(Request, C)> for Service where for node in nodes { if let Node::Part(part) = node { - let content_type = part.content_type().map(|x| format!("{}",x)); + let content_type = part.content_type().map(|x| format!("{x}")); match content_type.as_deref() { Some("application/octet-stream") if param_binary1.is_none() => { param_binary1.get_or_insert(swagger::ByteArray(part.body)); @@ -503,7 +621,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_binary2.get_or_insert(swagger::ByteArray(part.body)); }, Some(content_type) => { - warn!("Ignoring unexpected content type: {}", content_type); + warn!("Ignoring unexpected content type: {content_type}"); unused_elements.push(content_type.to_string()); }, None => { @@ -518,29 +636,37 @@ impl hyper::service::Service<(Request, C)> for Service where // Check that the required multipart chunks are present. + let result = api_impl.multiple_identical_mime_types_post( param_binary1, param_binary2, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) .expect("Unable to create X-Span-ID header value")); + if !unused_elements.is_empty() { + response.headers_mut().insert( + HeaderName::from_static("warning"), + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) + .expect("Unable to create Warning header value")); + } match result { Ok(rsp) => match rsp { MultipleIdenticalMimeTypesPostResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -548,19 +674,26 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter Default: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter Default")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, _ if path.matched(paths::ID_MULTIPART_RELATED_REQUEST) => method_not_allowed(), _ if path.matched(paths::ID_MULTIPART_REQUEST) => method_not_allowed(), _ if path.matched(paths::ID_MULTIPLE_IDENTICAL_MIME_TYPES) => method_not_allowed(), - _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) - .body(Body::empty()) - .expect("Unable to create Not Found response")) + _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) + .body(BoxBody::new(http_body_util::Empty::new())) + .expect("Unable to create Not Found response")) + } } - } Box::pin(run(self.api_impl.clone(), req)) } + Box::pin(run( + self.api_impl.clone(), + req, + self.validation, + self.multipart_form_size_limit + )) + } } /// Request parser for `Api`. diff --git a/samples/server/petstore/rust-server/output/multipart-v3/src/server/server_auth.rs b/samples/server/petstore/rust-server/output/multipart-v3/src/server/server_auth.rs index ba78eb2f3f5d..21b1d7babd03 100644 --- a/samples/server/petstore/rust-server/output/multipart-v3/src/server/server_auth.rs +++ b/samples/server/petstore/rust-server/output/multipart-v3/src/server/server_auth.rs @@ -1,11 +1,12 @@ use super::Service; use crate::{Api, AuthenticationApi}; +use headers::authorization::{Basic, Bearer}; use swagger::{ ApiError, - Authorization, - auth::{Basic, Bearer}, - Has, - XSpanIdString}; + Authorization, + Has, + XSpanIdString +}; impl AuthenticationApi for Service where T: Api + Clone + Send + 'static + AuthenticationApi, diff --git a/samples/server/petstore/rust-server/output/no-example-v3/.cargo/config.toml b/samples/server/petstore/rust-server/output/no-example-v3/.cargo/config.toml new file mode 100644 index 000000000000..df91f0f117f3 --- /dev/null +++ b/samples/server/petstore/rust-server/output/no-example-v3/.cargo/config.toml @@ -0,0 +1,19 @@ +[build] +rustflags = [ + "-W", "missing_docs", # detects missing documentation for public members + + "-W", "trivial_casts", # detects trivial casts which could be removed + + "-W", "trivial_numeric_casts", # detects trivial casts of numeric types which could be removed + + # unsafe is used in `TokioIo` bridging code copied from `hyper`. + # "-W", "unsafe_code", # usage of `unsafe` code + + "-W", "unused_qualifications", # detects unnecessarily qualified names + + "-W", "unused_extern_crates", # extern crates that are never used + + "-W", "unused_import_braces", # unnecessary braces around an imported item + + "-D", "warnings", # all warnings should be denied +] diff --git a/samples/server/petstore/rust-server/output/no-example-v3/.openapi-generator/FILES b/samples/server/petstore/rust-server/output/no-example-v3/.openapi-generator/FILES index c41dce9b6f0c..b1a97ff266dd 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/.openapi-generator/FILES +++ b/samples/server/petstore/rust-server/output/no-example-v3/.openapi-generator/FILES @@ -1,8 +1,9 @@ -.cargo/config +.cargo/config.toml .gitignore Cargo.toml README.md api/openapi.yaml +bin/cli.rs docs/OpGetRequest.md docs/default_api.md examples/ca.pem diff --git a/samples/server/petstore/rust-server/output/no-example-v3/.openapi-generator/VERSION b/samples/server/petstore/rust-server/output/no-example-v3/.openapi-generator/VERSION index f1358e30d8ae..f7962df3e243 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/.openapi-generator/VERSION +++ b/samples/server/petstore/rust-server/output/no-example-v3/.openapi-generator/VERSION @@ -1 +1 @@ -8.0.0-SNAPSHOT +7.22.0-SNAPSHOT diff --git a/samples/server/petstore/rust-server/output/no-example-v3/Cargo.toml b/samples/server/petstore/rust-server/output/no-example-v3/Cargo.toml index 3b708112b2fa..9e73002e56fe 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/Cargo.toml +++ b/samples/server/petstore/rust-server/output/no-example-v3/Cargo.toml @@ -8,74 +8,122 @@ license = "Unlicense" edition = "2018" [features] -default = ["client", "server"] +default = ["client", "server", "client-tls"] client = [ - "hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url" + "hyper", "percent-encoding", "hyper-util/http1", "hyper-util/http2", "url" +] +# TLS support - automatically selects backend based on target OS: +# - macOS/Windows/iOS: native-tls via hyper-tls +# - Other platforms: OpenSSL via hyper-openssl +# Dependencies are in target-specific sections below +client-tls = [ + "client", + "dep:native-tls", + "dep:hyper-tls", + "dep:openssl", + "dep:hyper-openssl", + "swagger/tls" ] server = [ - "serde_ignored", "hyper", "regex", "percent-encoding", "url", "lazy_static" + "serde_ignored", "hyper", "percent-encoding", "url", + "lazy_static", "regex" +] +cli = [ + "anyhow", "clap", "clap-verbosity-flag", "simple_logger", "tokio" ] conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"] -[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] -native-tls = { version = "0.2", optional = true } -hyper-tls = { version = "0.5", optional = true } - -[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] -hyper-openssl = { version = "0.9", optional = true } -openssl = {version = "0.10", optional = true } +mock = ["mockall"] +validate = ["regex", "serde_valid", "swagger/serdevalid"] [dependencies] # Common -async-trait = "0.1.24" +async-trait = "0.1.89" chrono = { version = "0.4", features = ["serde"] } futures = "0.3" -swagger = { version = "6.1", features = ["serdejson", "server", "client", "tls", "tcp"] } -log = "0.4.0" +swagger = { version = "7.0.0", features = ["serdejson", "server", "client"] } +headers = "0.4.1" +log = "0.4.29" + mime = "0.3" +mockall = { version = "0.14", optional = true } + serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -validator = { version = "0.16", features = ["derive"] } +serde_valid = { version = "2.0", optional = true } + +validator = { version = "0.20", features = ["derive"] } # Crates included if required by the API definition # Common between server and client features -hyper = {version = "0.14", features = ["full"], optional = true} -serde_ignored = {version = "0.1.1", optional = true} -url = {version = "2.1", optional = true} +bytes = "1.11" +http-body-util = "0.1.3" +hyper = { version = "1.9.0", features = ["full"], optional = true } +hyper-util = { version = "0.1.20", features = ["service"] } +serde_ignored = { version = "0.1.14", optional = true } +url = { version = "2.5", optional = true } # Client-specific +tower-service = "0.3.3" # Server, and client callback-specific -lazy_static = { version = "1.4", optional = true } -percent-encoding = {version = "2.1.0", optional = true} -regex = {version = "1.3", optional = true} +lazy_static = { version = "1.5", optional = true } +regex = { version = "1.12", optional = true } +percent-encoding = { version = "2.3.2", optional = true } + +# CLI-specific +anyhow = { version = "1", optional = true } +clap = { version = "4.6.0", features = ["env"], optional = true } +clap-verbosity-flag = { version = "3.0", optional = true } +simple_logger = { version = "5.2.0", features = ["stderr"], optional = true } +tokio = { version = "1.50.0", features = ["rt-multi-thread", "macros"], optional = true } # Conversion -frunk = { version = "0.3.0", optional = true } -frunk_derives = { version = "0.3.0", optional = true } -frunk_core = { version = "0.3.0", optional = true } -frunk-enum-derive = { version = "0.2.0", optional = true } -frunk-enum-core = { version = "0.2.0", optional = true } +frunk = { version = "0.4.4", optional = true } +frunk_derives = { version = "0.4.4", optional = true } +frunk_core = { version = "0.4.4", optional = true } +frunk-enum-derive = { version = "0.3.0", optional = true } +frunk-enum-core = { version = "0.3.0", optional = true } -# Bearer authentication -jsonwebtoken = { version = "9.3.0", optional = false } +# TLS dependencies - platform-specific backends +# On macOS/Windows/iOS, use native-tls via hyper-tls +[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] +native-tls = { version = "0.2", optional = true } +hyper-tls = { version = "0.6", optional = true } + +# On other platforms (Linux, etc.), use OpenSSL via hyper-openssl +[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] +openssl = { version = "0.10", optional = true } +hyper-openssl = { version = "0.10", optional = true } [dev-dependencies] -clap = "2.25" -env_logger = "0.7" -tokio = { version = "1.14", features = ["full"] } +always_send = "0.1.1" +clap = "4.6.0" +env_logger = "0.11" +tokio = { version = "1.50.0", features = ["full"] } native-tls = "0.2" +pin-project = "1.1.11" + +# Bearer authentication, used in examples +jsonwebtoken = {version = "10.3.0", features = ["rust_crypto"]} [target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies] -tokio-openssl = "0.6" openssl = "0.10" +tokio-openssl = "0.6" [[example]] -name = "client" +name = "no-example-v3-client" +path = "examples/client/main.rs" required-features = ["client"] [[example]] -name = "server" +name = "no-example-v3-server" +path = "examples/server/main.rs" required-features = ["server"] + +[[bin]] +name = "no-example-v3" +path = "bin/cli.rs" +required-features = ["client", "cli"] diff --git a/samples/server/petstore/rust-server/output/no-example-v3/README.md b/samples/server/petstore/rust-server/output/no-example-v3/README.md index e918de2d98e7..4c24d1aa1168 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/README.md +++ b/samples/server/petstore/rust-server/output/no-example-v3/README.md @@ -14,7 +14,7 @@ To see how to make this your own, look here: [README]((https://openapi-generator.tech)) - API version: 0.0.1 -- Generator version: 8.0.0-SNAPSHOT +- Generator version: 7.22.0-SNAPSHOT @@ -23,6 +23,7 @@ This autogenerated project defines an API crate `no-example-v3` which contains: * Data types representing the underlying data model. * A `Client` type which implements `Api` and issues HTTP requests for each operation. * A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. +* A CLI tool to drive basic API operations from the command line. It also contains an example server and client which make use of `no-example-v3`: @@ -34,27 +35,51 @@ It also contains an example server and client which make use of `no-example-v3`: arguments on the command line. You can use the example server and client as a basis for your own code. -See below for [more detail on implementing a server](#writing-a-server). +See below for [more detail on the examples](#using-the-generated-library). + +## CLI + +Run the included CLI tool with: + +``` +cargo run --bin cli --features=cli +``` + +To pass in arguments, put them after `--`, for example: + +``` +cargo run --bin cli --features=cli -- --help +``` + +See the help text for available options. + +To build a standalone tool, use: + +``` +cargo build --bin cli --features=cli --release +``` + +You'll find the binary at `target/release/cli`. ## Examples Run examples with: ``` -cargo run --example +cargo run --example no-example-v3- ``` To pass in arguments to the examples, put them after `--`, for example: ``` -cargo run --example client -- --help +cargo run --example no-example-v3-client -- --help ``` ### Running the example server To run the server, follow these simple steps: ``` -cargo run --example server +cargo run --example no-example-v3-server ``` ### Running the example client @@ -67,7 +92,7 @@ To run a client, follow one of the following simple steps: The examples can be run in HTTPS mode by passing in the flag `--https`, for example: ``` -cargo run --example server -- --https +cargo run --example no-example-v3-server -- --https ``` This will use the keys/certificates from the examples directory. Note that the @@ -83,8 +108,36 @@ The generated library has a few optional features that can be activated through * `client` * This defaults to enabled and creates the basic skeleton of a client implementation based on hyper * The constructed client implements the API trait by making remote API call. +* `client-tls` + * This default to enabled and provides HTTPS support with automatic TLS backend selection: + - macOS/Windows/iOS: native-tls + hyper-tls + - Linux/Unix/others: OpenSSL + hyper-openssl * `conversions` * This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types. +* `cli` + * This defaults to disabled and is required for building the included CLI tool. +* `validate` + * This defaults to disabled and allows JSON Schema validation of received data using `MakeService::set_validation` or `Service::set_validation`. + * Note, enabling validation will have a performance penalty, especially if the API heavily uses regex based checks. + +### HTTPS/TLS Support + +HTTPS support is included by default. To disable it (for example, to reduce dependencies), you can: + +```toml +[dependencies] +no-example-v3 = { version = "0.0.1", default-features = false, features = ["client", "server"] } +``` + +**For server with callbacks that need HTTPS:** +```toml +[dependencies] +no-example-v3 = { version = "0.0.1", features = ["server", "client-tls"] } +``` + +The TLS backend is automatically selected based on your target platform: +- **macOS, Windows, iOS**: Uses `native-tls` (system TLS libraries) +- **Linux, Unix, other platforms**: Uses `openssl` See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`. diff --git a/samples/server/petstore/rust-server/output/no-example-v3/api/openapi.yaml b/samples/server/petstore/rust-server/output/no-example-v3/api/openapi.yaml index ff77d0c73295..c031c1bb6a16 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/api/openapi.yaml +++ b/samples/server/petstore/rust-server/output/no-example-v3/api/openapi.yaml @@ -11,7 +11,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/_op_get_request' + $ref: "#/components/schemas/_op_get_request" required: true responses: "200": diff --git a/samples/server/petstore/rust-server/output/no-example-v3/bin/cli.rs b/samples/server/petstore/rust-server/output/no-example-v3/bin/cli.rs new file mode 100644 index 000000000000..df0d77c500e3 --- /dev/null +++ b/samples/server/petstore/rust-server/output/no-example-v3/bin/cli.rs @@ -0,0 +1,159 @@ +//! CLI tool driving the API client +use anyhow::{anyhow, Context, Result}; +use clap::Parser; +use log::{debug, info}; +// models may be unused if all inputs are primitive types +#[allow(unused_imports)] +use no_example_v3::{ + models, ApiNoContext, Client, ContextWrapperExt, + OpGetResponse, +}; +use simple_logger::SimpleLogger; +use swagger::{AuthData, ContextBuilder, EmptyContext, Push, XSpanIdString}; + +type ClientContext = swagger::make_context_ty!( + ContextBuilder, + EmptyContext, + Option, + XSpanIdString +); + +#[derive(Parser, Debug)] +#[clap( + name = "Regression test for an API which doesn't have any example", + version = "0.0.1", + about = "CLI access to Regression test for an API which doesn't have any example" +)] +struct Cli { + #[clap(subcommand)] + operation: Operation, + + /// Address or hostname of the server hosting this API, including optional port + #[clap(short = 'a', long, default_value = "http://localhost")] + server_address: String, + + /// Path to the client private key if using client-side TLS authentication + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_certificate", "server_certificate"]))] + client_key: Option, + + /// Path to the client's public certificate associated with the private key + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_key", "server_certificate"]))] + client_certificate: Option, + + /// Path to CA certificate used to authenticate the server + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long)] + server_certificate: Option, + + /// If set, write output to file instead of stdout + #[clap(short, long)] + output_file: Option, + + #[command(flatten)] + verbosity: clap_verbosity_flag::Verbosity, +} + +#[derive(Parser, Debug)] +enum Operation { + OpGet { + #[clap(value_parser = parse_json::)] + op_get_request: models::OpGetRequest, + }, +} + +// On Linux/Unix with OpenSSL (client-tls feature), support certificate pinning and mutual TLS +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + if args.client_certificate.is_some() { + debug!("Using mutual TLS"); + let client = Client::try_new_https_mutual( + &args.server_address, + args.server_certificate.clone().unwrap(), + args.client_key.clone().unwrap(), + args.client_certificate.clone().unwrap(), + ) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else if args.server_certificate.is_some() { + debug!("Using TLS with pinned server certificate"); + let client = + Client::try_new_https_pinned(&args.server_address, args.server_certificate.clone().unwrap()) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else { + debug!("Using client without certificates"); + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) + } +} + +// On macOS/Windows/iOS or without client-tls feature, use simple client (no cert pinning/mutual TLS) +#[cfg(any( + not(feature = "client-tls"), + all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")) +))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + // Client::try_new() automatically detects the URL scheme (http:// or https://) + // and creates the appropriate client. + // Note: Certificate pinning and mutual TLS are only available on Linux/Unix with OpenSSL + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) +} + +#[tokio::main] +async fn main() -> Result<()> { + let args = Cli::parse(); + if let Some(log_level) = args.verbosity.log_level() { + SimpleLogger::new().with_level(log_level.to_level_filter()).init()?; + } + + debug!("Arguments: {:?}", &args); + + let auth_data: Option = None; + + #[allow(trivial_casts)] + let context = swagger::make_context!( + ContextBuilder, + EmptyContext, + auth_data, + XSpanIdString::default() + ); + + let client = create_client(&args, context)?; + + let result = match args.operation { + Operation::OpGet { + op_get_request, + } => { + info!("Performing a OpGet request"); + + let result = client.op_get( + op_get_request, + ).await?; + debug!("Result: {:?}", result); + + match result { + OpGetResponse::OK + => "OK\n".to_string() + , + } + } + }; + + if let Some(output_file) = args.output_file { + std::fs::write(output_file, result)? + } else { + println!("{}", result); + } + Ok(()) +} + +// May be unused if all inputs are primitive types +#[allow(dead_code)] +fn parse_json(json_string: &str) -> Result { + serde_json::from_str(json_string).map_err(|err| anyhow!("Error parsing input: {}", err)) +} diff --git a/samples/server/petstore/rust-server/output/no-example-v3/examples/client/main.rs b/samples/server/petstore/rust-server/output/no-example-v3/examples/client/main.rs index 0d53eba568b5..abdecc1c0016 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/examples/client/main.rs +++ b/samples/server/petstore/rust-server/output/no-example-v3/examples/client/main.rs @@ -7,7 +7,7 @@ use futures::{future, Stream, stream}; use no_example_v3::{Api, ApiNoContext, Claims, Client, ContextWrapperExt, models, OpGetResponse, }; -use clap::{App, Arg}; +use clap::{Command, Arg}; // NOTE: Set environment variable RUST_LOG to the name of the executable (or "cargo run") to activate console logging for all loglevels. // See https://docs.rs/env_logger/latest/env_logger/ for more details @@ -30,24 +30,22 @@ use client_auth::build_token; fn main() { env_logger::init(); - let matches = App::new("client") - .arg(Arg::with_name("operation") + let matches = Command::new("client") + .arg(Arg::new("operation") .help("Sets the operation to run") - .possible_values(&[ - ]) + .value_parser(Vec::<&str>::from([ + ])) .required(true) .index(1)) - .arg(Arg::with_name("https") + .arg(Arg::new("https") .long("https") .help("Whether to use HTTPS or not")) - .arg(Arg::with_name("host") + .arg(Arg::new("host") .long("host") - .takes_value(true) .default_value("localhost") .help("Hostname to contact")) - .arg(Arg::with_name("port") + .arg(Arg::new("port") .long("port") - .takes_value(true) .default_value("8080") .help("Port to contact")) .get_matches(); @@ -56,53 +54,68 @@ fn main() { // In a real (production) system this Bearer token should be obtained via an external Identity/Authentication-server // Ensure that you set the correct algorithm and encodingkey that matches what is used on the server side. // See https://github.com/Keats/jsonwebtoken for more information - let auth_token = build_token( Claims { - sub: "tester@acme.com".to_owned(), + sub: "tester@acme.com".to_owned(), company: "ACME".to_owned(), iss: "my_identity_provider".to_owned(), // added a very long expiry time aud: "org.acme.Resource_Server".to_string(), exp: 10000000000, // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ - ].join(", ") - }, + scopes: + "".to_owned() + }, b"secret").unwrap(); let auth_data = if !auth_token.is_empty() { - Some(AuthData::Bearer(swagger::auth::Bearer { token: auth_token})) + Some(AuthData::Bearer(auth_token)) } else { // No Bearer-token available, so return None None }; - let is_https = matches.is_present("https"); + let is_https = matches.contains_id("https"); let base_url = format!("{}://{}:{}", if is_https { "https" } else { "http" }, - matches.value_of("host").unwrap(), - matches.value_of("port").unwrap()); + matches.get_one::("host").unwrap(), + matches.get_one::("port").unwrap()); let context: ClientContext = swagger::make_context!(ContextBuilder, EmptyContext, auth_data, XSpanIdString::default()); - let mut client : Box> = if matches.is_present("https") { - // Using Simple HTTPS - let client = Box::new(Client::try_new_https(&base_url) - .expect("Failed to create HTTPS client")); - Box::new(client.with_context(context)) - } else { - // Using HTTP - let client = Box::new(Client::try_new_http( - &base_url) - .expect("Failed to create HTTP client")); - Box::new(client.with_context(context)) + let mut client : Box> = { + #[cfg(feature = "client-tls")] + { + if is_https { + // Using HTTPS with native-tls + let client = Box::new(Client::try_new_https(&base_url) + .expect("Failed to create HTTPS client")); + Box::new(client.with_context(context)) + } else { + // Using HTTP + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } + } + + #[cfg(not(feature = "client-tls"))] + { + if is_https { + panic!("HTTPS requested but TLS support not enabled. \ + Enable the 'client-tls' feature to use HTTPS."); + } + // Using HTTP only + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } }; let mut rt = tokio::runtime::Runtime::new().unwrap(); - match matches.value_of("operation") { + match matches.get_one::("operation").map(String::as_str) { /* Disabled because there's no example. Some("OpGet") => { let result = rt.block_on(client.op_get( diff --git a/samples/server/petstore/rust-server/output/no-example-v3/examples/server/main.rs b/samples/server/petstore/rust-server/output/no-example-v3/examples/server/main.rs index ae01015501e5..d9dcb53b00cd 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/examples/server/main.rs +++ b/samples/server/petstore/rust-server/output/no-example-v3/examples/server/main.rs @@ -3,26 +3,26 @@ #![allow(missing_docs)] - -use clap::{App, Arg}; +use clap::{Arg, Command}; mod server; mod server_auth; - /// Create custom server, wire it to the autogenerated router, /// and pass it to the web server. #[tokio::main] async fn main() { env_logger::init(); - let matches = App::new("server") - .arg(Arg::with_name("https") - .long("https") - .help("Whether to use HTTPS or not")) + let matches = Command::new("server") + .arg( + Arg::new("https") + .long("https") + .help("Whether to use HTTPS or not"), + ) .get_matches(); let addr = "127.0.0.1:8080"; - server::create(addr, matches.is_present("https")).await; + server::create(addr, matches.contains_id("https")).await; } diff --git a/samples/server/petstore/rust-server/output/no-example-v3/examples/server/server.rs b/samples/server/petstore/rust-server/output/no-example-v3/examples/server/server.rs index 64eb831abcad..7887a2ee8c52 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/examples/server/server.rs +++ b/samples/server/petstore/rust-server/output/no-example-v3/examples/server/server.rs @@ -4,8 +4,9 @@ use async_trait::async_trait; use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt}; -use hyper::server::conn::Http; -use hyper::service::Service; +use hyper::server::conn::http1; +use hyper_util::rt::TokioIo; +use hyper::service::{service_fn, Service}; use log::info; use std::future::Future; use std::marker::PhantomData; @@ -24,15 +25,13 @@ use no_example_v3::models; /// Builds an SSL implementation for Simple HTTPS from some hard-coded file names pub async fn create(addr: &str, https: bool) { - let addr = addr.parse().expect("Failed to parse bind address"); + let addr: SocketAddr = addr.parse().expect("Failed to parse bind address"); + let listener = TcpListener::bind(&addr).await.unwrap(); let server = Server::new(); let service = MakeService::new(server); - - // This pushes a fourth layer of the middleware-stack even though Swagger assumes only three levels. - // This fourth layer creates an accept-all policy, hower the example-code already acchieves the same via a Bearer-token with full permissions, so next line is not needed (anymore). - // let service = MakeAllowAllAuthenticator::new(service, "cosmo"); + let service = MakeAllowAllAuthenticator::new(service, "cosmo"); #[allow(unused_mut)] let mut service = @@ -56,21 +55,19 @@ pub async fn create(addr: &str, https: bool) { ssl.check_private_key().expect("Failed to check private key"); let tls_acceptor = ssl.build(); - let tcp_listener = TcpListener::bind(&addr).await.unwrap(); info!("Starting a server (with https)"); loop { - if let Ok((tcp, _)) = tcp_listener.accept().await { + if let Ok((tcp, addr)) = listener.accept().await { let ssl = Ssl::new(tls_acceptor.context()).unwrap(); - let addr = tcp.peer_addr().expect("Unable to get remote address"); let service = service.call(addr); tokio::spawn(async move { let tls = tokio_openssl::SslStream::new(ssl, tcp).map_err(|_| ())?; let service = service.await.map_err(|_| ())?; - Http::new() - .serve_connection(tls, service) + http1::Builder::new() + .serve_connection(TokioIo::new(tls), service) .await .map_err(|_| ()) }); @@ -79,12 +76,40 @@ pub async fn create(addr: &str, https: bool) { } } else { info!("Starting a server (over http, so no TLS)"); - // Using HTTP - hyper::server::Server::bind(&addr).serve(service).await.unwrap() + println!("Listening on http://{}", addr); + + loop { + // When an incoming TCP connection is received grab a TCP stream for + // client<->server communication. + // + // Note, this is a .await point, this loop will loop forever but is not a busy loop. The + // .await point allows the Tokio runtime to pull the task off of the thread until the task + // has work to do. In this case, a connection arrives on the port we are listening on and + // the task is woken up, at which point the task is then put back on a thread, and is + // driven forward by the runtime, eventually yielding a TCP stream. + let (tcp_stream, addr) = listener.accept().await.expect("Failed to accept connection"); + + let service = service.call(addr).await.unwrap(); + let io = TokioIo::new(tcp_stream); + // Spin up a new task in Tokio so we can continue to listen for new TCP connection on the + // current task without waiting for the processing of the HTTP1 connection we just received + // to finish + tokio::task::spawn(async move { + // Handle the connection from the client using HTTP1 and pass any + // HTTP requests received on that connection to the `hello` function + let result = http1::Builder::new() + .serve_connection(io, service) + .await; + if let Err(err) = result + { + println!("Error serving connection: {err:?}"); + } + }); + } } } -#[derive(Copy, Clone)] +#[derive(Copy)] pub struct Server { marker: PhantomData, } @@ -95,6 +120,14 @@ impl Server { } } +impl Clone for Server { + fn clone(&self) -> Self { + Self { + marker: PhantomData, + } + } +} + use jsonwebtoken::{decode, encode, errors::Error as JwtError, Algorithm, DecodingKey, EncodingKey, Header, TokenData, Validation}; use serde::{Deserialize, Serialize}; diff --git a/samples/server/petstore/rust-server/output/no-example-v3/examples/server/server_auth.rs b/samples/server/petstore/rust-server/output/no-example-v3/examples/server/server_auth.rs index d08ae850a016..b5b26c5c51e4 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/examples/server/server_auth.rs +++ b/samples/server/petstore/rust-server/output/no-example-v3/examples/server/server_auth.rs @@ -1,8 +1,8 @@ use swagger::{ ApiError, - auth::{Basic, Bearer}, - Has, + Has, XSpanIdString}; +use headers::authorization::{Basic, Bearer}; use no_example_v3::{AuthenticationApi, Claims}; use crate::server::Server; use jsonwebtoken::{decode, errors as JwtError, decode_header, DecodingKey, TokenData, Validation}; @@ -15,24 +15,24 @@ use log::{error, debug}; /// Get a dummy claim with full permissions (all scopes) for testing purposes fn full_permission_claim() -> Claims { - Claims { - sub: "tester@acme.com".to_owned(), - company: "ACME".to_owned(), - iss: "mini-bank-IDP".to_owned(), - aud: "org.acme.Resource_Server".to_string(), - // added a very long expiry time - exp: 10000000000, - // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ - ].join(", ") - } + // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. + Claims { + sub: "tester@acme.com".to_owned(), + company: "ACME".to_owned(), + iss: "mini-bank-IDP".to_owned(), + aud: "org.acme.Resource_Server".to_string(), + // added a very long expiry time + exp: 10000000000, + scopes: + "".to_owned() + } } -/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. +/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. fn extract_token_data(token: &str, key: &[u8]) -> Result, JwtError::Error> { - + // Ensure that you set the correct algorithm and correct key. // See https://github.com/Keats/jsonwebtoken for more information. let header = decode_header(token)?; @@ -63,8 +63,8 @@ fn build_authorization(claims: Claims) -> Authorization { let scopes = swagger::auth::Scopes::Some(scopes); Authorization{ - subject: claims.sub, - scopes, + subject: claims.sub, + scopes, issuer: Some(claims.iss)} } @@ -87,7 +87,7 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn bearer_authorization(&self, bearer: &Bearer) -> Result { debug!("\tAuthorizationApi: Received Bearer-token, {bearer:#?}"); - match extract_token_data(&bearer.token, b"secret") { + match extract_token_data(&bearer.token(), b"secret") { Ok(auth_data) => { debug!("\tUnpack auth_data as: {auth_data:#?}"); let authorization = build_authorization(auth_data.claims); @@ -105,23 +105,22 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn apikey_authorization(&self, api_key: &str) -> Result { debug!("\tAuthorizationApi: Received api-key, {api_key:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } - + /// Implementation of the method to map a basic authentication (username and password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result { debug!("\tAuthorizationApi: Received Basic-token, {basic:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } -} - +} diff --git a/samples/server/petstore/rust-server/output/no-example-v3/src/auth.rs b/samples/server/petstore/rust-server/output/no-example-v3/src/auth.rs index cbaba3dca7c6..a6a39f79450f 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/src/auth.rs +++ b/samples/server/petstore/rust-server/output/no-example-v3/src/auth.rs @@ -1,8 +1,7 @@ use std::collections::BTreeSet; -use crate::server::Authorization; use serde::{Deserialize, Serialize}; -use swagger::{ApiError, auth::{Basic, Bearer}}; - +use swagger::{ApiError, auth::Authorization}; +use headers::authorization::{Basic, Bearer}; #[derive(Debug, Serialize, Deserialize)] pub struct Claims { pub sub: String, @@ -24,7 +23,7 @@ pub trait AuthenticationApi { /// Method should be implemented (see example-code) to map Basic (Username:password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result; -} +} // Implement it for AllowAllAuthenticator (dummy is needed, but should not used as we have Bearer authorization) use swagger::auth::{AllowAllAuthenticator, RcBound, Scopes}; @@ -34,7 +33,7 @@ fn dummy_authorization() -> Authorization { // However, if you want to use it anyway this can not be unimplemented, so dummy implementation added. // unimplemented!() Authorization{ - subject: "Dummmy".to_owned(), + subject: "Dummy".to_owned(), scopes: Scopes::Some(BTreeSet::new()), // create an empty scope, as this should not be used issuer: None } diff --git a/samples/server/petstore/rust-server/output/no-example-v3/src/client/mod.rs b/samples/server/petstore/rust-server/output/no-example-v3/src/client/mod.rs index b8bcf7763395..de9fcd4e3f48 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/src/client/mod.rs +++ b/samples/server/petstore/rust-server/output/no-example-v3/src/client/mod.rs @@ -1,10 +1,12 @@ use async_trait::async_trait; +use bytes::Bytes; use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt}; +use http_body_util::{combinators::BoxBody, Full}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; -use hyper::{Body, Request, Response, service::Service, Uri}; +use hyper::{body::{Body, Incoming}, Request, Response, service::Service, Uri}; use percent_encoding::{utf8_percent_encode, AsciiSet}; use std::borrow::Cow; -use std::convert::TryInto; +use std::convert::{TryInto, Infallible}; use std::io::{ErrorKind, Read}; use std::error::Error; use std::future::Future; @@ -18,6 +20,7 @@ use std::string::ToString; use std::task::{Context, Poll}; use swagger::{ApiError, AuthData, BodyExt, Connector, DropContextService, Has, XSpanIdString}; use url::form_urlencoded; +use tower_service::Service as _; use crate::models; @@ -54,15 +57,14 @@ fn into_base_path(input: impl TryInto, } let host = uri.host().ok_or(ClientInitError::MissingHost)?; - let port = uri.port_u16().map(|x| format!(":{}", x)).unwrap_or_default(); - Ok(format!("{}://{}{}{}", scheme, host, port, uri.path().trim_end_matches('/'))) + let port = uri.port_u16().map(|x| format!(":{x}")).unwrap_or_default(); + Ok(format!("{scheme}://{host}{port}{}", uri.path().trim_end_matches('/'))) } /// A client that implements the API by making HTTP calls out to a server. pub struct Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -79,8 +81,7 @@ pub struct Client where impl fmt::Debug for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -92,8 +93,7 @@ impl fmt::Debug for Client where impl Clone for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -107,8 +107,19 @@ impl Clone for Client where } } -impl Client, C>, C> where - Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static, +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + Connector, + BoxBody + > + >, + C + >, + C +> where + Connector: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static, C: Clone + Send + Sync + 'static, { /// Create a client with a custom implementation of hyper::client::Connect. @@ -122,7 +133,7 @@ impl Client" /// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")` /// * `connector` - Implementation of `hyper::client::Connect` to use for the client pub fn try_new_with_connector( @@ -131,8 +142,8 @@ impl Client Result { - let client_service = hyper::client::Client::builder().build(connector); - let client_service = DropContextService::new(client_service); + let client_service = hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector); + let client_service = DropContextService::new(hyper_util::service::TowerToHyperService::new(client_service)); Ok(Self { client_service, @@ -142,28 +153,29 @@ impl Client; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HyperHttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + #[derive(Debug, Clone)] pub enum HyperClient { - Http(hyper::client::Client), - Https(hyper::client::Client), + Http(hyper_util::client::legacy::Client>), + #[cfg(feature = "client-tls")] + Https(hyper_util::client::legacy::Client>), } -impl Service> for HyperClient { - type Response = Response; - type Error = hyper::Error; - type Future = hyper::client::ResponseFuture; +impl Service>> for HyperClient { + type Response = Response; + type Error = hyper_util::client::legacy::Error; + type Future = hyper_util::client::legacy::ResponseFuture; - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { + fn call(&self, req: Request>) -> Self::Future { match self { - HyperClient::Http(client) => client.poll_ready(cx), - HyperClient::Https(client) => client.poll_ready(cx), - } - } - - fn call(&mut self, req: Request) -> Self::Future { - match self { - HyperClient::Http(client) => client.call(req), - HyperClient::Https(client) => client.call(req) + HyperClient::Http(client) => client.request(req), + #[cfg(feature = "client-tls")] + HyperClient::Https(client) => client.request(req), } } } @@ -174,7 +186,7 @@ impl Client, C> where /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new( base_path: &str, ) -> Result { @@ -187,13 +199,19 @@ impl Client, C> where let client_service = match scheme.as_str() { "http" => { - HyperClient::Http(hyper::client::Client::builder().build(connector.build())) + HyperClient::Http(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector.build())) + }, + #[cfg(feature = "client-tls")] + "https" => { + let https_connector = connector + .https() + .build() + .map_err(ClientInitError::SslError)?; + HyperClient::Https(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(https_connector)) }, + #[cfg(not(feature = "client-tls"))] "https" => { - let connector = connector.https() - .build() - .map_err(ClientInitError::SslError)?; - HyperClient::Https(hyper::client::Client::builder().build(connector)) + return Err(ClientInitError::TlsNotEnabled); }, _ => { return Err(ClientInitError::InvalidScheme); @@ -210,13 +228,24 @@ impl Client, C> where } } -impl Client, C>, C> where +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + hyper_util::client::legacy::connect::HttpConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new_http( base_path: &str, ) -> Result { @@ -226,19 +255,32 @@ impl Client; - -#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] -type HttpsConnector = hyper_openssl::HttpsConnector; - -impl Client, C>, C> where +#[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] +type HttpsConnector = hyper_tls::HttpsConnector; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + +#[cfg(feature = "client-tls")] +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + HttpsConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { - /// Create a client with a TLS connection to the server + /// Create a client with a TLS connection to the server. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] pub fn try_new_https(base_path: &str) -> Result { let https_connector = Connector::builder() @@ -248,10 +290,24 @@ impl Client, C Self::try_new_with_connector(base_path, Some("https"), https_connector) } - /// Create a client with a TLS connection to the server using a pinned certificate + /// Create a client with a TLS connection to the server using OpenSSL via swagger. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] + pub fn try_new_https(base_path: &str) -> Result + { + let https_connector = Connector::builder() + .https() + .build() + .map_err(ClientInitError::SslError)?; + Self::try_new_with_connector(base_path, Some("https"), https_connector) + } + + /// Create a client with a TLS connection to the server using a pinned certificate. + /// + /// # Arguments + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn try_new_https_pinned( @@ -272,7 +328,7 @@ impl Client, C /// Create a client with a mutually authenticated TLS connection to the server. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server /// * `client_key` - Path to the client private key /// * `client_certificate` - Path to the client's public certificate associated with the private key @@ -300,8 +356,7 @@ impl Client, C impl Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -335,12 +390,15 @@ pub enum ClientInitError { /// Missing Hostname MissingHost, + /// HTTPS requested but TLS features not enabled + TlsNotEnabled, + /// SSL Connection Error - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + #[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] SslError(native_tls::Error), /// SSL Connection Error - #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] SslError(openssl::error::ErrorStack), } @@ -363,29 +421,32 @@ impl Error for ClientInitError { } } +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + #[async_trait] -impl Api for Client where +impl Api for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C), + Response=Response> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Has + Clone + Send + Sync + 'static, + B: hyper::body::Body + Send + 'static + Unpin, + B::Data: Send, + B::Error: Into>, { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - match self.client_service.clone().poll_ready(cx) { - Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())), - Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)), - Poll::Pending => Poll::Pending, - } - } + #[allow(clippy::vec_init_then_push)] async fn op_get( &self, param_op_get_request: models::OpGetRequest, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op", self.base_path @@ -403,36 +464,33 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body // Body parameter let body = serde_json::to_string(¶m_op_get_request).expect("impossible to fail to serialize"); - - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -442,18 +500,16 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } diff --git a/samples/server/petstore/rust-server/output/no-example-v3/src/context.rs b/samples/server/petstore/rust-server/output/no-example-v3/src/context.rs index ee8e118587bb..45180a543112 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/src/context.rs +++ b/samples/server/petstore/rust-server/output/no-example-v3/src/context.rs @@ -6,9 +6,9 @@ use std::default::Default; use std::io; use std::marker::PhantomData; use std::task::{Poll, Context}; -use swagger::auth::{AuthData, Authorization, Bearer, Scopes}; +use swagger::auth::{AuthData, Authorization, Scopes}; use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString}; -use crate::{Api, AuthenticationApi}; +use crate::Api; use log::error; pub struct MakeAddContext { @@ -16,11 +16,11 @@ pub struct MakeAddContext { marker: PhantomData, } -impl MakeAddContext +impl MakeAddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, + C: Send + 'static, { pub fn new(inner: T) -> MakeAddContext { MakeAddContext { @@ -30,27 +30,34 @@ where } } +impl Clone for MakeAddContext +where + T: Clone, +{ + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + // Make a service that adds context. -impl Service for +impl Service for MakeAddContext where Target: Send, A: Default + Push + Send, B: Push, Result = C>, - C: Push, Result = D>, - D: Send + 'static, + C: Send + 'static, T: Service + Send, T::Future: Send + 'static { type Error = T::Error; - type Response = AddContext; + type Response = AddContext; type Future = BoxFuture<'static, Result>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, target: Target) -> Self::Future { + fn call(&self, target: Target) -> Self::Future { let service = self.inner.call(target); Box::pin(async move { @@ -60,21 +67,17 @@ where } /// Middleware to add context data from the request -pub struct AddContext -where - A: Default + Push, - B: Push, Result = C>, - C: Push, Result = D> +#[derive(Debug, Clone)] +pub struct AddContext { inner: T, marker: PhantomData, } -impl AddContext +impl AddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, { pub fn new(inner: T) -> Self { AddContext { @@ -84,30 +87,23 @@ where } } -impl Service> for AddContext +impl Service> for AddContext where A: Default + Push, B: Push, Result=C>, - C: Push, Result=D>, - D: Send + 'static, - T: Service<(Request, D)> + AuthenticationApi + C: Send + 'static, + T: Service<(Request, C)> { type Error = T::Error; type Future = T::Future; type Response = T::Response; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - - fn call(&mut self, request: Request) -> Self::Future { + fn call(&self, request: Request) -> Self::Future { let context = A::default().push(XSpanIdString::get_or_generate(&request)); let headers = request.headers(); let context = context.push(None::); - let context = context.push(None::); self.inner.call((request, context)) } diff --git a/samples/server/petstore/rust-server/output/no-example-v3/src/header.rs b/samples/server/petstore/rust-server/output/no-example-v3/src/header.rs index 5bc6ebe929b9..823d2779b31f 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/src/header.rs +++ b/samples/server/petstore/rust-server/output/no-example-v3/src/header.rs @@ -31,11 +31,9 @@ macro_rules! ihv_generate { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse::<$t>() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse {} as a string: {}", - stringify!($t), e)), + Err(e) => Err(format!("Unable to parse {} as a string: {e}", stringify!($t))), }, - Err(e) => Err(format!("Unable to parse header {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header {hdr_value:?} as a string - {e}")), } } } @@ -76,8 +74,7 @@ impl TryFrom for IntoHeaderValue> { y => Some(y.to_string()), }) .collect())), - Err(e) => Err(format!("Unable to parse header: {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header: {hdr_value:?} as a string - {e}")), } } } @@ -88,8 +85,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(&hdr_value.0.join(", ")) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} into a header - {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} into a header - {e}")) } } } @@ -102,8 +98,7 @@ impl TryFrom for IntoHeaderValue { fn try_from(hdr_value: HeaderValue) -> Result { match hdr_value.to_str() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())), - Err(e) => Err(format!("Unable to convert header {:?} to {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to {e}")), } } } @@ -114,8 +109,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")) } } } @@ -128,11 +122,9 @@ impl TryFrom for IntoHeaderValue { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse bool from {} - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse bool from {hdr_value} - {e}")), }, - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")), } } } @@ -143,8 +135,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0.to_string()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert: {:?} into a header: {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert: {hdr_value:?} into a header: {e}")) } } } @@ -158,11 +149,9 @@ impl TryFrom for IntoHeaderValue> { match hdr_value.to_str() { Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) { Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))), - Err(e) => Err(format!("Unable to parse: {} as date - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse: {hdr_value} as date - {e}")), }, - Err(e) => Err(format!("Unable to convert header {:?} to string {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to string {e}")), } } } @@ -173,8 +162,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} to a header: {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} to a header: {e}")), } } } diff --git a/samples/server/petstore/rust-server/output/no-example-v3/src/lib.rs b/samples/server/petstore/rust-server/output/no-example-v3/src/lib.rs index 009a31837355..dd3536e86305 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/src/lib.rs +++ b/samples/server/petstore/rust-server/output/no-example-v3/src/lib.rs @@ -3,14 +3,15 @@ use async_trait::async_trait; use futures::Stream; +#[cfg(feature = "mock")] +use mockall::automock; use std::error::Error; use std::collections::BTreeSet; use std::task::{Poll, Context}; -use swagger::{ApiError, ContextWrapper}; +use swagger::{ApiError, ContextWrapper, auth::Authorization}; use serde::{Serialize, Deserialize}; -use crate::server::Authorization; - +#[cfg(any(feature = "client", feature = "server"))] type ServiceError = Box; pub const BASE_PATH: &str = ""; @@ -27,13 +28,10 @@ pub enum OpGetResponse { } /// API +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait Api { - fn poll_ready(&self, _cx: &mut Context) -> Poll>> { - Poll::Ready(Ok(())) - } - async fn op_get( &self, op_get_request: models::OpGetRequest, @@ -42,11 +40,14 @@ pub trait Api { } /// API where `Context` isn't passed on every API call +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait ApiNoContext { - - fn poll_ready(&self, _cx: &mut Context) -> Poll>>; + // The std::task::Context struct houses a reference to std::task::Waker with the lifetime <'a>. + // Adding an anonymous lifetime `'a` to allow mockall to create a mock object with the right lifetimes. + // This is needed because the compiler is unable to determine the lifetimes on F's trait bound + // where F is the closure created by mockall. We use higher-rank trait bounds here to get around this. fn context(&self) -> &C; @@ -72,10 +73,6 @@ impl + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt for T #[async_trait] impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for ContextWrapper { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - self.api().poll_ready(cx) - } - fn context(&self) -> &C { ContextWrapper::context(self) } diff --git a/samples/server/petstore/rust-server/output/no-example-v3/src/models.rs b/samples/server/petstore/rust-server/output/no-example-v3/src/models.rs index 07546b7a11f2..f2f7c683270e 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/src/models.rs +++ b/samples/server/petstore/rust-server/output/no-example-v3/src/models.rs @@ -1,19 +1,42 @@ #![allow(unused_qualifications)] - +#[cfg(not(feature = "validate"))] use validator::Validate; use crate::models; #[cfg(any(feature = "client", feature = "server"))] use crate::header; +#[cfg(feature = "validate")] +use serde_valid::Validate; -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct OpGetRequest { #[serde(rename = "property")] + pub property: String, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for OpGetRequest { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for OpGetRequest { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl OpGetRequest { #[allow(clippy::new_without_default)] @@ -25,23 +48,21 @@ impl OpGetRequest { } /// Converts the OpGetRequest value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for OpGetRequest { - fn to_string(&self) -> String { +impl std::fmt::Display for OpGetRequest { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - Some("property".to_string()), Some(self.property.to_string()), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a OpGetRequest value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for OpGetRequest { type Err = String; @@ -97,8 +118,7 @@ impl std::convert::TryFrom> for hyper::hea match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for OpGetRequest - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for OpGetRequest - value: {hdr_value} is invalid {e}")) } } } @@ -113,14 +133,54 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into OpGetRequest - {}", - value, err)) + format!("Unable to convert header value '{value}' into OpGetRequest - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into OpGetRequest - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} diff --git a/samples/server/petstore/rust-server/output/no-example-v3/src/server/mod.rs b/samples/server/petstore/rust-server/output/no-example-v3/src/server/mod.rs index d00a957c0531..ddac5c1d1be3 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/src/server/mod.rs +++ b/samples/server/petstore/rust-server/output/no-example-v3/src/server/mod.rs @@ -1,10 +1,14 @@ +use bytes::Bytes; use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt}; -use hyper::{Request, Response, StatusCode, Body, HeaderMap}; +use http_body_util::{combinators::BoxBody, Full}; +use hyper::{body::{Body, Incoming}, HeaderMap, Request, Response, StatusCode}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; use log::warn; +#[cfg(feature = "validate")] +use serde_valid::Validate; #[allow(unused_imports)] use std::convert::{TryFrom, TryInto}; -use std::error::Error; +use std::{convert::Infallible, error::Error}; use std::future::Future; use std::marker::PhantomData; use std::task::{Context, Poll}; @@ -18,7 +22,7 @@ use crate::{models, header, AuthenticationApi}; pub use crate::context; -type ServiceFuture = BoxFuture<'static, Result, crate::ServiceError>>; +type ServiceFuture = BoxFuture<'static, Result>, crate::ServiceError>>; use crate::{Api, OpGetResponse @@ -39,28 +43,52 @@ mod paths { } -pub struct MakeService where +pub struct MakeService +where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { api_impl: T, marker: PhantomData, + validation: bool } -impl MakeService where +impl MakeService +where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { pub fn new(api_impl: T) -> Self { MakeService { api_impl, - marker: PhantomData + marker: PhantomData, + validation: false } } + + // Turn on/off validation for the service being made. + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation; + } } +impl Clone for MakeService +where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static +{ + fn clone(&self) -> Self { + Self { + api_impl: self.api_impl.clone(), + marker: PhantomData, + validation: self.validation + } + } +} -impl hyper::service::Service for MakeService where +impl hyper::service::Service for MakeService +where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { @@ -68,43 +96,72 @@ impl hyper::service::Service for MakeService where type Error = crate::ServiceError; type Future = future::Ready>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } + fn call(&self, target: Target) -> Self::Future { + let service = Service::new(self.api_impl.clone(), self.validation); - fn call(&mut self, target: Target) -> Self::Future { - future::ok(Service::new( - self.api_impl.clone(), - )) + future::ok(service) } } -fn method_not_allowed() -> Result, crate::ServiceError> { +fn method_not_allowed() -> Result>, crate::ServiceError> { Ok( Response::builder().status(StatusCode::METHOD_NOT_ALLOWED) - .body(Body::empty()) + .body(BoxBody::new(http_body_util::Empty::new())) .expect("Unable to create Method Not Allowed response") ) } +#[allow(unused_macros)] +#[cfg(not(feature = "validate"))] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => (); +} + +#[allow(unused_macros)] +#[cfg(feature = "validate")] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => { + let $parameter = if $validation { + match $parameter.validate() { + Ok(()) => $parameter, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .header(CONTENT_TYPE, mime::TEXT_PLAIN.as_ref()) + .body(BoxBody::new(format!("Invalid value in body parameter {}: {}", $base_name, e))) + .expect(&format!("Unable to create Bad Request response for invalid value in body parameter {}", $base_name))), + } + } else { + $parameter + }; + } +} + pub struct Service where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { api_impl: T, marker: PhantomData, + // Enable regex pattern validation of received JSON models + validation: bool, } impl Service where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { - pub fn new(api_impl: T) -> Self { + pub fn new(api_impl: T, validation: bool) -> Self { Service { api_impl, - marker: PhantomData + marker: PhantomData, + validation, } } + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation + } + } impl Clone for Service where @@ -115,54 +172,73 @@ impl Clone for Service where Service { api_impl: self.api_impl.clone(), marker: self.marker, + validation: self.validation, } } } -impl hyper::service::Service<(Request, C)> for Service where +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + +fn body_from_str(s: &str) -> BoxBody { + BoxBody::new(Full::new(Bytes::copy_from_slice(s.as_bytes()))) +} + +impl hyper::service::Service<(Request, C)> for Service where T: Api + Clone + Send + Sync + 'static, - C: Has + Send + Sync + 'static + C: Has + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, { - type Response = Response; + type Response = Response>; type Error = crate::ServiceError; type Future = ServiceFuture; - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - self.api_impl.poll_ready(cx) - } + fn call(&self, req: (Request, C)) -> Self::Future { + async fn run( + mut api_impl: T, + req: (Request, C), + validation: bool, + ) -> Result>, crate::ServiceError> + where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, + { + let (request, context) = req; + let (parts, body) = request.into_parts(); + let (method, uri, headers) = (parts.method, parts.uri, parts.headers); + let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); - fn call(&mut self, req: (Request, C)) -> Self::Future { async fn run(mut api_impl: T, req: (Request, C)) -> Result, crate::ServiceError> where - T: Api + Clone + Send + 'static, - C: Has + Send + Sync + 'static - { - let (request, context) = req; - let (parts, body) = request.into_parts(); - let (method, uri, headers) = (parts.method, parts.uri, parts.headers); - let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); - - match method { + match method { // OpGet - GET /op hyper::Method::GET if path.matched(paths::ID_OP) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_op_get_request: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); + warn!("Ignoring unknown field in body: {path}"); unused_elements.push(path.to_string()); }) { Ok(param_op_get_request) => param_op_get_request, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter OpGetRequest - doesn't match schema: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter OpGetRequest - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter OpGetRequest due to schema")), } + } else { None }; @@ -170,15 +246,18 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_op_get_request) => param_op_get_request, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter OpGetRequest")) + .body(BoxBody::new("Missing required body parameter OpGetRequest".to_string())) .expect("Unable to create Bad Request response for missing body parameter OpGetRequest")), }; + #[cfg(not(feature = "validate"))] + run_validation!(param_op_get_request, "OpGetRequest", validation); + let result = api_impl.op_get( param_op_get_request, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -187,22 +266,22 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { OpGetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -210,17 +289,23 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter OpGetRequest: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter OpGetRequest")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, _ if path.matched(paths::ID_OP) => method_not_allowed(), - _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) - .body(Body::empty()) - .expect("Unable to create Not Found response")) + _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) + .body(BoxBody::new(http_body_util::Empty::new())) + .expect("Unable to create Not Found response")) + } } - } Box::pin(run(self.api_impl.clone(), req)) } + Box::pin(run( + self.api_impl.clone(), + req, + self.validation + )) + } } /// Request parser for `Api`. diff --git a/samples/server/petstore/rust-server/output/no-example-v3/src/server/server_auth.rs b/samples/server/petstore/rust-server/output/no-example-v3/src/server/server_auth.rs index ba78eb2f3f5d..21b1d7babd03 100644 --- a/samples/server/petstore/rust-server/output/no-example-v3/src/server/server_auth.rs +++ b/samples/server/petstore/rust-server/output/no-example-v3/src/server/server_auth.rs @@ -1,11 +1,12 @@ use super::Service; use crate::{Api, AuthenticationApi}; +use headers::authorization::{Basic, Bearer}; use swagger::{ ApiError, - Authorization, - auth::{Basic, Bearer}, - Has, - XSpanIdString}; + Authorization, + Has, + XSpanIdString +}; impl AuthenticationApi for Service where T: Api + Clone + Send + 'static + AuthenticationApi, diff --git a/samples/server/petstore/rust-server/output/openapi-v3/.cargo/config.toml b/samples/server/petstore/rust-server/output/openapi-v3/.cargo/config.toml new file mode 100644 index 000000000000..df91f0f117f3 --- /dev/null +++ b/samples/server/petstore/rust-server/output/openapi-v3/.cargo/config.toml @@ -0,0 +1,19 @@ +[build] +rustflags = [ + "-W", "missing_docs", # detects missing documentation for public members + + "-W", "trivial_casts", # detects trivial casts which could be removed + + "-W", "trivial_numeric_casts", # detects trivial casts of numeric types which could be removed + + # unsafe is used in `TokioIo` bridging code copied from `hyper`. + # "-W", "unsafe_code", # usage of `unsafe` code + + "-W", "unused_qualifications", # detects unnecessarily qualified names + + "-W", "unused_extern_crates", # extern crates that are never used + + "-W", "unused_import_braces", # unnecessary braces around an imported item + + "-D", "warnings", # all warnings should be denied +] diff --git a/samples/server/petstore/rust-server/output/openapi-v3/.openapi-generator/FILES b/samples/server/petstore/rust-server/output/openapi-v3/.openapi-generator/FILES index 7d5a61313944..bc66e332c22e 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/.openapi-generator/FILES +++ b/samples/server/petstore/rust-server/output/openapi-v3/.openapi-generator/FILES @@ -1,20 +1,23 @@ -.cargo/config +.cargo/config.toml .gitignore Cargo.toml README.md api/openapi.yaml +bin/cli.rs docs/AdditionalPropertiesWithList.md docs/AnotherXmlArray.md docs/AnotherXmlInner.md docs/AnotherXmlObject.md docs/AnyOfGet202Response.md docs/AnyOfObject.md +docs/AnyOfObjectAnyOf.md docs/AnyOfProperty.md docs/DuplicateXmlObject.md docs/EnumWithStarObject.md docs/Err.md docs/Error.md docs/Model12345AnyOfObject.md +docs/Model12345AnyOfObjectAnyOf.md docs/MultigetGet201Response.md docs/MyId.md docs/MyIdList.md diff --git a/samples/server/petstore/rust-server/output/openapi-v3/.openapi-generator/VERSION b/samples/server/petstore/rust-server/output/openapi-v3/.openapi-generator/VERSION index f1358e30d8ae..f7962df3e243 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/.openapi-generator/VERSION +++ b/samples/server/petstore/rust-server/output/openapi-v3/.openapi-generator/VERSION @@ -1 +1 @@ -8.0.0-SNAPSHOT +7.22.0-SNAPSHOT diff --git a/samples/server/petstore/rust-server/output/openapi-v3/Cargo.toml b/samples/server/petstore/rust-server/output/openapi-v3/Cargo.toml index 3dd0ee4d5f9b..856cd06b878f 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/Cargo.toml +++ b/samples/server/petstore/rust-server/output/openapi-v3/Cargo.toml @@ -8,80 +8,126 @@ license = "Unlicense" edition = "2018" [features] -default = ["client", "server"] +default = ["client", "server", "client-tls"] client = [ - "serde_ignored", "regex", "percent-encoding", "lazy_static", - "hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url" + "serde_ignored", "percent-encoding", + "hyper", "percent-encoding", "hyper-util/http1", "hyper-util/http2", "url" +] +# TLS support - automatically selects backend based on target OS: +# - macOS/Windows/iOS: native-tls via hyper-tls +# - Other platforms: OpenSSL via hyper-openssl +# Dependencies are in target-specific sections below +client-tls = [ + "client", + "dep:native-tls", + "dep:hyper-tls", + "dep:openssl", + "dep:hyper-openssl", + "swagger/tls" ] server = [ - "native-tls", "hyper-openssl", "hyper-tls", "openssl", - "serde_ignored", "hyper", "regex", "percent-encoding", "url", "lazy_static" + "hyper-util/http1", "hyper-util/http2", + "serde_ignored", "hyper", "percent-encoding", "url", + +] +cli = [ + "anyhow", "clap", "clap-verbosity-flag", "simple_logger", "tokio" ] conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"] -[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] -native-tls = { version = "0.2", optional = true } -hyper-tls = { version = "0.5", optional = true } - -[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] -hyper-openssl = { version = "0.9", optional = true } -openssl = {version = "0.10", optional = true } +mock = ["mockall"] +validate = [ "serde_valid", "swagger/serdevalid"] [dependencies] # Common -async-trait = "0.1.24" +async-trait = "0.1.89" chrono = { version = "0.4", features = ["serde"] } futures = "0.3" -swagger = { version = "6.1", features = ["serdejson", "server", "client", "tls", "tcp"] } -log = "0.4.0" +swagger = { version = "7.0.0", features = ["serdejson", "server", "client"] } +headers = "0.4.1" +log = "0.4.29" + mime = "0.3" +mockall = { version = "0.14", optional = true } +lazy_static = "1.5" +regex = "1.12" + serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -validator = { version = "0.16", features = ["derive"] } +serde_valid = { version = "2.0", optional = true } + +validator = { version = "0.20", features = ["derive"] } # Crates included if required by the API definition -# TODO: this should be updated to point at the official crate once -# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream -serde-xml-rs = {git = "https://github.com/Metaswitch/serde-xml-rs" , branch = "master"} -uuid = {version = "1.3.1", features = ["serde", "v4"]} +serde-xml-rs = "0.8" +uuid = { version = "1.23.0", features = ["serde", "v4"]} # Common between server and client features -hyper = {version = "0.14", features = ["full"], optional = true} -serde_ignored = {version = "0.1.1", optional = true} -url = {version = "2.1", optional = true} +bytes = "1.11" +http-body-util = "0.1.3" +hyper = { version = "1.9.0", features = ["full"], optional = true } +hyper-util = { version = "0.1.20", features = ["service"] } +serde_ignored = { version = "0.1.14", optional = true } +url = { version = "2.5", optional = true } # Client-specific +tower-service = "0.3.3" # Server, and client callback-specific -lazy_static = { version = "1.4", optional = true } -percent-encoding = {version = "2.1.0", optional = true} -regex = {version = "1.3", optional = true} +percent-encoding = { version = "2.3.2", optional = true } + +# CLI-specific +anyhow = { version = "1", optional = true } +clap = { version = "4.6.0", features = ["env"], optional = true } +clap-verbosity-flag = { version = "3.0", optional = true } +simple_logger = { version = "5.2.0", features = ["stderr"], optional = true } +tokio = { version = "1.50.0", features = ["rt-multi-thread", "macros"], optional = true } # Conversion -frunk = { version = "0.3.0", optional = true } -frunk_derives = { version = "0.3.0", optional = true } -frunk_core = { version = "0.3.0", optional = true } -frunk-enum-derive = { version = "0.2.0", optional = true } -frunk-enum-core = { version = "0.2.0", optional = true } +frunk = { version = "0.4.4", optional = true } +frunk_derives = { version = "0.4.4", optional = true } +frunk_core = { version = "0.4.4", optional = true } +frunk-enum-derive = { version = "0.3.0", optional = true } +frunk-enum-core = { version = "0.3.0", optional = true } -# Bearer authentication -jsonwebtoken = { version = "9.3.0", optional = false } +# TLS dependencies - platform-specific backends +# On macOS/Windows/iOS, use native-tls via hyper-tls +[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] +native-tls = { version = "0.2", optional = true } +hyper-tls = { version = "0.6", optional = true } + +# On other platforms (Linux, etc.), use OpenSSL via hyper-openssl +[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] +openssl = { version = "0.10", optional = true } +hyper-openssl = { version = "0.10", optional = true } [dev-dependencies] -clap = "2.25" -env_logger = "0.7" -tokio = { version = "1.14", features = ["full"] } +always_send = "0.1.1" +clap = "4.6.0" +env_logger = "0.11" +tokio = { version = "1.50.0", features = ["full"] } native-tls = "0.2" +pin-project = "1.1.11" + +# Bearer authentication, used in examples +jsonwebtoken = {version = "10.3.0", features = ["rust_crypto"]} [target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies] -tokio-openssl = "0.6" openssl = "0.10" +tokio-openssl = "0.6" [[example]] -name = "client" +name = "openapi-v3-client" +path = "examples/client/main.rs" required-features = ["client"] [[example]] -name = "server" +name = "openapi-v3-server" +path = "examples/server/main.rs" required-features = ["server"] + +[[bin]] +name = "openapi-v3" +path = "bin/cli.rs" +required-features = ["client", "cli"] diff --git a/samples/server/petstore/rust-server/output/openapi-v3/README.md b/samples/server/petstore/rust-server/output/openapi-v3/README.md index 8cc48764613a..c18a5ca15c80 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/README.md +++ b/samples/server/petstore/rust-server/output/openapi-v3/README.md @@ -14,7 +14,7 @@ To see how to make this your own, look here: [README]((https://openapi-generator.tech)) - API version: 1.0.7 -- Generator version: 8.0.0-SNAPSHOT +- Generator version: 7.22.0-SNAPSHOT @@ -23,6 +23,7 @@ This autogenerated project defines an API crate `openapi-v3` which contains: * Data types representing the underlying data model. * A `Client` type which implements `Api` and issues HTTP requests for each operation. * A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. +* A CLI tool to drive basic API operations from the command line. It also contains an example server and client which make use of `openapi-v3`: @@ -34,65 +35,86 @@ It also contains an example server and client which make use of `openapi-v3`: arguments on the command line. You can use the example server and client as a basis for your own code. -See below for [more detail on implementing a server](#writing-a-server). +See below for [more detail on the examples](#using-the-generated-library). + +## CLI + +Run the included CLI tool with: + +``` +cargo run --bin cli --features=cli +``` + +To pass in arguments, put them after `--`, for example: + +``` +cargo run --bin cli --features=cli -- --help +``` + +See the help text for available options. + +To build a standalone tool, use: + +``` +cargo build --bin cli --features=cli --release +``` + +You'll find the binary at `target/release/cli`. ## Examples Run examples with: ``` -cargo run --example +cargo run --example openapi-v3- ``` To pass in arguments to the examples, put them after `--`, for example: ``` -cargo run --example client -- --help +cargo run --example openapi-v3-client -- --help ``` ### Running the example server To run the server, follow these simple steps: ``` -cargo run --example server +cargo run --example openapi-v3-server ``` ### Running the example client To run a client, follow one of the following simple steps: ``` -cargo run --example client AnyOfGet -cargo run --example client CallbackWithHeaderPost -cargo run --example client ComplexQueryParamGet -cargo run --example client JsonComplexQueryParamGet -cargo run --example client MandatoryRequestHeaderGet -cargo run --example client MergePatchJsonGet -cargo run --example client MultigetGet -cargo run --example client MultipleAuthSchemeGet -cargo run --example client OneOfGet -cargo run --example client OverrideServerGet -cargo run --example client ParamgetGet -cargo run --example client ReadonlyAuthSchemeGet -cargo run --example client RegisterCallbackPost -cargo run --example client RequiredOctetStreamPut -cargo run --example client ResponsesWithHeadersGet -cargo run --example client Rfc7807Get -cargo run --example client UntypedPropertyGet -cargo run --example client UuidGet -cargo run --example client XmlExtraPost -cargo run --example client XmlOtherPost -cargo run --example client XmlOtherPut -cargo run --example client XmlPost -cargo run --example client XmlPut -cargo run --example client CreateRepo -cargo run --example client GetRepoInfo +cargo run --example openapi-v3-client AnyOfGet +cargo run --example openapi-v3-client ComplexQueryParamGet +cargo run --example openapi-v3-client JsonComplexQueryParamGet +cargo run --example openapi-v3-client MergePatchJsonGet +cargo run --example openapi-v3-client MultigetGet +cargo run --example openapi-v3-client MultipleAuthSchemeGet +cargo run --example openapi-v3-client OneOfGet +cargo run --example openapi-v3-client OverrideServerGet +cargo run --example openapi-v3-client ParamgetGet +cargo run --example openapi-v3-client ReadonlyAuthSchemeGet +cargo run --example openapi-v3-client RequiredOctetStreamPut +cargo run --example openapi-v3-client ResponsesWithHeadersGet +cargo run --example openapi-v3-client Rfc7807Get +cargo run --example openapi-v3-client UntypedPropertyGet +cargo run --example openapi-v3-client UuidGet +cargo run --example openapi-v3-client XmlExtraPost +cargo run --example openapi-v3-client XmlOtherPost +cargo run --example openapi-v3-client XmlOtherPut +cargo run --example openapi-v3-client XmlPost +cargo run --example openapi-v3-client XmlPut +cargo run --example openapi-v3-client EnumInPathPathParamGet +cargo run --example openapi-v3-client CreateRepo ``` ### HTTPS The examples can be run in HTTPS mode by passing in the flag `--https`, for example: ``` -cargo run --example server -- --https +cargo run --example openapi-v3-server -- --https ``` This will use the keys/certificates from the examples directory. Note that the @@ -108,8 +130,36 @@ The generated library has a few optional features that can be activated through * `client` * This defaults to enabled and creates the basic skeleton of a client implementation based on hyper * The constructed client implements the API trait by making remote API call. +* `client-tls` + * This default to enabled and provides HTTPS support with automatic TLS backend selection: + - macOS/Windows/iOS: native-tls + hyper-tls + - Linux/Unix/others: OpenSSL + hyper-openssl * `conversions` * This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types. +* `cli` + * This defaults to disabled and is required for building the included CLI tool. +* `validate` + * This defaults to disabled and allows JSON Schema validation of received data using `MakeService::set_validation` or `Service::set_validation`. + * Note, enabling validation will have a performance penalty, especially if the API heavily uses regex based checks. + +### HTTPS/TLS Support + +HTTPS support is included by default. To disable it (for example, to reduce dependencies), you can: + +```toml +[dependencies] +openapi-v3 = { version = "1.0.7", default-features = false, features = ["client", "server"] } +``` + +**For server with callbacks that need HTTPS:** +```toml +[dependencies] +openapi-v3 = { version = "1.0.7", features = ["server", "client-tls"] } +``` + +The TLS backend is automatically selected based on your target platform: +- **macOS, Windows, iOS**: Uses `native-tls` (system TLS libraries) +- **Linux, Unix, other platforms**: Uses `openssl` See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`. @@ -122,7 +172,6 @@ Method | HTTP request | Description [****](docs/default_api.md#) | **GET** /any-of | [****](docs/default_api.md#) | **POST** /callback-with-header | [****](docs/default_api.md#) | **GET** /complex-query-param | -[****](docs/default_api.md#) | **GET** /enum_in_path/{path_param} | [****](docs/default_api.md#) | **GET** /json-complex-query-param | [****](docs/default_api.md#) | **GET** /mandatory-request-header | [****](docs/default_api.md#) | **GET** /merge-patch-json | @@ -143,6 +192,7 @@ Method | HTTP request | Description [****](docs/default_api.md#) | **PUT** /xml_other | [****](docs/default_api.md#) | **POST** /xml | Post an array [****](docs/default_api.md#) | **PUT** /xml | +[****](docs/default_api.md#) | **GET** /enum_in_path/{path_param} | [**CreateRepo**](docs/repo_api.md#CreateRepo) | **POST** /repos | [**GetRepoInfo**](docs/repo_api.md#GetRepoInfo) | **GET** /repos/{repoId} | @@ -155,12 +205,14 @@ Method | HTTP request | Description - [AnotherXmlObject](docs/AnotherXmlObject.md) - [AnyOfGet202Response](docs/AnyOfGet202Response.md) - [AnyOfObject](docs/AnyOfObject.md) + - [AnyOfObjectAnyOf](docs/AnyOfObjectAnyOf.md) - [AnyOfProperty](docs/AnyOfProperty.md) - [DuplicateXmlObject](docs/DuplicateXmlObject.md) - [EnumWithStarObject](docs/EnumWithStarObject.md) - [Err](docs/Err.md) - [Error](docs/Error.md) - [Model12345AnyOfObject](docs/Model12345AnyOfObject.md) + - [Model12345AnyOfObjectAnyOf](docs/Model12345AnyOfObjectAnyOf.md) - [MultigetGet201Response](docs/MultigetGet201Response.md) - [MyId](docs/MyId.md) - [MyIdList](docs/MyIdList.md) diff --git a/samples/server/petstore/rust-server/output/openapi-v3/api/openapi.yaml b/samples/server/petstore/rust-server/output/openapi-v3/api/openapi.yaml index 51eb55c33843..42d49a6e6ab3 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/api/openapi.yaml +++ b/samples/server/petstore/rust-server/output/openapi-v3/api/openapi.yaml @@ -13,7 +13,7 @@ paths: content: application/xml: schema: - $ref: '#/components/schemas/xml_array' + $ref: "#/components/schemas/xml_array" responses: "201": description: OK @@ -25,7 +25,7 @@ paths: content: application/xml: schema: - $ref: '#/components/schemas/xml_object' + $ref: "#/components/schemas/xml_object" responses: "201": description: OK @@ -40,7 +40,7 @@ paths: name: uuid required: false schema: - $ref: '#/components/schemas/UuidObject' + $ref: "#/components/schemas/UuidObject" style: form - description: Some object to pass as query parameter explode: false @@ -48,7 +48,7 @@ paths: name: someObject required: false schema: - $ref: '#/components/schemas/ObjectParam' + $ref: "#/components/schemas/ObjectParam" style: form - description: Some list to pass as query parameter explode: false @@ -56,14 +56,14 @@ paths: name: someList required: false schema: - $ref: '#/components/schemas/MyIDList' + $ref: "#/components/schemas/MyIDList" style: form responses: "200": content: application/json: schema: - $ref: '#/components/schemas/anotherXmlObject' + $ref: "#/components/schemas/anotherXmlObject" description: JSON rsp summary: Get some stuff with parameters. /multiget: @@ -73,13 +73,13 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/anotherXmlObject' + $ref: "#/components/schemas/anotherXmlObject" description: JSON rsp "201": content: application/xml: schema: - $ref: '#/components/schemas/_multiget_get_201_response' + $ref: "#/components/schemas/_multiget_get_201_response" description: XML rsp "202": content: @@ -98,19 +98,19 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/anotherXmlObject' + $ref: "#/components/schemas/anotherXmlObject" description: Duplicate Response long text. One. "205": content: application/json: schema: - $ref: '#/components/schemas/anotherXmlObject' + $ref: "#/components/schemas/anotherXmlObject" description: Duplicate Response long text. Two. "206": content: application/json: schema: - $ref: '#/components/schemas/anotherXmlObject' + $ref: "#/components/schemas/anotherXmlObject" description: Duplicate Response long text. Three. summary: Get some stuff. /xml_other: @@ -119,13 +119,13 @@ paths: content: text/xml: schema: - $ref: '#/components/schemas/anotherXmlObject' + $ref: "#/components/schemas/anotherXmlObject" responses: "201": content: text/xml: schema: - $ref: '#/components/schemas/anotherXmlObject' + $ref: "#/components/schemas/anotherXmlObject" description: OK "400": description: Bad Request @@ -134,7 +134,7 @@ paths: content: application/xml: schema: - $ref: '#/components/schemas/anotherXmlArray' + $ref: "#/components/schemas/anotherXmlArray" responses: "201": description: OK @@ -146,7 +146,7 @@ paths: content: application/xml: schema: - $ref: '#/components/schemas/duplicate_xml_object' + $ref: "#/components/schemas/duplicate_xml_object" responses: "201": description: OK @@ -159,7 +159,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/UuidObject' + $ref: "#/components/schemas/UuidObject" description: Duplicate Response long text. One. /required_octet_stream: put: @@ -196,7 +196,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ObjectUntypedProps' + $ref: "#/components/schemas/ObjectUntypedProps" responses: "200": description: Check that untyped properties works @@ -224,7 +224,7 @@ paths: Object-Header: explode: false schema: - $ref: '#/components/schemas/ObjectHeader' + $ref: "#/components/schemas/ObjectHeader" style: simple "412": description: Precondition Failed @@ -258,7 +258,7 @@ paths: callback: '{$request.query.url}/callback': post: - operationId: callback_CallbackPost + operationId: CallbackCallbackPost responses: "204": description: OK @@ -281,7 +281,7 @@ paths: callback: '{$request.query.url}/callback-with-header': post: - operationId: callback_CallbackWithHeaderPost + operationId: CallbackCallbackWithHeaderPost parameters: - explode: false in: header @@ -313,19 +313,19 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ObjectWithArrayOfObjects' + $ref: "#/components/schemas/ObjectWithArrayOfObjects" description: OK "404": content: application/problem+json: schema: - $ref: '#/components/schemas/ObjectWithArrayOfObjects' + $ref: "#/components/schemas/ObjectWithArrayOfObjects" description: NotFound "406": content: application/problem+xml: schema: - $ref: '#/components/schemas/ObjectWithArrayOfObjects' + $ref: "#/components/schemas/ObjectWithArrayOfObjects" description: NotAcceptable /merge-patch-json: get: @@ -334,7 +334,7 @@ paths: content: application/merge-patch+json: schema: - $ref: '#/components/schemas/anotherXmlObject' + $ref: "#/components/schemas/anotherXmlObject" description: merge-patch+json-encoded response /enum_in_path/{path_param}: get: @@ -344,7 +344,7 @@ paths: name: path_param required: true schema: - $ref: '#/components/schemas/StringEnum' + $ref: "#/components/schemas/StringEnum" style: simple responses: "200": @@ -365,7 +365,7 @@ paths: required: false schema: items: - $ref: '#/components/schemas/StringObject' + $ref: "#/components/schemas/StringObject" type: array style: form responses: @@ -387,7 +387,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/StringObject' + $ref: "#/components/schemas/StringObject" description: OK tags: - repo @@ -401,7 +401,7 @@ paths: example: requiredParam: true schema: - $ref: '#/components/schemas/ObjectParam' + $ref: "#/components/schemas/ObjectParam" required: true responses: "200": @@ -415,7 +415,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/_one_of_get_200_response' + $ref: "#/components/schemas/_one_of_get_200_response" description: Success /any-of: get: @@ -427,7 +427,7 @@ paths: required: false schema: items: - $ref: '#/components/schemas/AnyOfObject' + $ref: "#/components/schemas/AnyOfObject" minItems: 1 type: array style: form @@ -436,19 +436,19 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/AnyOfObject' + $ref: "#/components/schemas/AnyOfObject" description: Success "201": content: application/json: schema: - $ref: '#/components/schemas/12345AnyOfObject' + $ref: "#/components/schemas/12345AnyOfObject" description: AlternateSuccess "202": content: application/json: schema: - $ref: '#/components/schemas/_any_of_get_202_response' + $ref: "#/components/schemas/_any_of_get_202_response" description: AnyOfSuccess /json-complex-query-param: get: @@ -457,7 +457,7 @@ paths: application/json: schema: items: - $ref: '#/components/schemas/StringObject' + $ref: "#/components/schemas/StringObject" type: array in: query name: list-of-strings @@ -471,27 +471,20 @@ components: description: Test containing an anyOf object properties: requiredAnyOf: - $ref: '#/components/schemas/AnyOfObject' + $ref: "#/components/schemas/AnyOfObject" optionalAnyOf: - $ref: '#/components/schemas/12345AnyOfObject' + $ref: "#/components/schemas/12345AnyOfObject" required: - requiredAnyOf AnyOfObject: anyOf: - - enum: - - FOO - - BAR - type: string + - $ref: "#/components/schemas/AnyOfObject_anyOf" - description: Alternate option type: string description: Test a model containing an anyOf "12345AnyOfObject": anyOf: - - enum: - - FOO - - BAR - - '*' - type: string + - $ref: "#/components/schemas/_12345AnyOfObject_anyOf" - description: Alternate option type: string description: Test a model containing an anyOf that starts with a number @@ -508,7 +501,7 @@ components: type: string xml_array: items: - $ref: '#/components/schemas/xml_inner' + $ref: "#/components/schemas/xml_inner" type: array xml: name: CamelXmlArray @@ -535,7 +528,7 @@ components: inner_string: type: string inner_array: - $ref: '#/components/schemas/xml_array' + $ref: "#/components/schemas/xml_array" required: - inner_array type: object @@ -544,7 +537,7 @@ components: namespace: http://different.bar anotherXmlArray: items: - $ref: '#/components/schemas/anotherXmlInner' + $ref: "#/components/schemas/anotherXmlInner" type: array xml: name: snake_another_xml_array @@ -572,14 +565,14 @@ components: properties: objectArray: items: - $ref: '#/components/schemas/StringObject' + $ref: "#/components/schemas/StringObject" type: array type: object StringObject: type: string MyIDList: items: - $ref: '#/components/schemas/MyID' + $ref: "#/components/schemas/MyID" type: array MyID: type: integer @@ -699,8 +692,19 @@ components: type: array _any_of_get_202_response: anyOf: - - $ref: '#/components/schemas/StringObject' - - $ref: '#/components/schemas/UuidObject' + - $ref: "#/components/schemas/StringObject" + - $ref: "#/components/schemas/UuidObject" + AnyOfObject_anyOf: + enum: + - FOO + - BAR + type: string + _12345AnyOfObject_anyOf: + enum: + - FOO + - BAR + - '*' + type: string securitySchemes: authScheme: flows: diff --git a/samples/server/petstore/rust-server/output/openapi-v3/bin/cli.rs b/samples/server/petstore/rust-server/output/openapi-v3/bin/cli.rs new file mode 100644 index 000000000000..d5f561a57798 --- /dev/null +++ b/samples/server/petstore/rust-server/output/openapi-v3/bin/cli.rs @@ -0,0 +1,789 @@ +//! CLI tool driving the API client +use anyhow::{anyhow, Context, Result}; +use clap::Parser; +use log::{debug, info}; +// models may be unused if all inputs are primitive types +#[allow(unused_imports)] +use openapi_v3::{ + models, ApiNoContext, Client, ContextWrapperExt, + AnyOfGetResponse, + CallbackWithHeaderPostResponse, + ComplexQueryParamGetResponse, + JsonComplexQueryParamGetResponse, + MandatoryRequestHeaderGetResponse, + MergePatchJsonGetResponse, + MultigetGetResponse, + MultipleAuthSchemeGetResponse, + OneOfGetResponse, + OverrideServerGetResponse, + ParamgetGetResponse, + ReadonlyAuthSchemeGetResponse, + RegisterCallbackPostResponse, + RequiredOctetStreamPutResponse, + ResponsesWithHeadersGetResponse, + Rfc7807GetResponse, + UntypedPropertyGetResponse, + UuidGetResponse, + XmlExtraPostResponse, + XmlOtherPostResponse, + XmlOtherPutResponse, + XmlPostResponse, + XmlPutResponse, + EnumInPathPathParamGetResponse, + CreateRepoResponse, + GetRepoInfoResponse, +}; +use simple_logger::SimpleLogger; +use swagger::{AuthData, ContextBuilder, EmptyContext, Push, XSpanIdString}; + +type ClientContext = swagger::make_context_ty!( + ContextBuilder, + EmptyContext, + Option, + XSpanIdString +); + +#[derive(Parser, Debug)] +#[clap( + name = "My title", + version = "1.0.7", + about = "CLI access to My title" +)] +struct Cli { + #[clap(subcommand)] + operation: Operation, + + /// Address or hostname of the server hosting this API, including optional port + #[clap(short = 'a', long, default_value = "http://localhost")] + server_address: String, + + /// Path to the client private key if using client-side TLS authentication + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_certificate", "server_certificate"]))] + client_key: Option, + + /// Path to the client's public certificate associated with the private key + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_key", "server_certificate"]))] + client_certificate: Option, + + /// Path to CA certificate used to authenticate the server + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long)] + server_certificate: Option, + + /// If set, write output to file instead of stdout + #[clap(short, long)] + output_file: Option, + + #[command(flatten)] + verbosity: clap_verbosity_flag::Verbosity, + + /// Bearer token if used for authentication + #[arg(env = "OPENAPI_V3_BEARER_TOKEN", hide_env = true)] + bearer_token: Option, +} + +#[derive(Parser, Debug)] +enum Operation { + AnyOfGet { + /// list of any of objects + #[clap(value_parser = parse_json::>, long)] + any_of: Option>, + }, + CallbackWithHeaderPost { + url: String, + }, + ComplexQueryParamGet { + #[clap(value_parser = parse_json::>, long)] + list_of_strings: Option>, + }, + JsonComplexQueryParamGet { + #[clap(value_parser = parse_json::>, long)] + list_of_strings: Option>, + }, + MandatoryRequestHeaderGet { + x_header: String, + }, + MergePatchJsonGet { + }, + /// Get some stuff. + MultigetGet { + }, + MultipleAuthSchemeGet { + }, + OneOfGet { + }, + OverrideServerGet { + }, + /// Get some stuff with parameters. + ParamgetGet { + /// The stuff to get + #[clap(value_parser = parse_json::)] + uuid: Option, + /// Some object to pass as query parameter + #[clap(value_parser = parse_json::)] + some_object: Option, + /// Some list to pass as query parameter + #[clap(value_parser = parse_json::)] + some_list: Option, + }, + ReadonlyAuthSchemeGet { + }, + RegisterCallbackPost { + url: String, + }, + RequiredOctetStreamPut { + #[clap(value_parser = parse_json::)] + body: swagger::ByteArray, + }, + ResponsesWithHeadersGet { + }, + Rfc7807Get { + }, + UntypedPropertyGet { + #[clap(value_parser = parse_json::)] + object_untyped_props: Option, + }, + UuidGet { + }, + XmlExtraPost { + #[clap(value_parser = parse_json::)] + duplicate_xml_object: Option, + }, + XmlOtherPost { + #[clap(value_parser = parse_json::)] + another_xml_object: Option, + }, + XmlOtherPut { + #[clap(value_parser = parse_json::)] + another_xml_array: Option, + }, + /// Post an array + XmlPost { + #[clap(value_parser = parse_json::)] + xml_array: Option, + }, + XmlPut { + #[clap(value_parser = parse_json::)] + xml_object: Option, + }, + EnumInPathPathParamGet { + #[clap(value_parser = parse_json::)] + path_param: models::StringEnum, + }, + CreateRepo { + #[clap(value_parser = parse_json::)] + object_param: models::ObjectParam, + }, + GetRepoInfo { + repo_id: String, + }, +} + +// On Linux/Unix with OpenSSL (client-tls feature), support certificate pinning and mutual TLS +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + if args.client_certificate.is_some() { + debug!("Using mutual TLS"); + let client = Client::try_new_https_mutual( + &args.server_address, + args.server_certificate.clone().unwrap(), + args.client_key.clone().unwrap(), + args.client_certificate.clone().unwrap(), + ) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else if args.server_certificate.is_some() { + debug!("Using TLS with pinned server certificate"); + let client = + Client::try_new_https_pinned(&args.server_address, args.server_certificate.clone().unwrap()) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else { + debug!("Using client without certificates"); + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) + } +} + +// On macOS/Windows/iOS or without client-tls feature, use simple client (no cert pinning/mutual TLS) +#[cfg(any( + not(feature = "client-tls"), + all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")) +))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + // Client::try_new() automatically detects the URL scheme (http:// or https://) + // and creates the appropriate client. + // Note: Certificate pinning and mutual TLS are only available on Linux/Unix with OpenSSL + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) +} + +#[tokio::main] +async fn main() -> Result<()> { + let args = Cli::parse(); + if let Some(log_level) = args.verbosity.log_level() { + SimpleLogger::new().with_level(log_level.to_level_filter()).init()?; + } + + debug!("Arguments: {:?}", &args); + + let mut auth_data: Option = None; + + if let Some(ref bearer_token) = args.bearer_token { + debug!("Using bearer token"); + auth_data = AuthData::bearer(bearer_token); + } + + #[allow(trivial_casts)] + let context = swagger::make_context!( + ContextBuilder, + EmptyContext, + auth_data, + XSpanIdString::default() + ); + + let client = create_client(&args, context)?; + + let result = match args.operation { + Operation::AnyOfGet { + any_of, + } => { + info!("Performing a AnyOfGet request"); + + let result = client.any_of_get( + any_of.as_ref(), + ).await?; + debug!("Result: {:?}", result); + + match result { + AnyOfGetResponse::Success + (body) + => "Success\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + AnyOfGetResponse::AlternateSuccess + (body) + => "AlternateSuccess\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + AnyOfGetResponse::AnyOfSuccess + (body) + => "AnyOfSuccess\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::CallbackWithHeaderPost { + url, + } => { + info!("Performing a CallbackWithHeaderPost request"); + + let result = client.callback_with_header_post( + url, + ).await?; + debug!("Result: {:?}", result); + + match result { + CallbackWithHeaderPostResponse::OK + => "OK\n".to_string() + , + } + } + Operation::ComplexQueryParamGet { + list_of_strings, + } => { + info!("Performing a ComplexQueryParamGet request"); + + let result = client.complex_query_param_get( + list_of_strings.as_ref(), + ).await?; + debug!("Result: {:?}", result); + + match result { + ComplexQueryParamGetResponse::Success + => "Success\n".to_string() + , + } + } + Operation::JsonComplexQueryParamGet { + list_of_strings, + } => { + info!("Performing a JsonComplexQueryParamGet request"); + + let result = client.json_complex_query_param_get( + list_of_strings.as_ref(), + ).await?; + debug!("Result: {:?}", result); + + match result { + JsonComplexQueryParamGetResponse::Success + => "Success\n".to_string() + , + } + } + Operation::MandatoryRequestHeaderGet { + x_header, + } => { + info!("Performing a MandatoryRequestHeaderGet request"); + + let result = client.mandatory_request_header_get( + x_header, + ).await?; + debug!("Result: {:?}", result); + + match result { + MandatoryRequestHeaderGetResponse::Success + => "Success\n".to_string() + , + } + } + Operation::MergePatchJsonGet { + } => { + info!("Performing a MergePatchJsonGet request"); + + let result = client.merge_patch_json_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + MergePatchJsonGetResponse::Merge + (body) + => "Merge\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::MultigetGet { + } => { + info!("Performing a MultigetGet request"); + + let result = client.multiget_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + MultigetGetResponse::JSONRsp + (body) + => "JSONRsp\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + MultigetGetResponse::XMLRsp + (body) + => "XMLRsp\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + MultigetGetResponse::OctetRsp + (body) + => "OctetRsp\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + MultigetGetResponse::StringRsp + (body) + => "StringRsp\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + MultigetGetResponse::DuplicateResponseLongText + (body) + => "DuplicateResponseLongText\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + MultigetGetResponse::DuplicateResponseLongText_2 + (body) + => "DuplicateResponseLongText_2\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + MultigetGetResponse::DuplicateResponseLongText_3 + (body) + => "DuplicateResponseLongText_3\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::MultipleAuthSchemeGet { + } => { + info!("Performing a MultipleAuthSchemeGet request"); + + let result = client.multiple_auth_scheme_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + MultipleAuthSchemeGetResponse::CheckThatLimitingToMultipleRequiredAuthSchemesWorks + => "CheckThatLimitingToMultipleRequiredAuthSchemesWorks\n".to_string() + , + } + } + Operation::OneOfGet { + } => { + info!("Performing a OneOfGet request"); + + let result = client.one_of_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + OneOfGetResponse::Success + (body) + => "Success\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::OverrideServerGet { + } => { + info!("Performing a OverrideServerGet request"); + + let result = client.override_server_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + OverrideServerGetResponse::Success + => "Success\n".to_string() + , + } + } + Operation::ParamgetGet { + uuid, + some_object, + some_list, + } => { + info!("Performing a ParamgetGet request"); + + let result = client.paramget_get( + uuid, + some_object, + some_list, + ).await?; + debug!("Result: {:?}", result); + + match result { + ParamgetGetResponse::JSONRsp + (body) + => "JSONRsp\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::ReadonlyAuthSchemeGet { + } => { + info!("Performing a ReadonlyAuthSchemeGet request"); + + let result = client.readonly_auth_scheme_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + ReadonlyAuthSchemeGetResponse::CheckThatLimitingToASingleRequiredAuthSchemeWorks + => "CheckThatLimitingToASingleRequiredAuthSchemeWorks\n".to_string() + , + } + } + Operation::RegisterCallbackPost { + url, + } => { + info!("Performing a RegisterCallbackPost request"); + + let result = client.register_callback_post( + url, + ).await?; + debug!("Result: {:?}", result); + + match result { + RegisterCallbackPostResponse::OK + => "OK\n".to_string() + , + } + } + Operation::RequiredOctetStreamPut { + body, + } => { + info!("Performing a RequiredOctetStreamPut request"); + + let result = client.required_octet_stream_put( + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + RequiredOctetStreamPutResponse::OK + => "OK\n".to_string() + , + } + } + Operation::ResponsesWithHeadersGet { + } => { + info!("Performing a ResponsesWithHeadersGet request"); + + let result = client.responses_with_headers_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + ResponsesWithHeadersGetResponse::Success + { + body, + success_info, + bool_header, + object_header, + } + => "Success\n".to_string() + + + &format!("body: {}\n", serde_json::to_string_pretty(&body)?) + + &format!( + "success_info: {}\n", + serde_json::to_string_pretty(&success_info)? + ) + + &format!( + "bool_header: {}\n", + serde_json::to_string_pretty(&bool_header)? + ) + + &format!( + "object_header: {}\n", + serde_json::to_string_pretty(&object_header)? + ), + ResponsesWithHeadersGetResponse::PreconditionFailed + { + further_info, + failure_info, + } + => "PreconditionFailed\n".to_string() + + + &format!( + "further_info: {}\n", + serde_json::to_string_pretty(&further_info)? + ) + + &format!( + "failure_info: {}\n", + serde_json::to_string_pretty(&failure_info)? + ), + } + } + Operation::Rfc7807Get { + } => { + info!("Performing a Rfc7807Get request"); + + let result = client.rfc7807_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Rfc7807GetResponse::OK + (body) + => "OK\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + Rfc7807GetResponse::NotFound + (body) + => "NotFound\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + Rfc7807GetResponse::NotAcceptable + (body) + => "NotAcceptable\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::UntypedPropertyGet { + object_untyped_props, + } => { + info!("Performing a UntypedPropertyGet request"); + + let result = client.untyped_property_get( + object_untyped_props, + ).await?; + debug!("Result: {:?}", result); + + match result { + UntypedPropertyGetResponse::CheckThatUntypedPropertiesWorks + => "CheckThatUntypedPropertiesWorks\n".to_string() + , + } + } + Operation::UuidGet { + } => { + info!("Performing a UuidGet request"); + + let result = client.uuid_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + UuidGetResponse::DuplicateResponseLongText + (body) + => "DuplicateResponseLongText\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::XmlExtraPost { + duplicate_xml_object, + } => { + info!("Performing a XmlExtraPost request"); + + let result = client.xml_extra_post( + duplicate_xml_object, + ).await?; + debug!("Result: {:?}", result); + + match result { + XmlExtraPostResponse::OK + => "OK\n".to_string() + , + XmlExtraPostResponse::BadRequest + => "BadRequest\n".to_string() + , + } + } + Operation::XmlOtherPost { + another_xml_object, + } => { + info!("Performing a XmlOtherPost request"); + + let result = client.xml_other_post( + another_xml_object, + ).await?; + debug!("Result: {:?}", result); + + match result { + XmlOtherPostResponse::OK + (body) + => "OK\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + XmlOtherPostResponse::BadRequest + => "BadRequest\n".to_string() + , + } + } + Operation::XmlOtherPut { + another_xml_array, + } => { + info!("Performing a XmlOtherPut request"); + + let result = client.xml_other_put( + another_xml_array, + ).await?; + debug!("Result: {:?}", result); + + match result { + XmlOtherPutResponse::OK + => "OK\n".to_string() + , + XmlOtherPutResponse::BadRequest + => "BadRequest\n".to_string() + , + } + } + Operation::XmlPost { + xml_array, + } => { + info!("Performing a XmlPost request"); + + let result = client.xml_post( + xml_array, + ).await?; + debug!("Result: {:?}", result); + + match result { + XmlPostResponse::OK + => "OK\n".to_string() + , + XmlPostResponse::BadRequest + => "BadRequest\n".to_string() + , + } + } + Operation::XmlPut { + xml_object, + } => { + info!("Performing a XmlPut request"); + + let result = client.xml_put( + xml_object, + ).await?; + debug!("Result: {:?}", result); + + match result { + XmlPutResponse::OK + => "OK\n".to_string() + , + XmlPutResponse::BadRequest + => "BadRequest\n".to_string() + , + } + } + Operation::EnumInPathPathParamGet { + path_param, + } => { + info!("Performing a EnumInPathPathParamGet request on {:?}", ( + &path_param + )); + + let result = client.enum_in_path_path_param_get( + path_param, + ).await?; + debug!("Result: {:?}", result); + + match result { + EnumInPathPathParamGetResponse::Success + => "Success\n".to_string() + , + } + } + Operation::CreateRepo { + object_param, + } => { + info!("Performing a CreateRepo request"); + + let result = client.create_repo( + object_param, + ).await?; + debug!("Result: {:?}", result); + + match result { + CreateRepoResponse::Success + => "Success\n".to_string() + , + } + } + Operation::GetRepoInfo { + repo_id, + } => { + info!("Performing a GetRepoInfo request on {:?}", ( + &repo_id + )); + + let result = client.get_repo_info( + repo_id, + ).await?; + debug!("Result: {:?}", result); + + match result { + GetRepoInfoResponse::OK + (body) + => "OK\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + }; + + if let Some(output_file) = args.output_file { + std::fs::write(output_file, result)? + } else { + println!("{}", result); + } + Ok(()) +} + +// May be unused if all inputs are primitive types +#[allow(dead_code)] +fn parse_json(json_string: &str) -> Result { + serde_json::from_str(json_string).map_err(|err| anyhow!("Error parsing input: {}", err)) +} diff --git a/samples/server/petstore/rust-server/output/openapi-v3/docs/NullableTest.md b/samples/server/petstore/rust-server/output/openapi-v3/docs/NullableTest.md index 2512b338a5b9..be0cda4a1e9c 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/docs/NullableTest.md +++ b/samples/server/petstore/rust-server/output/openapi-v3/docs/NullableTest.md @@ -3,11 +3,11 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**nullable** | **String** | | -**nullable_with_null_default** | **String** | | [optional] [default to None] -**nullable_with_present_default** | **String** | | [optional] [default to Some(swagger::Nullable::Present("default".to_string()))] -**nullable_with_no_default** | **String** | | [optional] [default to None] -**nullable_array** | **Vec** | | [optional] [default to None] +**nullable** | **swagger::Nullable** | | +**nullable_with_null_default** | **swagger::Nullable** | | [optional] [default to None] +**nullable_with_present_default** | **swagger::Nullable** | | [optional] [default to Some(swagger::Nullable::Present("default".to_string()))] +**nullable_with_no_default** | **swagger::Nullable** | | [optional] [default to None] +**nullable_array** | **swagger::Nullable>** | | [optional] [default to None] **min_item_test** | **Vec** | | [optional] [default to None] **max_item_test** | **Vec** | | [optional] [default to None] **min_max_item_test** | **Vec** | | [optional] [default to None] diff --git a/samples/server/petstore/rust-server/output/openapi-v3/docs/ObjectUntypedProps.md b/samples/server/petstore/rust-server/output/openapi-v3/docs/ObjectUntypedProps.md index 492045cab7c6..1b668dec84f2 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/docs/ObjectUntypedProps.md +++ b/samples/server/petstore/rust-server/output/openapi-v3/docs/ObjectUntypedProps.md @@ -4,7 +4,7 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **required_untyped** | [***serde_json::Value**](.md) | | -**required_untyped_nullable** | [***serde_json::Value**](.md) | | +**required_untyped_nullable** | [***swagger::Nullable**](.md) | | **not_required_untyped** | [***serde_json::Value**](.md) | | [optional] [default to None] **not_required_untyped_nullable** | [***serde_json::Value**](.md) | | [optional] [default to None] diff --git a/samples/server/petstore/rust-server/output/openapi-v3/docs/default_api.md b/samples/server/petstore/rust-server/output/openapi-v3/docs/default_api.md index 192101ead315..e0897cd495b7 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/docs/default_api.md +++ b/samples/server/petstore/rust-server/output/openapi-v3/docs/default_api.md @@ -7,7 +7,6 @@ Method | HTTP request | Description ****](default_api.md#) | **GET** /any-of | ****](default_api.md#) | **POST** /callback-with-header | ****](default_api.md#) | **GET** /complex-query-param | -****](default_api.md#) | **GET** /enum_in_path/{path_param} | ****](default_api.md#) | **GET** /json-complex-query-param | ****](default_api.md#) | **GET** /mandatory-request-header | ****](default_api.md#) | **GET** /merge-patch-json | @@ -28,6 +27,7 @@ Method | HTTP request | Description ****](default_api.md#) | **PUT** /xml_other | ****](default_api.md#) | **POST** /xml | Post an array ****](default_api.md#) | **PUT** /xml | +****](default_api.md#) | **GET** /enum_in_path/{path_param} | # **** @@ -119,31 +119,6 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **** -> (path_param) - - -### Required Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **path_param** | [****](.md)| | - -### Return type - - (empty response body) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - # **** > (optional) @@ -677,3 +652,28 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **** +> (path_param) + + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **path_param** | [****](.md)| | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/samples/server/petstore/rust-server/output/openapi-v3/examples/client/main.rs b/samples/server/petstore/rust-server/output/openapi-v3/examples/client/main.rs index af8b2f382938..c2706e317c7a 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/examples/client/main.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/examples/client/main.rs @@ -9,7 +9,6 @@ use openapi_v3::{Api, ApiNoContext, Claims, Client, ContextWrapperExt, models, AnyOfGetResponse, CallbackWithHeaderPostResponse, ComplexQueryParamGetResponse, - EnumInPathPathParamGetResponse, JsonComplexQueryParamGetResponse, MandatoryRequestHeaderGetResponse, MergePatchJsonGetResponse, @@ -30,10 +29,11 @@ use openapi_v3::{Api, ApiNoContext, Claims, Client, ContextWrapperExt, models, XmlOtherPutResponse, XmlPostResponse, XmlPutResponse, + EnumInPathPathParamGetResponse, CreateRepoResponse, GetRepoInfoResponse, }; -use clap::{App, Arg}; +use clap::{Command, Arg}; // NOTE: Set environment variable RUST_LOG to the name of the executable (or "cargo run") to activate console logging for all loglevels. // See https://docs.rs/env_logger/latest/env_logger/ for more details @@ -56,49 +56,44 @@ use client_auth::build_token; fn main() { env_logger::init(); - let matches = App::new("client") - .arg(Arg::with_name("operation") + let matches = Command::new("client") + .arg(Arg::new("operation") .help("Sets the operation to run") - .possible_values(&[ - "AnyOfGet", - "CallbackWithHeaderPost", - "ComplexQueryParamGet", - "JsonComplexQueryParamGet", - "MandatoryRequestHeaderGet", - "MergePatchJsonGet", - "MultigetGet", - "MultipleAuthSchemeGet", - "OneOfGet", - "OverrideServerGet", - "ParamgetGet", - "ReadonlyAuthSchemeGet", - "RegisterCallbackPost", - "RequiredOctetStreamPut", - "ResponsesWithHeadersGet", - "Rfc7807Get", - "UntypedPropertyGet", - "UuidGet", - "XmlExtraPost", - "XmlOtherPost", - "XmlOtherPut", - "XmlPost", - "XmlPut", - "CreateRepo", - "GetRepoInfo", - ]) + .value_parser(Vec::<&str>::from([ + "AnyOfGet", + "ComplexQueryParamGet", + "JsonComplexQueryParamGet", + "MergePatchJsonGet", + "MultigetGet", + "MultipleAuthSchemeGet", + "OneOfGet", + "OverrideServerGet", + "ParamgetGet", + "ReadonlyAuthSchemeGet", + "RequiredOctetStreamPut", + "ResponsesWithHeadersGet", + "Rfc7807Get", + "UntypedPropertyGet", + "UuidGet", + "XmlExtraPost", + "XmlOtherPost", + "XmlOtherPut", + "XmlPost", + "XmlPut", + "EnumInPathPathParamGet", + "CreateRepo", + ])) .required(true) .index(1)) - .arg(Arg::with_name("https") + .arg(Arg::new("https") .long("https") .help("Whether to use HTTPS or not")) - .arg(Arg::with_name("host") + .arg(Arg::new("host") .long("host") - .takes_value(true) .default_value("localhost") .help("Hostname to contact")) - .arg(Arg::with_name("port") + .arg(Arg::new("port") .long("port") - .takes_value(true) .default_value("8080") .help("Port to contact")) .get_matches(); @@ -107,50 +102,66 @@ fn main() { // In a real (production) system this Bearer token should be obtained via an external Identity/Authentication-server // Ensure that you set the correct algorithm and encodingkey that matches what is used on the server side. // See https://github.com/Keats/jsonwebtoken for more information - let auth_token = build_token( Claims { - sub: "tester@acme.com".to_owned(), + sub: "tester@acme.com".to_owned(), company: "ACME".to_owned(), iss: "my_identity_provider".to_owned(), // added a very long expiry time aud: "org.acme.Resource_Server".to_string(), exp: 10000000000, // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ + scopes: + [ "test.read", "test.write", - ].join(", ") - }, + ].join::<&str>(", ") + }, b"secret").unwrap(); let auth_data = if !auth_token.is_empty() { - Some(AuthData::Bearer(swagger::auth::Bearer { token: auth_token})) + Some(AuthData::Bearer(auth_token)) } else { // No Bearer-token available, so return None None }; - let is_https = matches.is_present("https"); + let is_https = matches.contains_id("https"); let base_url = format!("{}://{}:{}", if is_https { "https" } else { "http" }, - matches.value_of("host").unwrap(), - matches.value_of("port").unwrap()); + matches.get_one::("host").unwrap(), + matches.get_one::("port").unwrap()); let context: ClientContext = swagger::make_context!(ContextBuilder, EmptyContext, auth_data, XSpanIdString::default()); - let mut client : Box> = if matches.is_present("https") { - // Using Simple HTTPS - let client = Box::new(Client::try_new_https(&base_url) - .expect("Failed to create HTTPS client")); - Box::new(client.with_context(context)) - } else { - // Using HTTP - let client = Box::new(Client::try_new_http( - &base_url) - .expect("Failed to create HTTP client")); - Box::new(client.with_context(context)) + let mut client : Box> = { + #[cfg(feature = "client-tls")] + { + if is_https { + // Using HTTPS with native-tls + let client = Box::new(Client::try_new_https(&base_url) + .expect("Failed to create HTTPS client")); + Box::new(client.with_context(context)) + } else { + // Using HTTP + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } + } + + #[cfg(not(feature = "client-tls"))] + { + if is_https { + panic!("HTTPS requested but TLS support not enabled. \ + Enable the 'client-tls' feature to use HTTPS."); + } + // Using HTTP only + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } }; let mut rt = tokio::runtime::Runtime::new().unwrap(); @@ -158,45 +169,41 @@ fn main() { // We could do HTTPS here, but for simplicity we don't rt.spawn(server::create("127.0.0.1:8081", false)); - match matches.value_of("operation") { + match matches.get_one::("operation").map(String::as_str) { Some("AnyOfGet") => { let result = rt.block_on(client.any_of_get( Some(&Vec::new()) )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, + /* Disabled because there's no example. Some("CallbackWithHeaderPost") => { let result = rt.block_on(client.callback_with_header_post( - "url_example".to_string() + ??? )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, + */ Some("ComplexQueryParamGet") => { let result = rt.block_on(client.complex_query_param_get( Some(&Vec::new()) )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, - /* Disabled because there's no example. - Some("EnumInPathPathParamGet") => { - let result = rt.block_on(client.enum_in_path_path_param_get( - ??? - )); - info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); - }, - */ Some("JsonComplexQueryParamGet") => { let result = rt.block_on(client.json_complex_query_param_get( Some(&Vec::new()) )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, + /* Disabled because there's no example. Some("MandatoryRequestHeaderGet") => { let result = rt.block_on(client.mandatory_request_header_get( - "x_header_example".to_string() + ??? )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, + */ Some("MergePatchJsonGet") => { let result = rt.block_on(client.merge_patch_json_get( )); @@ -224,7 +231,7 @@ fn main() { }, Some("ParamgetGet") => { let result = rt.block_on(client.paramget_get( - Some(serde_json::from_str::(r#"38400000-8cf0-11bd-b23e-10b96e4ef00d"#).expect("Failed to parse JSON example")), + None, None, None )); @@ -235,12 +242,14 @@ fn main() { )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, + /* Disabled because there's no example. Some("RegisterCallbackPost") => { let result = rt.block_on(client.register_callback_post( - "url_example".to_string() + ??? )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, + */ Some("RequiredOctetStreamPut") => { let result = rt.block_on(client.required_octet_stream_put( swagger::ByteArray(Vec::from("BYTE_ARRAY_DATA_HERE")) @@ -298,18 +307,26 @@ fn main() { )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, + Some("EnumInPathPathParamGet") => { + let result = rt.block_on(client.enum_in_path_path_param_get( + models::StringEnum::Foo + )); + info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); + }, Some("CreateRepo") => { let result = rt.block_on(client.create_repo( serde_json::from_str::(r#"{"requiredParam":true}"#).expect("Failed to parse JSON example") )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, + /* Disabled because there's no example. Some("GetRepoInfo") => { let result = rt.block_on(client.get_repo_info( - "repo_id_example".to_string() + ??? )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, + */ _ => { panic!("Invalid operation provided") } diff --git a/samples/server/petstore/rust-server/output/openapi-v3/examples/client/server.rs b/samples/server/petstore/rust-server/output/openapi-v3/examples/client/server.rs index 96694d1ad85b..417f3408b577 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/examples/client/server.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/examples/client/server.rs @@ -4,8 +4,9 @@ use async_trait::async_trait; use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt}; -use hyper::server::conn::Http; -use hyper::service::Service; +use hyper::server::conn::http1; +use hyper_util::rt::TokioIo; +use hyper::service::{service_fn, Service}; use log::info; use std::future::Future; use std::marker::PhantomData; @@ -24,15 +25,13 @@ use openapi_v3::models; /// Builds an SSL implementation for Simple HTTPS from some hard-coded file names pub async fn create(addr: &str, https: bool) { - let addr = addr.parse().expect("Failed to parse bind address"); + let addr: SocketAddr = addr.parse().expect("Failed to parse bind address"); + let listener = TcpListener::bind(&addr).await.unwrap(); let server = Server::new(); let service = MakeService::new(server); - - // This pushes a fourth layer of the middleware-stack even though Swagger assumes only three levels. - // This fourth layer creates an accept-all policy, hower the example-code already acchieves the same via a Bearer-token with full permissions, so next line is not needed (anymore). - // let service = MakeAllowAllAuthenticator::new(service, "cosmo"); + let service = MakeAllowAllAuthenticator::new(service, "cosmo"); #[allow(unused_mut)] let mut service = @@ -56,21 +55,19 @@ pub async fn create(addr: &str, https: bool) { ssl.check_private_key().expect("Failed to check private key"); let tls_acceptor = ssl.build(); - let tcp_listener = TcpListener::bind(&addr).await.unwrap(); info!("Starting a server (with https)"); loop { - if let Ok((tcp, _)) = tcp_listener.accept().await { + if let Ok((tcp, addr)) = listener.accept().await { let ssl = Ssl::new(tls_acceptor.context()).unwrap(); - let addr = tcp.peer_addr().expect("Unable to get remote address"); let service = service.call(addr); tokio::spawn(async move { let tls = tokio_openssl::SslStream::new(ssl, tcp).map_err(|_| ())?; let service = service.await.map_err(|_| ())?; - Http::new() - .serve_connection(tls, service) + http1::Builder::new() + .serve_connection(TokioIo::new(tls), service) .await .map_err(|_| ()) }); @@ -79,12 +76,40 @@ pub async fn create(addr: &str, https: bool) { } } else { info!("Starting a server (over http, so no TLS)"); - // Using HTTP - hyper::server::Server::bind(&addr).serve(service).await.unwrap() + println!("Listening on http://{}", addr); + + loop { + // When an incoming TCP connection is received grab a TCP stream for + // client<->server communication. + // + // Note, this is a .await point, this loop will loop forever but is not a busy loop. The + // .await point allows the Tokio runtime to pull the task off of the thread until the task + // has work to do. In this case, a connection arrives on the port we are listening on and + // the task is woken up, at which point the task is then put back on a thread, and is + // driven forward by the runtime, eventually yielding a TCP stream. + let (tcp_stream, addr) = listener.accept().await.expect("Failed to accept connection"); + + let service = service.call(addr).await.unwrap(); + let io = TokioIo::new(tcp_stream); + // Spin up a new task in Tokio so we can continue to listen for new TCP connection on the + // current task without waiting for the processing of the HTTP1 connection we just received + // to finish + tokio::task::spawn(async move { + // Handle the connection from the client using HTTP1 and pass any + // HTTP requests received on that connection to the `hello` function + let result = http1::Builder::new() + .serve_connection(io, service) + .await; + if let Err(err) = result + { + println!("Error serving connection: {err:?}"); + } + }); + } } } -#[derive(Copy, Clone)] +#[derive(Copy)] pub struct Server { marker: PhantomData, } @@ -95,6 +120,14 @@ impl Server { } } +impl Clone for Server { + fn clone(&self) -> Self { + Self { + marker: PhantomData, + } + } +} + use openapi_v3::CallbackApi; use openapi_v3::CallbackCallbackWithHeaderPostResponse; use openapi_v3::CallbackCallbackPostResponse; diff --git a/samples/server/petstore/rust-server/output/openapi-v3/examples/server/main.rs b/samples/server/petstore/rust-server/output/openapi-v3/examples/server/main.rs index 08af24903e54..65a3a706bb43 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/examples/server/main.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/examples/server/main.rs @@ -3,26 +3,26 @@ #![allow(missing_docs)] - -use clap::{App, Arg}; +use clap::{Arg, Command}; mod server; mod server_auth; - /// Create custom server, wire it to the autogenerated router, /// and pass it to the web server. #[tokio::main] async fn main() { env_logger::init(); - let matches = App::new("server") - .arg(Arg::with_name("https") - .long("https") - .help("Whether to use HTTPS or not")) + let matches = Command::new("server") + .arg( + Arg::new("https") + .long("https") + .help("Whether to use HTTPS or not"), + ) .get_matches(); let addr = "127.0.0.1:8080"; - server::create(addr, matches.is_present("https")).await; + server::create(addr, matches.contains_id("https")).await; } diff --git a/samples/server/petstore/rust-server/output/openapi-v3/examples/server/server.rs b/samples/server/petstore/rust-server/output/openapi-v3/examples/server/server.rs index 63706763819e..6b3a673c990a 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/examples/server/server.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/examples/server/server.rs @@ -4,8 +4,9 @@ use async_trait::async_trait; use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt}; -use hyper::server::conn::Http; -use hyper::service::Service; +use hyper::server::conn::http1; +use hyper_util::rt::TokioIo; +use hyper::service::{service_fn, Service}; use log::info; use std::future::Future; use std::marker::PhantomData; @@ -24,15 +25,13 @@ use openapi_v3::models; /// Builds an SSL implementation for Simple HTTPS from some hard-coded file names pub async fn create(addr: &str, https: bool) { - let addr = addr.parse().expect("Failed to parse bind address"); + let addr: SocketAddr = addr.parse().expect("Failed to parse bind address"); + let listener = TcpListener::bind(&addr).await.unwrap(); let server = Server::new(); let service = MakeService::new(server); - - // This pushes a fourth layer of the middleware-stack even though Swagger assumes only three levels. - // This fourth layer creates an accept-all policy, hower the example-code already acchieves the same via a Bearer-token with full permissions, so next line is not needed (anymore). - // let service = MakeAllowAllAuthenticator::new(service, "cosmo"); + let service = MakeAllowAllAuthenticator::new(service, "cosmo"); #[allow(unused_mut)] let mut service = @@ -56,21 +55,19 @@ pub async fn create(addr: &str, https: bool) { ssl.check_private_key().expect("Failed to check private key"); let tls_acceptor = ssl.build(); - let tcp_listener = TcpListener::bind(&addr).await.unwrap(); info!("Starting a server (with https)"); loop { - if let Ok((tcp, _)) = tcp_listener.accept().await { + if let Ok((tcp, addr)) = listener.accept().await { let ssl = Ssl::new(tls_acceptor.context()).unwrap(); - let addr = tcp.peer_addr().expect("Unable to get remote address"); let service = service.call(addr); tokio::spawn(async move { let tls = tokio_openssl::SslStream::new(ssl, tcp).map_err(|_| ())?; let service = service.await.map_err(|_| ())?; - Http::new() - .serve_connection(tls, service) + http1::Builder::new() + .serve_connection(TokioIo::new(tls), service) .await .map_err(|_| ()) }); @@ -79,12 +76,40 @@ pub async fn create(addr: &str, https: bool) { } } else { info!("Starting a server (over http, so no TLS)"); - // Using HTTP - hyper::server::Server::bind(&addr).serve(service).await.unwrap() + println!("Listening on http://{}", addr); + + loop { + // When an incoming TCP connection is received grab a TCP stream for + // client<->server communication. + // + // Note, this is a .await point, this loop will loop forever but is not a busy loop. The + // .await point allows the Tokio runtime to pull the task off of the thread until the task + // has work to do. In this case, a connection arrives on the port we are listening on and + // the task is woken up, at which point the task is then put back on a thread, and is + // driven forward by the runtime, eventually yielding a TCP stream. + let (tcp_stream, addr) = listener.accept().await.expect("Failed to accept connection"); + + let service = service.call(addr).await.unwrap(); + let io = TokioIo::new(tcp_stream); + // Spin up a new task in Tokio so we can continue to listen for new TCP connection on the + // current task without waiting for the processing of the HTTP1 connection we just received + // to finish + tokio::task::spawn(async move { + // Handle the connection from the client using HTTP1 and pass any + // HTTP requests received on that connection to the `hello` function + let result = http1::Builder::new() + .serve_connection(io, service) + .await; + if let Err(err) = result + { + println!("Error serving connection: {err:?}"); + } + }); + } } } -#[derive(Copy, Clone)] +#[derive(Copy)] pub struct Server { marker: PhantomData, } @@ -95,6 +120,14 @@ impl Server { } } +impl Clone for Server { + fn clone(&self) -> Self { + Self { + marker: PhantomData, + } + } +} + use jsonwebtoken::{decode, encode, errors::Error as JwtError, Algorithm, DecodingKey, EncodingKey, Header, TokenData, Validation}; use serde::{Deserialize, Serialize}; @@ -107,7 +140,6 @@ use openapi_v3::{ AnyOfGetResponse, CallbackWithHeaderPostResponse, ComplexQueryParamGetResponse, - EnumInPathPathParamGetResponse, JsonComplexQueryParamGetResponse, MandatoryRequestHeaderGetResponse, MergePatchJsonGetResponse, @@ -128,6 +160,7 @@ use openapi_v3::{ XmlOtherPutResponse, XmlPostResponse, XmlPutResponse, + EnumInPathPathParamGetResponse, CreateRepoResponse, GetRepoInfoResponse, }; @@ -138,9 +171,9 @@ use swagger::ApiError; #[async_trait] impl Api for Server where C: Has + Send + Sync { - async fn any_of_get( + async fn any_of_get<'a>( &self, - any_of: Option<&Vec>, + any_of: Option<&'a Vec>, context: &C) -> Result { info!("any_of_get({:?}) - X-Span-ID: {:?}", any_of, context.get().0.clone()); @@ -156,27 +189,18 @@ impl Api for Server where C: Has + Send + Sync Err(ApiError("Api-Error: Operation is NOT implemented".into())) } - async fn complex_query_param_get( + async fn complex_query_param_get<'a>( &self, - list_of_strings: Option<&Vec>, + list_of_strings: Option<&'a Vec>, context: &C) -> Result { info!("complex_query_param_get({:?}) - X-Span-ID: {:?}", list_of_strings, context.get().0.clone()); Err(ApiError("Api-Error: Operation is NOT implemented".into())) } - async fn enum_in_path_path_param_get( + async fn json_complex_query_param_get<'a>( &self, - path_param: models::StringEnum, - context: &C) -> Result - { - info!("enum_in_path_path_param_get({:?}) - X-Span-ID: {:?}", path_param, context.get().0.clone()); - Err(ApiError("Api-Error: Operation is NOT implemented".into())) - } - - async fn json_complex_query_param_get( - &self, - list_of_strings: Option<&Vec>, + list_of_strings: Option<&'a Vec>, context: &C) -> Result { info!("json_complex_query_param_get({:?}) - X-Span-ID: {:?}", list_of_strings, context.get().0.clone()); @@ -350,6 +374,15 @@ impl Api for Server where C: Has + Send + Sync Err(ApiError("Api-Error: Operation is NOT implemented".into())) } + async fn enum_in_path_path_param_get( + &self, + path_param: models::StringEnum, + context: &C) -> Result + { + info!("enum_in_path_path_param_get({:?}) - X-Span-ID: {:?}", path_param, context.get().0.clone()); + Err(ApiError("Api-Error: Operation is NOT implemented".into())) + } + async fn create_repo( &self, object_param: models::ObjectParam, diff --git a/samples/server/petstore/rust-server/output/openapi-v3/examples/server/server_auth.rs b/samples/server/petstore/rust-server/output/openapi-v3/examples/server/server_auth.rs index 7f486733588d..bdaacda67702 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/examples/server/server_auth.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/examples/server/server_auth.rs @@ -1,8 +1,8 @@ use swagger::{ ApiError, - auth::{Basic, Bearer}, - Has, + Has, XSpanIdString}; +use headers::authorization::{Basic, Bearer}; use openapi_v3::{AuthenticationApi, Claims}; use crate::server::Server; use jsonwebtoken::{decode, errors as JwtError, decode_header, DecodingKey, TokenData, Validation}; @@ -15,26 +15,27 @@ use log::{error, debug}; /// Get a dummy claim with full permissions (all scopes) for testing purposes fn full_permission_claim() -> Claims { - Claims { - sub: "tester@acme.com".to_owned(), - company: "ACME".to_owned(), - iss: "mini-bank-IDP".to_owned(), - aud: "org.acme.Resource_Server".to_string(), - // added a very long expiry time - exp: 10000000000, - // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ - "test.read", - "test.write", - ].join(", ") - } + // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. + Claims { + sub: "tester@acme.com".to_owned(), + company: "ACME".to_owned(), + iss: "mini-bank-IDP".to_owned(), + aud: "org.acme.Resource_Server".to_string(), + // added a very long expiry time + exp: 10000000000, + scopes: + [ + "test.read", + "test.write", + ].join::<&str>(", ") + } } -/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. +/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. fn extract_token_data(token: &str, key: &[u8]) -> Result, JwtError::Error> { - + // Ensure that you set the correct algorithm and correct key. // See https://github.com/Keats/jsonwebtoken for more information. let header = decode_header(token)?; @@ -65,8 +66,8 @@ fn build_authorization(claims: Claims) -> Authorization { let scopes = swagger::auth::Scopes::Some(scopes); Authorization{ - subject: claims.sub, - scopes, + subject: claims.sub, + scopes, issuer: Some(claims.iss)} } @@ -89,7 +90,7 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn bearer_authorization(&self, bearer: &Bearer) -> Result { debug!("\tAuthorizationApi: Received Bearer-token, {bearer:#?}"); - match extract_token_data(&bearer.token, b"secret") { + match extract_token_data(&bearer.token(), b"secret") { Ok(auth_data) => { debug!("\tUnpack auth_data as: {auth_data:#?}"); let authorization = build_authorization(auth_data.claims); @@ -107,23 +108,22 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn apikey_authorization(&self, api_key: &str) -> Result { debug!("\tAuthorizationApi: Received api-key, {api_key:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } - + /// Implementation of the method to map a basic authentication (username and password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result { debug!("\tAuthorizationApi: Received Basic-token, {basic:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } -} - +} diff --git a/samples/server/petstore/rust-server/output/openapi-v3/src/auth.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/auth.rs index cbaba3dca7c6..a6a39f79450f 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/auth.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/auth.rs @@ -1,8 +1,7 @@ use std::collections::BTreeSet; -use crate::server::Authorization; use serde::{Deserialize, Serialize}; -use swagger::{ApiError, auth::{Basic, Bearer}}; - +use swagger::{ApiError, auth::Authorization}; +use headers::authorization::{Basic, Bearer}; #[derive(Debug, Serialize, Deserialize)] pub struct Claims { pub sub: String, @@ -24,7 +23,7 @@ pub trait AuthenticationApi { /// Method should be implemented (see example-code) to map Basic (Username:password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result; -} +} // Implement it for AllowAllAuthenticator (dummy is needed, but should not used as we have Bearer authorization) use swagger::auth::{AllowAllAuthenticator, RcBound, Scopes}; @@ -34,7 +33,7 @@ fn dummy_authorization() -> Authorization { // However, if you want to use it anyway this can not be unimplemented, so dummy implementation added. // unimplemented!() Authorization{ - subject: "Dummmy".to_owned(), + subject: "Dummy".to_owned(), scopes: Scopes::Some(BTreeSet::new()), // create an empty scope, as this should not be used issuer: None } diff --git a/samples/server/petstore/rust-server/output/openapi-v3/src/client/callbacks.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/client/callbacks.rs index 172d284a43c6..fdfb3c8dd62d 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/client/callbacks.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/client/callbacks.rs @@ -1,10 +1,14 @@ +use bytes::Bytes; use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt}; -use hyper::{Request, Response, StatusCode, Body, HeaderMap}; +use http_body_util::{combinators::BoxBody, Full}; +use hyper::{body::{Body, Incoming}, HeaderMap, Request, Response, StatusCode}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; use log::warn; +#[cfg(feature = "validate")] +use serde_valid::Validate; #[allow(unused_imports)] use std::convert::{TryFrom, TryInto}; -use std::error::Error; +use std::{convert::Infallible, error::Error}; use std::future::Future; use std::marker::PhantomData; use std::task::{Context, Poll}; @@ -18,7 +22,7 @@ use crate::{models, header, AuthenticationApi}; pub use crate::context; -type ServiceFuture = BoxFuture<'static, Result, crate::ServiceError>>; +type ServiceFuture = BoxFuture<'static, Result>, crate::ServiceError>>; use crate::CallbackApi as Api; use crate::CallbackCallbackWithHeaderPostResponse; @@ -52,28 +56,52 @@ mod paths { -pub struct MakeService where +pub struct MakeService +where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { api_impl: T, marker: PhantomData, + validation: bool } -impl MakeService where +impl MakeService +where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { pub fn new(api_impl: T) -> Self { MakeService { api_impl, - marker: PhantomData + marker: PhantomData, + validation: false } } + + // Turn on/off validation for the service being made. + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation; + } } +impl Clone for MakeService +where + T: Api + Clone + Send + 'static, + C: Has + Has> + Send + Sync + 'static +{ + fn clone(&self) -> Self { + Self { + api_impl: self.api_impl.clone(), + marker: PhantomData, + validation: self.validation + } + } +} -impl hyper::service::Service for MakeService where +impl hyper::service::Service for MakeService +where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { @@ -81,44 +109,73 @@ impl hyper::service::Service for MakeService where type Error = crate::ServiceError; type Future = future::Ready>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } + fn call(&self, target: Target) -> Self::Future { + let service = Service::new(self.api_impl.clone(), self.validation); - fn call(&mut self, target: Target) -> Self::Future { - future::ok(Service::new( - self.api_impl.clone(), - )) + future::ok(service) } } -fn method_not_allowed() -> Result, crate::ServiceError> { +fn method_not_allowed() -> Result>, crate::ServiceError> { Ok( Response::builder().status(StatusCode::METHOD_NOT_ALLOWED) - .body(Body::empty()) + .body(BoxBody::new(http_body_util::Empty::new())) .expect("Unable to create Method Not Allowed response") ) } +#[allow(unused_macros)] +#[cfg(not(feature = "validate"))] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => (); +} + +#[allow(unused_macros)] +#[cfg(feature = "validate")] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => { + let $parameter = if $validation { + match $parameter.validate() { + Ok(()) => $parameter, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .header(CONTENT_TYPE, mime::TEXT_PLAIN.as_ref()) + .body(BoxBody::new(format!("Invalid value in body parameter {}: {}", $base_name, e))) + .expect(&format!("Unable to create Bad Request response for invalid value in body parameter {}", $base_name))), + } + } else { + $parameter + }; + } +} + pub struct Service where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { api_impl: T, marker: PhantomData, + // Enable regex pattern validation of received JSON models + validation: bool, } impl Service where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { - pub fn new(api_impl: T) -> Self { + pub fn new(api_impl: T, validation: bool) -> Self { Service { api_impl, - marker: PhantomData + marker: PhantomData, + validation, } } + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation + } + } impl Clone for Service where @@ -129,32 +186,50 @@ impl Clone for Service where Service { api_impl: self.api_impl.clone(), marker: self.marker, + validation: self.validation, } } } -impl hyper::service::Service<(Request, C)> for Service where +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + +fn body_from_str(s: &str) -> BoxBody { + BoxBody::new(Full::new(Bytes::copy_from_slice(s.as_bytes()))) +} + +impl hyper::service::Service<(Request, C)> for Service where T: Api + Clone + Send + Sync + 'static, - C: Has + Has> + Send + Sync + 'static + C: Has + Has> + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, { - type Response = Response; + type Response = Response>; type Error = crate::ServiceError; type Future = ServiceFuture; - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - self.api_impl.poll_ready(cx) - } - - fn call(&mut self, req: (Request, C)) -> Self::Future { async fn run(mut api_impl: T, req: (Request, C)) -> Result, crate::ServiceError> where - T: Api + Clone + Send + 'static, - C: Has + Has> + Send + Sync + 'static - { - let (request, context) = req; - let (parts, body) = request.into_parts(); - let (method, uri, headers) = (parts.method, parts.uri, parts.headers); - let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); - - match method { + fn call(&self, req: (Request, C)) -> Self::Future { + async fn run( + mut api_impl: T, + req: (Request, C), + validation: bool, + ) -> Result>, crate::ServiceError> + where + T: Api + Clone + Send + 'static, + C: Has + Has> + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, + { + let (request, context) = req; + let (parts, body) = request.into_parts(); + let (method, uri, headers) = (parts.method, parts.uri, parts.headers); + let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); + + match method { // CallbackCallbackWithHeaderPost - POST /{$request.query.url}/callback-with-header hyper::Method::POST if path.matched(paths::ID_REQUEST_QUERY_URL_CALLBACK_WITH_HEADER) => { @@ -178,7 +253,7 @@ impl hyper::service::Service<(Request, C)> for Service where Err(err) => { return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Invalid header Information - {}", err))) + .body(body_from_string(format!("Invalid header Information - {err}"))) .expect("Unable to create Bad Request response for invalid header Information")); }, @@ -193,7 +268,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_information, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -204,13 +279,14 @@ impl hyper::service::Service<(Request, C)> for Service where CallbackCallbackWithHeaderPostResponse::OK => { *response.status_mut() = StatusCode::from_u16(204).expect("Unable to turn 204 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -233,7 +309,7 @@ impl hyper::service::Service<(Request, C)> for Service where callback_request_query_url, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -244,13 +320,14 @@ impl hyper::service::Service<(Request, C)> for Service where CallbackCallbackPostResponse::OK => { *response.status_mut() = StatusCode::from_u16(204).expect("Unable to turn 204 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -259,11 +336,17 @@ impl hyper::service::Service<(Request, C)> for Service where _ if path.matched(paths::ID_REQUEST_QUERY_URL_CALLBACK) => method_not_allowed(), _ if path.matched(paths::ID_REQUEST_QUERY_URL_CALLBACK_WITH_HEADER) => method_not_allowed(), - _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) - .body(Body::empty()) - .expect("Unable to create Not Found response")) + _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) + .body(BoxBody::new(http_body_util::Empty::new())) + .expect("Unable to create Not Found response")) + } } - } Box::pin(run(self.api_impl.clone(), req)) } + Box::pin(run( + self.api_impl.clone(), + req, + self.validation + )) + } } /// Request parser for `Api`. diff --git a/samples/server/petstore/rust-server/output/openapi-v3/src/client/mod.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/client/mod.rs index b71408c2422f..0adfab96588c 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/client/mod.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/client/mod.rs @@ -1,10 +1,12 @@ use async_trait::async_trait; +use bytes::Bytes; use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt}; +use http_body_util::{combinators::BoxBody, Full}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; -use hyper::{Body, Request, Response, service::Service, Uri}; +use hyper::{body::{Body, Incoming}, Request, Response, service::Service, Uri}; use percent_encoding::{utf8_percent_encode, AsciiSet}; use std::borrow::Cow; -use std::convert::TryInto; +use std::convert::{TryInto, Infallible}; use std::io::{ErrorKind, Read}; use std::error::Error; use std::future::Future; @@ -18,6 +20,7 @@ use std::string::ToString; use std::task::{Context, Poll}; use swagger::{ApiError, AuthData, BodyExt, Connector, DropContextService, Has, XSpanIdString}; use url::form_urlencoded; +use tower_service::Service as _; use crate::models; @@ -39,7 +42,6 @@ use crate::{Api, AnyOfGetResponse, CallbackWithHeaderPostResponse, ComplexQueryParamGetResponse, - EnumInPathPathParamGetResponse, JsonComplexQueryParamGetResponse, MandatoryRequestHeaderGetResponse, MergePatchJsonGetResponse, @@ -60,6 +62,7 @@ use crate::{Api, XmlOtherPutResponse, XmlPostResponse, XmlPutResponse, + EnumInPathPathParamGetResponse, CreateRepoResponse, GetRepoInfoResponse }; @@ -81,15 +84,14 @@ fn into_base_path(input: impl TryInto, } let host = uri.host().ok_or(ClientInitError::MissingHost)?; - let port = uri.port_u16().map(|x| format!(":{}", x)).unwrap_or_default(); - Ok(format!("{}://{}{}{}", scheme, host, port, uri.path().trim_end_matches('/'))) + let port = uri.port_u16().map(|x| format!(":{x}")).unwrap_or_default(); + Ok(format!("{scheme}://{host}{port}{}", uri.path().trim_end_matches('/'))) } /// A client that implements the API by making HTTP calls out to a server. pub struct Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -106,8 +108,7 @@ pub struct Client where impl fmt::Debug for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -119,8 +120,7 @@ impl fmt::Debug for Client where impl Clone for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -134,8 +134,19 @@ impl Clone for Client where } } -impl Client, C>, C> where - Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static, +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + Connector, + BoxBody + > + >, + C + >, + C +> where + Connector: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static, C: Clone + Send + Sync + 'static, { /// Create a client with a custom implementation of hyper::client::Connect. @@ -149,7 +160,7 @@ impl Client" /// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")` /// * `connector` - Implementation of `hyper::client::Connect` to use for the client pub fn try_new_with_connector( @@ -158,8 +169,8 @@ impl Client Result { - let client_service = hyper::client::Client::builder().build(connector); - let client_service = DropContextService::new(client_service); + let client_service = hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector); + let client_service = DropContextService::new(hyper_util::service::TowerToHyperService::new(client_service)); Ok(Self { client_service, @@ -169,28 +180,29 @@ impl Client; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HyperHttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + #[derive(Debug, Clone)] pub enum HyperClient { - Http(hyper::client::Client), - Https(hyper::client::Client), + Http(hyper_util::client::legacy::Client>), + #[cfg(feature = "client-tls")] + Https(hyper_util::client::legacy::Client>), } -impl Service> for HyperClient { - type Response = Response; - type Error = hyper::Error; - type Future = hyper::client::ResponseFuture; - - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - match self { - HyperClient::Http(client) => client.poll_ready(cx), - HyperClient::Https(client) => client.poll_ready(cx), - } - } +impl Service>> for HyperClient { + type Response = Response; + type Error = hyper_util::client::legacy::Error; + type Future = hyper_util::client::legacy::ResponseFuture; - fn call(&mut self, req: Request) -> Self::Future { + fn call(&self, req: Request>) -> Self::Future { match self { - HyperClient::Http(client) => client.call(req), - HyperClient::Https(client) => client.call(req) + HyperClient::Http(client) => client.request(req), + #[cfg(feature = "client-tls")] + HyperClient::Https(client) => client.request(req), } } } @@ -201,7 +213,7 @@ impl Client, C> where /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new( base_path: &str, ) -> Result { @@ -214,13 +226,19 @@ impl Client, C> where let client_service = match scheme.as_str() { "http" => { - HyperClient::Http(hyper::client::Client::builder().build(connector.build())) + HyperClient::Http(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector.build())) + }, + #[cfg(feature = "client-tls")] + "https" => { + let https_connector = connector + .https() + .build() + .map_err(ClientInitError::SslError)?; + HyperClient::Https(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(https_connector)) }, + #[cfg(not(feature = "client-tls"))] "https" => { - let connector = connector.https() - .build() - .map_err(ClientInitError::SslError)?; - HyperClient::Https(hyper::client::Client::builder().build(connector)) + return Err(ClientInitError::TlsNotEnabled); }, _ => { return Err(ClientInitError::InvalidScheme); @@ -237,13 +255,24 @@ impl Client, C> where } } -impl Client, C>, C> where +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + hyper_util::client::legacy::connect::HttpConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new_http( base_path: &str, ) -> Result { @@ -253,19 +282,32 @@ impl Client; - -#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] -type HttpsConnector = hyper_openssl::HttpsConnector; - -impl Client, C>, C> where +#[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] +type HttpsConnector = hyper_tls::HttpsConnector; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + +#[cfg(feature = "client-tls")] +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + HttpsConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { - /// Create a client with a TLS connection to the server + /// Create a client with a TLS connection to the server. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] pub fn try_new_https(base_path: &str) -> Result { let https_connector = Connector::builder() @@ -275,10 +317,24 @@ impl Client, C Self::try_new_with_connector(base_path, Some("https"), https_connector) } - /// Create a client with a TLS connection to the server using a pinned certificate + /// Create a client with a TLS connection to the server using OpenSSL via swagger. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] + pub fn try_new_https(base_path: &str) -> Result + { + let https_connector = Connector::builder() + .https() + .build() + .map_err(ClientInitError::SslError)?; + Self::try_new_with_connector(base_path, Some("https"), https_connector) + } + + /// Create a client with a TLS connection to the server using a pinned certificate. + /// + /// # Arguments + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn try_new_https_pinned( @@ -299,7 +355,7 @@ impl Client, C /// Create a client with a mutually authenticated TLS connection to the server. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server /// * `client_key` - Path to the client private key /// * `client_certificate` - Path to the client's public certificate associated with the private key @@ -327,8 +383,7 @@ impl Client, C impl Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -362,12 +417,15 @@ pub enum ClientInitError { /// Missing Hostname MissingHost, + /// HTTPS requested but TLS features not enabled + TlsNotEnabled, + /// SSL Connection Error - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + #[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] SslError(native_tls::Error), /// SSL Connection Error - #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] SslError(openssl::error::ErrorStack), } @@ -390,29 +448,32 @@ impl Error for ClientInitError { } } +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + #[async_trait] -impl Api for Client where +impl Api for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C), + Response=Response> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Has + Has> + Clone + Send + Sync + 'static, + B: hyper::body::Body + Send + 'static + Unpin, + B::Data: Send, + B::Error: Into>, { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - match self.client_service.clone().poll_ready(cx) { - Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())), - Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)), - Poll::Pending => Poll::Pending, - } - } - async fn any_of_get( + #[allow(clippy::vec_init_then_push)] + async fn any_of_get<'a>( &self, - param_any_of: Option<&Vec>, + param_any_of: Option<&'a Vec>, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/any-of", self.base_path @@ -434,95 +495,104 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(AnyOfGetResponse::Success (body) ) } 201 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(AnyOfGetResponse::AlternateSuccess (body) ) } 202 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(AnyOfGetResponse::AnyOfSuccess (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn callback_with_header_post( &self, param_url: String, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/callback-with-header", self.base_path @@ -542,25 +612,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 204 => { @@ -570,30 +640,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn complex_query_param_get( + #[allow(clippy::vec_init_then_push)] + async fn complex_query_param_get<'a>( &self, - param_list_of_strings: Option<&Vec>, + param_list_of_strings: Option<&'a Vec>, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/complex-query-param", self.base_path @@ -615,25 +685,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -643,100 +713,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn enum_in_path_path_param_get( + #[allow(clippy::vec_init_then_push)] + async fn json_complex_query_param_get<'a>( &self, - param_path_param: models::StringEnum, - context: &C) -> Result - { - let mut client_service = self.client_service.clone(); - let mut uri = format!( - "{}/enum_in_path/{path_param}", - self.base_path - ,path_param=utf8_percent_encode(¶m_path_param.to_string(), ID_ENCODE_SET) - ); - - // Query parameters - let query_string = { - let mut query_string = form_urlencoded::Serializer::new("".to_owned()); - query_string.finish() - }; - if !query_string.is_empty() { - uri += "?"; - uri += &query_string; - } - - let uri = match Uri::from_str(&uri) { - Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), - }; - - let mut request = match Request::builder() - .method("GET") - .uri(uri) - .body(Body::empty()) { - Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) - }; - - let header = HeaderValue::from_str(Has::::get(context).0.as_str()); - request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) - }); - - let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; - - match response.status().as_u16() { - 200 => { - Ok( - EnumInPathPathParamGetResponse::Success - ) - } - code => { - let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, - match body { - Ok(body) => match String::from_utf8(body) { - Ok(body) => body, - Err(e) => format!("", e), - }, - Err(e) => format!("", e), - } - ))) - } - } - } - - async fn json_complex_query_param_get( - &self, - param_list_of_strings: Option<&Vec>, + param_list_of_strings: Option<&'a Vec>, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/json-complex-query-param", self.base_path @@ -749,7 +749,7 @@ impl Api for Client where query_string.append_pair("list-of-strings", &match serde_json::to_string(¶m_list_of_strings) { Ok(str) => str, - Err(e) => return Err(ApiError(format!("Unable to serialize list_of_strings to string: {}", e))), + Err(e) => return Err(ApiError(format!("Unable to serialize list_of_strings to string: {e}"))), }); } query_string.finish() @@ -761,25 +761,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -789,30 +789,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn mandatory_request_header_get( &self, param_x_header: String, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/mandatory-request-header", self.base_path @@ -830,37 +830,37 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); // Header parameters request.headers_mut().append( HeaderName::from_static("x-header"), - #[allow(clippy::redundant_clone)] + #[allow(clippy::redundant_clone, clippy::clone_on_copy)] match header::IntoHeaderValue(param_x_header.clone()).try_into() { Ok(header) => header, Err(e) => { return Err(ApiError(format!( - "Invalid header x_header - {}", e))); + "Invalid header x_header - {e}"))); }, }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -870,29 +870,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn merge_patch_json_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/merge-patch-json", self.base_path @@ -910,66 +910,69 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(MergePatchJsonGetResponse::Merge (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn multiget_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/multiget", self.base_path @@ -987,145 +990,169 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(MultigetGetResponse::JSONRsp (body) ) } 201 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; // ToDo: this will move to swagger-rs and become a standard From conversion trait // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream let body = serde_xml_rs::from_str::(body) - .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?; + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(MultigetGetResponse::XMLRsp (body) ) } 202 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = swagger::ByteArray(body.to_vec()); + + Ok(MultigetGetResponse::OctetRsp (body) ) } 203 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; let body = body.to_string(); + + Ok(MultigetGetResponse::StringRsp (body) ) } 204 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(MultigetGetResponse::DuplicateResponseLongText (body) ) } 205 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(MultigetGetResponse::DuplicateResponseLongText_2 (body) ) } 206 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(MultigetGetResponse::DuplicateResponseLongText_3 (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn multiple_auth_scheme_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/multiple_auth_scheme", self.base_path @@ -1143,44 +1170,43 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); #[allow(clippy::collapsible_match)] if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported + use headers::authorization::Credentials; #[allow(clippy::single_match, clippy::match_single_binding)] match auth_data { - AuthData::Bearer(bearer_header) => { - let auth = swagger::auth::Header(bearer_header.clone()); - let header = match HeaderValue::from_str(&format!("{}", auth)) { + AuthData::Bearer(ref bearer_header) => { + let header = match headers::Authorization::bearer(&bearer_header.to_string()) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {e}"))) }; request.headers_mut().insert( hyper::header::AUTHORIZATION, - header); + header.0.encode()); }, _ => {} } } let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1190,29 +1216,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn one_of_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/one-of", self.base_path @@ -1230,66 +1256,69 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(OneOfGetResponse::Success (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn override_server_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/override/override-server", self.base_path @@ -1307,25 +1336,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 204 => { @@ -1335,24 +1364,23 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn paramget_get( &self, param_uuid: Option, @@ -1361,6 +1389,7 @@ impl Api for Client where context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/paramget", self.base_path @@ -1390,66 +1419,69 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(ParamgetGetResponse::JSONRsp (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn readonly_auth_scheme_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/readonly_auth_scheme", self.base_path @@ -1467,44 +1499,43 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); #[allow(clippy::collapsible_match)] if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported + use headers::authorization::Credentials; #[allow(clippy::single_match, clippy::match_single_binding)] match auth_data { - AuthData::Bearer(bearer_header) => { - let auth = swagger::auth::Header(bearer_header.clone()); - let header = match HeaderValue::from_str(&format!("{}", auth)) { + AuthData::Bearer(ref bearer_header) => { + let header = match headers::Authorization::bearer(&bearer_header.to_string()) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {e}"))) }; request.headers_mut().insert( hyper::header::AUTHORIZATION, - header); + header.0.encode()); }, _ => {} } } let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1514,30 +1545,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn register_callback_post( &self, param_url: String, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/register-callback", self.base_path @@ -1557,25 +1588,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 204 => { @@ -1585,30 +1616,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn required_octet_stream_put( &self, param_body: swagger::ByteArray, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/required_octet_stream", self.base_path @@ -1626,33 +1657,33 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("PUT") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let body = param_body.0; - *request.body_mut() = Body::from(body); + // Consumes basic body + // Body parameter + let body = String::from_utf8(param_body.0).expect("Body was not valid UTF8"); + *request.body_mut() = body_from_string(body); let header = "application/octet-stream"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1662,29 +1693,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn responses_with_headers_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/responses_with_headers", self.base_path @@ -1702,25 +1733,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1730,7 +1761,7 @@ impl Api for Client where let response_success_info = match TryInto::>::try_into(response_success_info) { Ok(value) => value, Err(e) => { - return Err(ApiError(format!("Invalid response header Success-Info for response 200 - {}", e))); + return Err(ApiError(format!("Invalid response header Success-Info for response 200 - {e}"))); }, }; response_success_info.0 @@ -1744,7 +1775,7 @@ impl Api for Client where let response_bool_header = match TryInto::>::try_into(response_bool_header) { Ok(value) => value, Err(e) => { - return Err(ApiError(format!("Invalid response header Bool-Header for response 200 - {}", e))); + return Err(ApiError(format!("Invalid response header Bool-Header for response 200 - {e}"))); }, }; Some(response_bool_header.0) @@ -1758,7 +1789,7 @@ impl Api for Client where let response_object_header = match TryInto::>::try_into(response_object_header) { Ok(value) => value, Err(e) => { - return Err(ApiError(format!("Invalid response header Object-Header for response 200 - {}", e))); + return Err(ApiError(format!("Invalid response header Object-Header for response 200 - {e}"))); }, }; Some(response_object_header.0) @@ -1767,14 +1798,17 @@ impl Api for Client where }; let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(ResponsesWithHeadersGetResponse::Success { body, @@ -1791,7 +1825,7 @@ impl Api for Client where let response_further_info = match TryInto::>::try_into(response_further_info) { Ok(value) => value, Err(e) => { - return Err(ApiError(format!("Invalid response header Further-Info for response 412 - {}", e))); + return Err(ApiError(format!("Invalid response header Further-Info for response 412 - {e}"))); }, }; Some(response_further_info.0) @@ -1805,7 +1839,7 @@ impl Api for Client where let response_failure_info = match TryInto::>::try_into(response_failure_info) { Ok(value) => value, Err(e) => { - return Err(ApiError(format!("Invalid response header Failure-Info for response 412 - {}", e))); + return Err(ApiError(format!("Invalid response header Failure-Info for response 412 - {e}"))); }, }; Some(response_failure_info.0) @@ -1823,29 +1857,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn rfc7807_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/rfc7807", self.base_path @@ -1863,96 +1897,106 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 204 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(Rfc7807GetResponse::OK (body) ) } 404 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(Rfc7807GetResponse::NotFound (body) ) } 406 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; // ToDo: this will move to swagger-rs and become a standard From conversion trait // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream let body = serde_xml_rs::from_str::(body) - .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?; + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(Rfc7807GetResponse::NotAcceptable (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn untyped_property_get( &self, param_object_untyped_props: Option, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/untyped_property", self.base_path @@ -1970,37 +2014,35 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let body = param_object_untyped_props.map(|ref body| { - serde_json::to_string(body).expect("impossible to fail to serialize") - }); - if let Some(body) = body { - *request.body_mut() = Body::from(body); + // Consumes basic body + // Body parameter + if let Some(param_object_untyped_props) = param_object_untyped_props { + let body = serde_json::to_string(¶m_object_untyped_props).expect("impossible to fail to serialize"); + *request.body_mut() = body_from_string(body); } let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2010,29 +2052,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn uuid_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/uuid", self.base_path @@ -2050,67 +2092,70 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(UuidGetResponse::DuplicateResponseLongText (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn xml_extra_post( &self, param_duplicate_xml_object: Option, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/xml_extra", self.base_path @@ -2128,37 +2173,35 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let body = param_duplicate_xml_object.map(|ref body| { - body.as_xml() - }); - if let Some(body) = body { - *request.body_mut() = Body::from(body); + // Consumes basic body + // Body parameter + if let Some(param_duplicate_xml_object) = param_duplicate_xml_object { + let body = param_duplicate_xml_object.as_xml(); + *request.body_mut() = body_from_string(body); } let header = "application/xml"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 201 => { @@ -2173,30 +2216,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn xml_other_post( &self, param_another_xml_object: Option, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/xml_other", self.base_path @@ -2214,50 +2257,52 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let body = param_another_xml_object.map(|ref body| { - body.as_xml() - }); - if let Some(body) = body { - *request.body_mut() = Body::from(body); + // Consumes basic body + // Body parameter + if let Some(param_another_xml_object) = param_another_xml_object { + let body = param_another_xml_object.as_xml(); + *request.body_mut() = body_from_string(body); } let header = "text/xml"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 201 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; // ToDo: this will move to swagger-rs and become a standard From conversion trait // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream let body = serde_xml_rs::from_str::(body) - .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?; + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(XmlOtherPostResponse::OK (body) ) @@ -2269,30 +2314,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn xml_other_put( &self, param_another_xml_array: Option, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/xml_other", self.base_path @@ -2310,37 +2355,35 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("PUT") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let body = param_another_xml_array.map(|ref body| { - body.as_xml() - }); - if let Some(body) = body { - *request.body_mut() = Body::from(body); + // Consumes basic body + // Body parameter + if let Some(param_another_xml_array) = param_another_xml_array { + let body = param_another_xml_array.as_xml(); + *request.body_mut() = body_from_string(body); } let header = "application/xml"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 201 => { @@ -2355,30 +2398,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn xml_post( &self, param_xml_array: Option, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/xml", self.base_path @@ -2396,37 +2439,35 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let body = param_xml_array.map(|ref body| { - body.as_xml() - }); - if let Some(body) = body { - *request.body_mut() = Body::from(body); + // Consumes basic body + // Body parameter + if let Some(param_xml_array) = param_xml_array { + let body = param_xml_array.as_xml(); + *request.body_mut() = body_from_string(body); } let header = "application/xml"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 201 => { @@ -2441,30 +2482,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn xml_put( &self, param_xml_object: Option, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/xml", self.base_path @@ -2482,39 +2523,35 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("PUT") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let body = param_xml_object.map(|ref body| { - body.as_xml() - }); - - if let Some(body) = body { - *request.body_mut() = Body::from(body); + // Consumes basic body + // Body parameter + if let Some(param_xml_object) = param_xml_object { + let body = param_xml_object.as_xml(); + *request.body_mut() = body_from_string(body); } let header = "application/xml"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 201 => { @@ -2529,30 +2566,100 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", + match body { + Ok(body) => match String::from_utf8(body) { + Ok(body) => body, + Err(e) => format!(""), + }, + Err(e) => format!("", Into::::into(e)), + } + ))) + } + } + } + + #[allow(clippy::vec_init_then_push)] + async fn enum_in_path_path_param_get( + &self, + param_path_param: models::StringEnum, + context: &C) -> Result + { + let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] + let mut uri = format!( + "{}/enum_in_path/{path_param}", + self.base_path + ,path_param=utf8_percent_encode(¶m_path_param.to_string(), ID_ENCODE_SET) + ); + + // Query parameters + let query_string = { + let mut query_string = form_urlencoded::Serializer::new("".to_owned()); + query_string.finish() + }; + if !query_string.is_empty() { + uri += "?"; + uri += &query_string; + } + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), + }; + + let mut request = match Request::builder() + .method("GET") + .uri(uri) + .body(BoxBody::new(http_body_util::Empty::new())) { + Ok(req) => req, + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) + }; + + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); + request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) + }); + + let response = client_service.call((request, context.clone())) + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; + + match response.status().as_u16() { + 200 => { + Ok( + EnumInPathPathParamGetResponse::Success + ) + } + code => { + let headers = response.headers().clone(); + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn create_repo( &self, param_object_param: models::ObjectParam, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/repos", self.base_path @@ -2570,34 +2677,33 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body // Body parameter let body = serde_json::to_string(¶m_object_param).expect("impossible to fail to serialize"); - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2607,30 +2713,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn get_repo_info( &self, param_repo_id: String, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/repos/{repo_id}", self.base_path @@ -2649,55 +2755,56 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(GetRepoInfoResponse::OK (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } diff --git a/samples/server/petstore/rust-server/output/openapi-v3/src/context.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/context.rs index e01187ca3c82..7a52731cc064 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/context.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/context.rs @@ -6,9 +6,9 @@ use std::default::Default; use std::io; use std::marker::PhantomData; use std::task::{Poll, Context}; -use swagger::auth::{AuthData, Authorization, Bearer, Scopes}; +use swagger::auth::{AuthData, Authorization, Scopes}; use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString}; -use crate::{Api, AuthenticationApi}; +use crate::Api; use log::error; pub struct MakeAddContext { @@ -16,11 +16,11 @@ pub struct MakeAddContext { marker: PhantomData, } -impl MakeAddContext +impl MakeAddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, + C: Send + 'static, { pub fn new(inner: T) -> MakeAddContext { MakeAddContext { @@ -30,27 +30,34 @@ where } } +impl Clone for MakeAddContext +where + T: Clone, +{ + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + // Make a service that adds context. -impl Service for +impl Service for MakeAddContext where Target: Send, A: Default + Push + Send, B: Push, Result = C>, - C: Push, Result = D>, - D: Send + 'static, + C: Send + 'static, T: Service + Send, T::Future: Send + 'static { type Error = T::Error; - type Response = AddContext; + type Response = AddContext; type Future = BoxFuture<'static, Result>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, target: Target) -> Self::Future { + fn call(&self, target: Target) -> Self::Future { let service = self.inner.call(target); Box::pin(async move { @@ -60,21 +67,17 @@ where } /// Middleware to add context data from the request -pub struct AddContext -where - A: Default + Push, - B: Push, Result = C>, - C: Push, Result = D> +#[derive(Debug, Clone)] +pub struct AddContext { inner: T, marker: PhantomData, } -impl AddContext +impl AddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, { pub fn new(inner: T) -> Self { AddContext { @@ -84,49 +87,32 @@ where } } -impl Service> for AddContext +impl Service> for AddContext where A: Default + Push, B: Push, Result=C>, - C: Push, Result=D>, - D: Send + 'static, - T: Service<(Request, D)> + AuthenticationApi + C: Send + 'static, + T: Service<(Request, C)> { type Error = T::Error; type Future = T::Future; type Response = T::Response; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - - fn call(&mut self, request: Request) -> Self::Future { + fn call(&self, request: Request) -> Self::Future { let context = A::default().push(XSpanIdString::get_or_generate(&request)); let headers = request.headers(); { - use swagger::auth::Bearer; + use headers::authorization::Bearer; use std::ops::Deref; - if let Some(bearer) = swagger::auth::from_headers::(headers) { - let authorization = self.inner.bearer_authorization(&bearer); - let auth_data = AuthData::Bearer(bearer); - - let context = context.push(Some(auth_data)); - let context = match authorization { - Ok(auth) => context.push(Some(auth)), - Err(err) => { - error!("Error during Authorization: {err:?}"); - context.push(None::) - } - }; + if let Some(bearer) = swagger::auth::from_headers(headers) { + let context = context.push(Some(bearer)); return self.inner.call((request, context)) } } let context = context.push(None::); - let context = context.push(None::); self.inner.call((request, context)) } diff --git a/samples/server/petstore/rust-server/output/openapi-v3/src/header.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/header.rs index 5bc6ebe929b9..823d2779b31f 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/header.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/header.rs @@ -31,11 +31,9 @@ macro_rules! ihv_generate { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse::<$t>() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse {} as a string: {}", - stringify!($t), e)), + Err(e) => Err(format!("Unable to parse {} as a string: {e}", stringify!($t))), }, - Err(e) => Err(format!("Unable to parse header {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header {hdr_value:?} as a string - {e}")), } } } @@ -76,8 +74,7 @@ impl TryFrom for IntoHeaderValue> { y => Some(y.to_string()), }) .collect())), - Err(e) => Err(format!("Unable to parse header: {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header: {hdr_value:?} as a string - {e}")), } } } @@ -88,8 +85,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(&hdr_value.0.join(", ")) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} into a header - {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} into a header - {e}")) } } } @@ -102,8 +98,7 @@ impl TryFrom for IntoHeaderValue { fn try_from(hdr_value: HeaderValue) -> Result { match hdr_value.to_str() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())), - Err(e) => Err(format!("Unable to convert header {:?} to {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to {e}")), } } } @@ -114,8 +109,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")) } } } @@ -128,11 +122,9 @@ impl TryFrom for IntoHeaderValue { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse bool from {} - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse bool from {hdr_value} - {e}")), }, - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")), } } } @@ -143,8 +135,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0.to_string()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert: {:?} into a header: {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert: {hdr_value:?} into a header: {e}")) } } } @@ -158,11 +149,9 @@ impl TryFrom for IntoHeaderValue> { match hdr_value.to_str() { Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) { Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))), - Err(e) => Err(format!("Unable to parse: {} as date - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse: {hdr_value} as date - {e}")), }, - Err(e) => Err(format!("Unable to convert header {:?} to string {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to string {e}")), } } } @@ -173,8 +162,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} to a header: {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} to a header: {e}")), } } } diff --git a/samples/server/petstore/rust-server/output/openapi-v3/src/lib.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/lib.rs index 02500e5701ea..0002f71cd1db 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/lib.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/lib.rs @@ -3,14 +3,15 @@ use async_trait::async_trait; use futures::Stream; +#[cfg(feature = "mock")] +use mockall::automock; use std::error::Error; use std::collections::BTreeSet; use std::task::{Poll, Context}; -use swagger::{ApiError, ContextWrapper}; +use swagger::{ApiError, ContextWrapper, auth::Authorization}; use serde::{Serialize, Deserialize}; -use crate::server::Authorization; - +#[cfg(any(feature = "client", feature = "server"))] type ServiceError = Box; pub const BASE_PATH: &str = ""; @@ -48,12 +49,6 @@ pub enum ComplexQueryParamGetResponse { Success } -#[derive(Debug, PartialEq, Serialize, Deserialize)] -pub enum EnumInPathPathParamGetResponse { - /// Success - Success -} - #[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum JsonComplexQueryParamGetResponse { /// Success @@ -265,6 +260,12 @@ pub enum XmlPutResponse { BadRequest } +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub enum EnumInPathPathParamGetResponse { + /// Success + Success +} + #[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum CreateRepoResponse { /// Success @@ -279,16 +280,13 @@ pub enum GetRepoInfoResponse { } /// API +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait Api { - fn poll_ready(&self, _cx: &mut Context) -> Poll>> { - Poll::Ready(Ok(())) - } - - async fn any_of_get( + async fn any_of_get<'a>( &self, - any_of: Option<&Vec>, + any_of: Option<&'a Vec>, context: &C) -> Result; async fn callback_with_header_post( @@ -296,19 +294,14 @@ pub trait Api { url: String, context: &C) -> Result; - async fn complex_query_param_get( + async fn complex_query_param_get<'a>( &self, - list_of_strings: Option<&Vec>, + list_of_strings: Option<&'a Vec>, context: &C) -> Result; - async fn enum_in_path_path_param_get( - &self, - path_param: models::StringEnum, - context: &C) -> Result; - - async fn json_complex_query_param_get( + async fn json_complex_query_param_get<'a>( &self, - list_of_strings: Option<&Vec>, + list_of_strings: Option<&'a Vec>, context: &C) -> Result; async fn mandatory_request_header_get( @@ -402,6 +395,11 @@ pub trait Api { xml_object: Option, context: &C) -> Result; + async fn enum_in_path_path_param_get( + &self, + path_param: models::StringEnum, + context: &C) -> Result; + async fn create_repo( &self, object_param: models::ObjectParam, @@ -415,17 +413,20 @@ pub trait Api { } /// API where `Context` isn't passed on every API call +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait ApiNoContext { - - fn poll_ready(&self, _cx: &mut Context) -> Poll>>; + // The std::task::Context struct houses a reference to std::task::Waker with the lifetime <'a>. + // Adding an anonymous lifetime `'a` to allow mockall to create a mock object with the right lifetimes. + // This is needed because the compiler is unable to determine the lifetimes on F's trait bound + // where F is the closure created by mockall. We use higher-rank trait bounds here to get around this. fn context(&self) -> &C; - async fn any_of_get( + async fn any_of_get<'a>( &self, - any_of: Option<&Vec>, + any_of: Option<&'a Vec>, ) -> Result; async fn callback_with_header_post( @@ -433,19 +434,14 @@ pub trait ApiNoContext { url: String, ) -> Result; - async fn complex_query_param_get( + async fn complex_query_param_get<'a>( &self, - list_of_strings: Option<&Vec>, + list_of_strings: Option<&'a Vec>, ) -> Result; - async fn enum_in_path_path_param_get( + async fn json_complex_query_param_get<'a>( &self, - path_param: models::StringEnum, - ) -> Result; - - async fn json_complex_query_param_get( - &self, - list_of_strings: Option<&Vec>, + list_of_strings: Option<&'a Vec>, ) -> Result; async fn mandatory_request_header_get( @@ -539,6 +535,11 @@ pub trait ApiNoContext { xml_object: Option, ) -> Result; + async fn enum_in_path_path_param_get( + &self, + path_param: models::StringEnum, + ) -> Result; + async fn create_repo( &self, object_param: models::ObjectParam, @@ -566,17 +567,13 @@ impl + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt for T #[async_trait] impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for ContextWrapper { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - self.api().poll_ready(cx) - } - fn context(&self) -> &C { ContextWrapper::context(self) } - async fn any_of_get( + async fn any_of_get<'a>( &self, - any_of: Option<&Vec>, + any_of: Option<&'a Vec>, ) -> Result { let context = self.context().clone(); @@ -592,27 +589,18 @@ impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for Contex self.api().callback_with_header_post(url, &context).await } - async fn complex_query_param_get( + async fn complex_query_param_get<'a>( &self, - list_of_strings: Option<&Vec>, + list_of_strings: Option<&'a Vec>, ) -> Result { let context = self.context().clone(); self.api().complex_query_param_get(list_of_strings, &context).await } - async fn enum_in_path_path_param_get( + async fn json_complex_query_param_get<'a>( &self, - path_param: models::StringEnum, - ) -> Result - { - let context = self.context().clone(); - self.api().enum_in_path_path_param_get(path_param, &context).await - } - - async fn json_complex_query_param_get( - &self, - list_of_strings: Option<&Vec>, + list_of_strings: Option<&'a Vec>, ) -> Result { let context = self.context().clone(); @@ -786,6 +774,15 @@ impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for Contex self.api().xml_put(xml_object, &context).await } + async fn enum_in_path_path_param_get( + &self, + path_param: models::StringEnum, + ) -> Result + { + let context = self.context().clone(); + self.api().enum_in_path_path_param_get(path_param, &context).await + } + async fn create_repo( &self, object_param: models::ObjectParam, @@ -821,11 +818,9 @@ pub enum CallbackCallbackPostResponse { /// Callback API +#[cfg_attr(feature = "mock", automock)] #[async_trait] pub trait CallbackApi { - fn poll_ready(&self, _cx: &mut Context) -> Poll>> { - Poll::Ready(Ok(())) - } async fn callback_callback_with_header_post( &self, @@ -841,9 +836,9 @@ pub trait CallbackApi { } /// Callback API without a `Context` +#[cfg_attr(feature = "mock", automock)] #[async_trait] pub trait CallbackApiNoContext { - fn poll_ready(&self, _cx: &mut Context) -> Poll>>; fn context(&self) -> &C; @@ -874,9 +869,6 @@ impl + Send + Sync, C: Clone + Send + Sync> CallbackContextWra #[async_trait] impl + Send + Sync, C: Clone + Send + Sync> CallbackApiNoContext for ContextWrapper { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - self.api().poll_ready(cx) - } fn context(&self) -> &C { ContextWrapper::context(self) diff --git a/samples/server/petstore/rust-server/output/openapi-v3/src/models.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/models.rs index 007c0f268f8b..907798195e37 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/models.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/models.rs @@ -1,5 +1,4 @@ #![allow(unused_qualifications)] - use validator::Validate; use crate::models; @@ -7,8 +6,11 @@ use crate::models; use crate::header; #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct AdditionalPropertiesWithList(std::collections::HashMap>); +pub struct AdditionalPropertiesWithList( + std::collections::HashMap> +); impl std::convert::From>> for AdditionalPropertiesWithList { fn from(x: std::collections::HashMap>) -> Self { @@ -36,23 +38,101 @@ impl std::ops::DerefMut for AdditionalPropertiesWithList { } /// Converts the AdditionalPropertiesWithList value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl ::std::string::ToString for AdditionalPropertiesWithList { - fn to_string(&self) -> String { - // Skipping additionalProperties in query parameter serialization - "".to_string() +impl std::fmt::Display for AdditionalPropertiesWithList { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Display for this model is not supported + write!(f, "") } } /// Converts Query Parameters representation (style=form, explode=false) to a AdditionalPropertiesWithList value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl ::std::str::FromStr for AdditionalPropertiesWithList { type Err = &'static str; fn from_str(s: &str) -> std::result::Result { - std::result::Result::Err("Parsing additionalProperties for AdditionalPropertiesWithList is not supported") + std::result::Result::Err("Parsing AdditionalPropertiesWithList is not supported") + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for AdditionalPropertiesWithList - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into AdditionalPropertiesWithList - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into AdditionalPropertiesWithList - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } } } @@ -67,14 +147,22 @@ impl AdditionalPropertiesWithList { // Utility function for wrapping list elements when serializing xml #[allow(non_snake_case)] -fn wrap_in_snake_another_xml_inner(item: &Vec, serializer: S) -> std::result::Result +fn wrap_in_snake_another_xml_inner(items: &Vec, serializer: S) -> std::result::Result where S: serde::ser::Serializer, { - serde_xml_rs::wrap_primitives(item, serializer, "snake_another_xml_inner") + use serde::ser::SerializeMap; + + let mut map = serializer.serialize_map(None)?; + for ref item in items { + map.serialize_key("snake_another_xml_inner")?; + map.serialize_value(item)?; + } + map.end() } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct AnotherXmlArray( #[serde(serialize_with = "wrap_in_snake_another_xml_inner")] @@ -140,16 +228,16 @@ impl std::ops::DerefMut for AnotherXmlArray { } /// Converts the AnotherXmlArray value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for AnotherXmlArray { - fn to_string(&self) -> String { - self.iter().map(|x| x.to_string()).collect::>().join(",") +impl std::fmt::Display for AnotherXmlArray { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.iter().map(|x| x.to_string()).collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a AnotherXmlArray value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for AnotherXmlArray { type Err = ::Err; @@ -176,8 +264,7 @@ impl std::convert::TryFrom> for hyper:: match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for AnotherXmlArray - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for AnotherXmlArray - value: {hdr_value} is invalid {e}")) } } } @@ -192,17 +279,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into AnotherXmlArray - {}", - value, err)) + format!("Unable to convert header value '{value}' into AnotherXmlArray - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into AnotherXmlArray - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl AnotherXmlArray { /// Helper function to allow us to convert this model to an XML string. @@ -214,9 +341,12 @@ impl AnotherXmlArray { } #[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] #[serde(rename = "snake_another_xml_inner")] -pub struct AnotherXmlInner(String); +pub struct AnotherXmlInner( + String +); impl std::convert::From for AnotherXmlInner { fn from(x: String) -> Self { @@ -224,19 +354,6 @@ impl std::convert::From for AnotherXmlInner { } } -impl std::string::ToString for AnotherXmlInner { - fn to_string(&self) -> String { - self.0.to_string() - } -} - -impl std::str::FromStr for AnotherXmlInner { - type Err = std::string::ParseError; - fn from_str(x: &str) -> std::result::Result { - std::result::Result::Ok(AnotherXmlInner(x.to_string())) - } -} - impl std::convert::From for String { fn from(x: AnotherXmlInner) -> Self { x.0 @@ -256,6 +373,96 @@ impl std::ops::DerefMut for AnotherXmlInner { } } +impl std::fmt::Display for AnotherXmlInner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.clone()) + } +} + +impl std::str::FromStr for AnotherXmlInner { + type Err = ::std::convert::Infallible; + fn from_str(x: &str) -> std::result::Result { + std::result::Result::Ok(AnotherXmlInner(x.to_owned())) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for AnotherXmlInner - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into AnotherXmlInner - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into AnotherXmlInner - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl AnotherXmlInner { /// Helper function to allow us to convert this model to an XML string. @@ -267,17 +474,19 @@ impl AnotherXmlInner { } /// An XML object -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] #[serde(rename = "snake_another_xml_object")] pub struct AnotherXmlObject { #[serde(rename = "inner_string")] + #[serde(skip_serializing_if="Option::is_none")] pub inner_string: Option, } + impl AnotherXmlObject { #[allow(clippy::new_without_default)] pub fn new() -> AnotherXmlObject { @@ -288,27 +497,25 @@ impl AnotherXmlObject { } /// Converts the AnotherXmlObject value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for AnotherXmlObject { - fn to_string(&self) -> String { +impl std::fmt::Display for AnotherXmlObject { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.inner_string.as_ref().map(|inner_string| { [ "inner_string".to_string(), inner_string.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a AnotherXmlObject value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for AnotherXmlObject { type Err = String; @@ -364,8 +571,7 @@ impl std::convert::TryFrom> for hyper: match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for AnotherXmlObject - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for AnotherXmlObject - value: {hdr_value} is invalid {e}")) } } } @@ -380,17 +586,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into AnotherXmlObject - {}", - value, err)) + format!("Unable to convert header value '{value}' into AnotherXmlObject - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into AnotherXmlObject - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl AnotherXmlObject { /// Associated constant for this model's XML namespace. @@ -403,78 +649,63 @@ impl AnotherXmlObject { /// Will panic if serialisation fails. #[allow(dead_code)] pub(crate) fn as_xml(&self) -> String { - let mut namespaces = std::collections::BTreeMap::new(); // An empty string is used to indicate a global namespace in xmltree. - namespaces.insert("".to_string(), Self::NAMESPACE.to_string()); - serde_xml_rs::to_string_with_namespaces(&self, namespaces).expect("impossible to fail to serialize") + let config = serde_xml_rs::SerdeXml::new() + .namespace("", Self::NAMESPACE); + config.to_string(&self).expect("impossible to fail to serialize") } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct AnyOfGet202Response { +pub struct AnyOfGet202Response( + swagger::AnyOf2 +); + +impl std::convert::From> for AnyOfGet202Response { + fn from(x: swagger::AnyOf2) -> Self { + AnyOfGet202Response(x) + } } +impl std::convert::From for swagger::AnyOf2 { + fn from(x: AnyOfGet202Response) -> Self { + x.0 + } +} -impl AnyOfGet202Response { - #[allow(clippy::new_without_default)] - pub fn new() -> AnyOfGet202Response { - AnyOfGet202Response { - } +impl std::ops::Deref for AnyOfGet202Response { + type Target = swagger::AnyOf2; + fn deref(&self) -> &swagger::AnyOf2 { + &self.0 + } +} + +impl std::ops::DerefMut for AnyOfGet202Response { + fn deref_mut(&mut self) -> &mut swagger::AnyOf2 { + &mut self.0 } } /// Converts the AnyOfGet202Response value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for AnyOfGet202Response { - fn to_string(&self) -> String { - let params: Vec> = vec![ - ]; - - params.into_iter().flatten().collect::>().join(",") +impl std::fmt::Display for AnyOfGet202Response { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Display for this model is not supported + write!(f, "") } } /// Converts Query Parameters representation (style=form, explode=false) to a AnyOfGet202Response value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer -impl std::str::FromStr for AnyOfGet202Response { - type Err = String; +impl ::std::str::FromStr for AnyOfGet202Response { + type Err = &'static str; fn from_str(s: &str) -> std::result::Result { - /// An intermediate representation of the struct to use for parsing. - #[derive(Default)] - #[allow(dead_code)] - struct IntermediateRep { - } - - let mut intermediate_rep = IntermediateRep::default(); - - // Parse into intermediate representation - let mut string_iter = s.split(','); - let mut key_result = string_iter.next(); - - while key_result.is_some() { - let val = match string_iter.next() { - Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing AnyOfGet202Response".to_string()) - }; - - if let Some(key) = key_result { - #[allow(clippy::match_single_binding)] - match key { - _ => return std::result::Result::Err("Unexpected key while parsing AnyOfGet202Response".to_string()) - } - } - - // Get the next key - key_result = string_iter.next(); - } - - // Use the intermediate representation to return the struct - std::result::Result::Ok(AnyOfGet202Response { - }) + std::result::Result::Err("Parsing AnyOfGet202Response is not supported") } } @@ -489,8 +720,7 @@ impl std::convert::TryFrom> for hyp match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for AnyOfGet202Response - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for AnyOfGet202Response - value: {hdr_value} is invalid {e}")) } } } @@ -505,17 +735,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into AnyOfGet202Response - {}", - value, err)) + format!("Unable to convert header value '{value}' into AnyOfGet202Response - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into AnyOfGet202Response - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl AnyOfGet202Response { /// Helper function to allow us to convert this model to an XML string. @@ -527,114 +797,261 @@ impl AnyOfGet202Response { } /// Test a model containing an anyOf -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct AnyOfObject { +pub struct AnyOfObject( + swagger::AnyOf2 +); + +impl std::convert::From> for AnyOfObject { + fn from(x: swagger::AnyOf2) -> Self { + AnyOfObject(x) + } +} + +impl std::convert::From for swagger::AnyOf2 { + fn from(x: AnyOfObject) -> Self { + x.0 + } } +impl std::ops::Deref for AnyOfObject { + type Target = swagger::AnyOf2; + fn deref(&self) -> &swagger::AnyOf2 { + &self.0 + } +} -impl AnyOfObject { - #[allow(clippy::new_without_default)] - pub fn new() -> AnyOfObject { - AnyOfObject { - } +impl std::ops::DerefMut for AnyOfObject { + fn deref_mut(&mut self) -> &mut swagger::AnyOf2 { + &mut self.0 } } /// Converts the AnyOfObject value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for AnyOfObject { - fn to_string(&self) -> String { - let params: Vec> = vec![ - ]; - - params.into_iter().flatten().collect::>().join(",") +impl std::fmt::Display for AnyOfObject { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Display for this model is not supported + write!(f, "") } } /// Converts Query Parameters representation (style=form, explode=false) to a AnyOfObject value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer -impl std::str::FromStr for AnyOfObject { - type Err = String; +impl ::std::str::FromStr for AnyOfObject { + type Err = &'static str; fn from_str(s: &str) -> std::result::Result { - /// An intermediate representation of the struct to use for parsing. - #[derive(Default)] - #[allow(dead_code)] - struct IntermediateRep { - } - - let mut intermediate_rep = IntermediateRep::default(); - - // Parse into intermediate representation - let mut string_iter = s.split(','); - let mut key_result = string_iter.next(); + std::result::Result::Err("Parsing AnyOfObject is not supported") + } +} - while key_result.is_some() { - let val = match string_iter.next() { - Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing AnyOfObject".to_string()) - }; +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue - if let Some(key) = key_result { - #[allow(clippy::match_single_binding)] - match key { - _ => return std::result::Result::Err("Unexpected key while parsing AnyOfObject".to_string()) - } - } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; - // Get the next key - key_result = string_iter.next(); + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for AnyOfObject - value: {hdr_value} is invalid {e}")) } + } +} - // Use the intermediate representation to return the struct - std::result::Result::Ok(AnyOfObject { - }) +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into AnyOfObject - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue> { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into AnyOfObject - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl AnyOfObject { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] + +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum AnyOfObjectAnyOf { + #[serde(rename = "FOO")] + Foo, + #[serde(rename = "BAR")] + Bar, +} + +impl std::fmt::Display for AnyOfObjectAnyOf { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + AnyOfObjectAnyOf::Foo => write!(f, "FOO"), + AnyOfObjectAnyOf::Bar => write!(f, "BAR"), + } + } +} + +impl std::str::FromStr for AnyOfObjectAnyOf { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match s { + "FOO" => std::result::Result::Ok(AnyOfObjectAnyOf::Foo), + "BAR" => std::result::Result::Ok(AnyOfObjectAnyOf::Bar), + _ => std::result::Result::Err(format!("Value not valid: {s}")), + } + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for AnyOfObject - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for AnyOfObjectAnyOf - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into AnyOfObject - {}", - value, err)) + format!("Unable to convert header value '{value}' into AnyOfObjectAnyOf - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl AnyOfObject { + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into AnyOfObjectAnyOf - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl AnyOfObjectAnyOf { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -644,19 +1061,22 @@ impl AnyOfObject { } /// Test containing an anyOf object -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct AnyOfProperty { #[serde(rename = "requiredAnyOf")] + pub required_any_of: models::AnyOfObject, #[serde(rename = "optionalAnyOf")] + #[serde(skip_serializing_if="Option::is_none")] pub optional_any_of: Option, } + impl AnyOfProperty { #[allow(clippy::new_without_default)] pub fn new(required_any_of: models::AnyOfObject, ) -> AnyOfProperty { @@ -668,23 +1088,21 @@ impl AnyOfProperty { } /// Converts the AnyOfProperty value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for AnyOfProperty { - fn to_string(&self) -> String { +impl std::fmt::Display for AnyOfProperty { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - // Skipping requiredAnyOf in query parameter serialization - - // Skipping optionalAnyOf in query parameter serialization - + // Skipping non-primitive type requiredAnyOf in query parameter serialization + // Skipping non-primitive type optionalAnyOf in query parameter serialization ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a AnyOfProperty value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for AnyOfProperty { type Err = String; @@ -744,8 +1162,7 @@ impl std::convert::TryFrom> for hyper::he match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for AnyOfProperty - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for AnyOfProperty - value: {hdr_value} is invalid {e}")) } } } @@ -760,17 +1177,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into AnyOfProperty - {}", - value, err)) + format!("Unable to convert header value '{value}' into AnyOfProperty - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into AnyOfProperty - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl AnyOfProperty { /// Helper function to allow us to convert this model to an XML string. @@ -782,21 +1239,24 @@ impl AnyOfProperty { } /// An XML object -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] #[serde(rename = "camelDuplicateXmlObject")] pub struct DuplicateXmlObject { #[serde(rename = "inner_string")] + #[serde(skip_serializing_if="Option::is_none")] pub inner_string: Option, #[serde(rename = "inner_array")] #[serde(serialize_with = "wrap_in_camelXmlInner")] + pub inner_array: models::XmlArray, } + impl DuplicateXmlObject { #[allow(clippy::new_without_default)] pub fn new(inner_array: models::XmlArray, ) -> DuplicateXmlObject { @@ -808,29 +1268,26 @@ impl DuplicateXmlObject { } /// Converts the DuplicateXmlObject value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for DuplicateXmlObject { - fn to_string(&self) -> String { +impl std::fmt::Display for DuplicateXmlObject { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.inner_string.as_ref().map(|inner_string| { [ "inner_string".to_string(), inner_string.to_string(), ].join(",") }), - - // Skipping inner_array in query parameter serialization - + // Skipping non-primitive type inner_array in query parameter serialization ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a DuplicateXmlObject value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for DuplicateXmlObject { type Err = String; @@ -890,8 +1347,7 @@ impl std::convert::TryFrom> for hype match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for DuplicateXmlObject - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for DuplicateXmlObject - value: {hdr_value} is invalid {e}")) } } } @@ -906,17 +1362,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into DuplicateXmlObject - {}", - value, err)) + format!("Unable to convert header value '{value}' into DuplicateXmlObject - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into DuplicateXmlObject - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl DuplicateXmlObject { /// Associated constant for this model's XML namespace. @@ -929,10 +1425,10 @@ impl DuplicateXmlObject { /// Will panic if serialisation fails. #[allow(dead_code)] pub(crate) fn as_xml(&self) -> String { - let mut namespaces = std::collections::BTreeMap::new(); // An empty string is used to indicate a global namespace in xmltree. - namespaces.insert("".to_string(), Self::NAMESPACE.to_string()); - serde_xml_rs::to_string_with_namespaces(&self, namespaces).expect("impossible to fail to serialize") + let config = serde_xml_rs::SerdeXml::new() + .namespace("", Self::NAMESPACE); + config.to_string(&self).expect("impossible to fail to serialize") } } @@ -942,7 +1438,8 @@ impl DuplicateXmlObject { /// which helps with FFI. #[allow(non_camel_case_types)] #[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] + #[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] pub enum EnumWithStarObject { #[serde(rename = "FOO")] @@ -971,7 +1468,85 @@ impl std::str::FromStr for EnumWithStarObject { "FOO" => std::result::Result::Ok(EnumWithStarObject::Foo), "BAR" => std::result::Result::Ok(EnumWithStarObject::Bar), "*" => std::result::Result::Ok(EnumWithStarObject::Star), - _ => std::result::Result::Err(format!("Value not valid: {}", s)), + _ => std::result::Result::Err(format!("Value not valid: {s}")), + } + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for EnumWithStarObject - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into EnumWithStarObject - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into EnumWithStarObject - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), } } } @@ -986,8 +1561,11 @@ impl EnumWithStarObject { } #[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct Err(String); +pub struct Err( + String +); impl std::convert::From for Err { fn from(x: String) -> Self { @@ -995,19 +1573,6 @@ impl std::convert::From for Err { } } -impl std::string::ToString for Err { - fn to_string(&self) -> String { - self.0.to_string() - } -} - -impl std::str::FromStr for Err { - type Err = std::string::ParseError; - fn from_str(x: &str) -> std::result::Result { - std::result::Result::Ok(Err(x.to_string())) - } -} - impl std::convert::From for String { fn from(x: Err) -> Self { x.0 @@ -1027,6 +1592,96 @@ impl std::ops::DerefMut for Err { } } +impl std::fmt::Display for Err { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.clone()) + } +} + +impl std::str::FromStr for Err { + type Err = ::std::convert::Infallible; + fn from_str(x: &str) -> std::result::Result { + std::result::Result::Ok(Err(x.to_owned())) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for Err - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into Err - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Err - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl Err { /// Helper function to allow us to convert this model to an XML string. @@ -1038,8 +1693,11 @@ impl Err { } #[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct Error(String); +pub struct Error( + String +); impl std::convert::From for Error { fn from(x: String) -> Self { @@ -1047,19 +1705,6 @@ impl std::convert::From for Error { } } -impl std::string::ToString for Error { - fn to_string(&self) -> String { - self.0.to_string() - } -} - -impl std::str::FromStr for Error { - type Err = std::string::ParseError; - fn from_str(x: &str) -> std::result::Result { - std::result::Result::Ok(Error(x.to_string())) - } -} - impl std::convert::From for String { fn from(x: Error) -> Self { x.0 @@ -1079,10 +1724,100 @@ impl std::ops::DerefMut for Error { } } +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.clone()) + } +} -impl Error { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. +impl std::str::FromStr for Error { + type Err = ::std::convert::Infallible; + fn from_str(x: &str) -> std::result::Result { + std::result::Result::Ok(Error(x.to_owned())) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for Error - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into Error - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Error - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl Error { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. #[allow(dead_code)] pub(crate) fn as_xml(&self) -> String { serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") @@ -1090,114 +1825,265 @@ impl Error { } /// Test a model containing an anyOf that starts with a number -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct Model12345AnyOfObject { +pub struct Model12345AnyOfObject( + swagger::AnyOf2 +); + +impl std::convert::From> for Model12345AnyOfObject { + fn from(x: swagger::AnyOf2) -> Self { + Model12345AnyOfObject(x) + } } +impl std::convert::From for swagger::AnyOf2 { + fn from(x: Model12345AnyOfObject) -> Self { + x.0 + } +} -impl Model12345AnyOfObject { - #[allow(clippy::new_without_default)] - pub fn new() -> Model12345AnyOfObject { - Model12345AnyOfObject { - } +impl std::ops::Deref for Model12345AnyOfObject { + type Target = swagger::AnyOf2; + fn deref(&self) -> &swagger::AnyOf2 { + &self.0 + } +} + +impl std::ops::DerefMut for Model12345AnyOfObject { + fn deref_mut(&mut self) -> &mut swagger::AnyOf2 { + &mut self.0 } } /// Converts the Model12345AnyOfObject value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for Model12345AnyOfObject { - fn to_string(&self) -> String { - let params: Vec> = vec![ - ]; - - params.into_iter().flatten().collect::>().join(",") +impl std::fmt::Display for Model12345AnyOfObject { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Display for this model is not supported + write!(f, "") } } /// Converts Query Parameters representation (style=form, explode=false) to a Model12345AnyOfObject value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer -impl std::str::FromStr for Model12345AnyOfObject { - type Err = String; +impl ::std::str::FromStr for Model12345AnyOfObject { + type Err = &'static str; fn from_str(s: &str) -> std::result::Result { - /// An intermediate representation of the struct to use for parsing. - #[derive(Default)] - #[allow(dead_code)] - struct IntermediateRep { + std::result::Result::Err("Parsing Model12345AnyOfObject is not supported") + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for Model12345AnyOfObject - value: {hdr_value} is invalid {e}")) } + } +} - let mut intermediate_rep = IntermediateRep::default(); +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; - // Parse into intermediate representation - let mut string_iter = s.split(','); - let mut key_result = string_iter.next(); + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into Model12345AnyOfObject - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} - while key_result.is_some() { - let val = match string_iter.next() { - Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing Model12345AnyOfObject".to_string()) - }; +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; - if let Some(key) = key_result { - #[allow(clippy::match_single_binding)] - match key { - _ => return std::result::Result::Err("Unexpected key while parsing Model12345AnyOfObject".to_string()) - } - } + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); - // Get the next key - key_result = string_iter.next(); + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } + } +} - // Use the intermediate representation to return the struct - std::result::Result::Ok(Model12345AnyOfObject { - }) +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Model12345AnyOfObject - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +impl Model12345AnyOfObject { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] + +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum Model12345AnyOfObjectAnyOf { + #[serde(rename = "FOO")] + Foo, + #[serde(rename = "BAR")] + Bar, + #[serde(rename = "*")] + Star, +} + +impl std::fmt::Display for Model12345AnyOfObjectAnyOf { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + Model12345AnyOfObjectAnyOf::Foo => write!(f, "FOO"), + Model12345AnyOfObjectAnyOf::Bar => write!(f, "BAR"), + Model12345AnyOfObjectAnyOf::Star => write!(f, "*"), + } + } +} + +impl std::str::FromStr for Model12345AnyOfObjectAnyOf { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match s { + "FOO" => std::result::Result::Ok(Model12345AnyOfObjectAnyOf::Foo), + "BAR" => std::result::Result::Ok(Model12345AnyOfObjectAnyOf::Bar), + "*" => std::result::Result::Ok(Model12345AnyOfObjectAnyOf::Star), + _ => std::result::Result::Err(format!("Value not valid: {s}")), + } + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for Model12345AnyOfObject - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for Model12345AnyOfObjectAnyOf - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into Model12345AnyOfObject - {}", - value, err)) + format!("Unable to convert header value '{value}' into Model12345AnyOfObjectAnyOf - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Model12345AnyOfObjectAnyOf - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} -impl Model12345AnyOfObject { +impl Model12345AnyOfObjectAnyOf { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -1206,16 +2092,18 @@ impl Model12345AnyOfObject { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct MultigetGet201Response { #[serde(rename = "foo")] + #[serde(skip_serializing_if="Option::is_none")] pub foo: Option, } + impl MultigetGet201Response { #[allow(clippy::new_without_default)] pub fn new() -> MultigetGet201Response { @@ -1226,27 +2114,25 @@ impl MultigetGet201Response { } /// Converts the MultigetGet201Response value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for MultigetGet201Response { - fn to_string(&self) -> String { +impl std::fmt::Display for MultigetGet201Response { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.foo.as_ref().map(|foo| { [ "foo".to_string(), foo.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a MultigetGet201Response value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for MultigetGet201Response { type Err = String; @@ -1302,8 +2188,7 @@ impl std::convert::TryFrom> for match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for MultigetGet201Response - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for MultigetGet201Response - value: {hdr_value} is invalid {e}")) } } } @@ -1318,17 +2203,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into MultigetGet201Response - {}", - value, err)) + format!("Unable to convert header value '{value}' into MultigetGet201Response - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into MultigetGet201Response - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl MultigetGet201Response { /// Helper function to allow us to convert this model to an XML string. @@ -1340,8 +2265,11 @@ impl MultigetGet201Response { } #[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct MyId(i32); +pub struct MyId( + i32 +); impl std::convert::From for MyId { fn from(x: i32) -> Self { @@ -1368,50 +2296,151 @@ impl std::ops::DerefMut for MyId { } } - -impl MyId { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. - #[allow(dead_code)] - pub(crate) fn as_xml(&self) -> String { - serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") +/// Converts the MyId value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for MyId { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] -#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct MyIdList( - Vec -); - -impl std::convert::From> for MyIdList { - fn from(x: Vec) -> Self { - MyIdList(x) - } -} +/// Converts Query Parameters representation (style=form, explode=false) to a MyId value +/// as specified in +/// Should be implemented in a serde deserializer +impl ::std::str::FromStr for MyId { + type Err = String; -impl std::convert::From for Vec { - fn from(x: MyIdList) -> Self { - x.0 + fn from_str(s: &str) -> std::result::Result { + match std::str::FromStr::from_str(s) { + std::result::Result::Ok(r) => std::result::Result::Ok(MyId(r)), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {s} to MyId: {e:?}")), + } } } -impl std::iter::FromIterator for MyIdList { - fn from_iter>(u: U) -> Self { - MyIdList(Vec::::from_iter(u)) - } -} +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue -impl std::iter::IntoIterator for MyIdList { - type Item = i32; - type IntoIter = std::vec::IntoIter; +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for MyId - value: {hdr_value} is invalid {e}")) + } } } -impl<'a> std::iter::IntoIterator for &'a MyIdList { +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into MyId - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into MyId - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl MyId { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] + +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct MyIdList( + Vec +); + +impl std::convert::From> for MyIdList { + fn from(x: Vec) -> Self { + MyIdList(x) + } +} + +impl std::convert::From for Vec { + fn from(x: MyIdList) -> Self { + x.0 + } +} + +impl std::iter::FromIterator for MyIdList { + fn from_iter>(u: U) -> Self { + MyIdList(Vec::::from_iter(u)) + } +} + +impl std::iter::IntoIterator for MyIdList { + type Item = i32; + type IntoIter = std::vec::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl<'a> std::iter::IntoIterator for &'a MyIdList { type Item = &'a i32; type IntoIter = std::slice::Iter<'a, i32>; @@ -1443,16 +2472,16 @@ impl std::ops::DerefMut for MyIdList { } /// Converts the MyIdList value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for MyIdList { - fn to_string(&self) -> String { - self.iter().map(|x| x.to_string()).collect::>().join(",") +impl std::fmt::Display for MyIdList { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.iter().map(|x| x.to_string()).collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a MyIdList value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for MyIdList { type Err = ::Err; @@ -1479,8 +2508,7 @@ impl std::convert::TryFrom> for hyper::header: match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for MyIdList - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for MyIdList - value: {hdr_value} is invalid {e}")) } } } @@ -1495,17 +2523,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into MyIdList - {}", - value, err)) + format!("Unable to convert header value '{value}' into MyIdList - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into MyIdList - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl MyIdList { /// Helper function to allow us to convert this model to an XML string. @@ -1516,33 +2584,38 @@ impl MyIdList { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct NullableTest { #[serde(rename = "nullable")] + pub nullable: swagger::Nullable, #[serde(rename = "nullableWithNullDefault")] #[serde(deserialize_with = "swagger::nullable_format::deserialize_optional_nullable")] #[serde(default = "swagger::nullable_format::default_optional_nullable")] + #[serde(skip_serializing_if="Option::is_none")] pub nullable_with_null_default: Option>, #[serde(rename = "nullableWithPresentDefault")] #[serde(deserialize_with = "swagger::nullable_format::deserialize_optional_nullable")] #[serde(default = "swagger::nullable_format::default_optional_nullable")] + #[serde(skip_serializing_if="Option::is_none")] pub nullable_with_present_default: Option>, #[serde(rename = "nullableWithNoDefault")] #[serde(deserialize_with = "swagger::nullable_format::deserialize_optional_nullable")] #[serde(default = "swagger::nullable_format::default_optional_nullable")] + #[serde(skip_serializing_if="Option::is_none")] pub nullable_with_no_default: Option>, #[serde(rename = "nullableArray")] #[serde(deserialize_with = "swagger::nullable_format::deserialize_optional_nullable")] #[serde(default = "swagger::nullable_format::default_optional_nullable")] + #[serde(skip_serializing_if="Option::is_none")] pub nullable_array: Option>>, @@ -1550,6 +2623,7 @@ pub struct NullableTest { #[validate( length(min = 1), )] + #[serde(skip_serializing_if="Option::is_none")] pub min_item_test: Option>, @@ -1557,6 +2631,7 @@ pub struct NullableTest { #[validate( length(max = 2), )] + #[serde(skip_serializing_if="Option::is_none")] pub max_item_test: Option>, @@ -1564,12 +2639,14 @@ pub struct NullableTest { #[validate( length(min = 1, max = 3), )] + #[serde(skip_serializing_if="Option::is_none")] pub min_max_item_test: Option>, } + impl NullableTest { #[allow(clippy::new_without_default)] pub fn new(nullable: swagger::Nullable, ) -> NullableTest { @@ -1587,79 +2664,63 @@ impl NullableTest { } /// Converts the NullableTest value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for NullableTest { - fn to_string(&self) -> String { +impl std::fmt::Display for NullableTest { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - Some("nullable".to_string()), Some(self.nullable.as_ref().map_or("null".to_string(), |x| x.to_string())), - - self.nullable_with_null_default.as_ref().map(|nullable_with_null_default| { [ "nullableWithNullDefault".to_string(), nullable_with_null_default.as_ref().map_or("null".to_string(), |x| x.to_string()), ].join(",") }), - - self.nullable_with_present_default.as_ref().map(|nullable_with_present_default| { [ "nullableWithPresentDefault".to_string(), nullable_with_present_default.as_ref().map_or("null".to_string(), |x| x.to_string()), ].join(",") }), - - self.nullable_with_no_default.as_ref().map(|nullable_with_no_default| { [ "nullableWithNoDefault".to_string(), nullable_with_no_default.as_ref().map_or("null".to_string(), |x| x.to_string()), ].join(",") }), - - self.nullable_array.as_ref().map(|nullable_array| { [ "nullableArray".to_string(), nullable_array.as_ref().map_or("null".to_string(), |x| x.iter().map(|x| x.to_string()).collect::>().join(",")), ].join(",") }), - - self.min_item_test.as_ref().map(|min_item_test| { [ "min_item_test".to_string(), min_item_test.iter().map(|x| x.to_string()).collect::>().join(","), ].join(",") }), - - self.max_item_test.as_ref().map(|max_item_test| { [ "max_item_test".to_string(), max_item_test.iter().map(|x| x.to_string()).collect::>().join(","), ].join(",") }), - - self.min_max_item_test.as_ref().map(|min_max_item_test| { [ "min_max_item_test".to_string(), min_max_item_test.iter().map(|x| x.to_string()).collect::>().join(","), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a NullableTest value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for NullableTest { type Err = String; @@ -1669,11 +2730,11 @@ impl std::str::FromStr for NullableTest { #[derive(Default)] #[allow(dead_code)] struct IntermediateRep { - pub nullable: Vec, - pub nullable_with_null_default: Vec, - pub nullable_with_present_default: Vec, - pub nullable_with_no_default: Vec, - pub nullable_array: Vec>, + pub nullable: Vec>, + pub nullable_with_null_default: Vec>, + pub nullable_with_present_default: Vec>, + pub nullable_with_no_default: Vec>, + pub nullable_array: Vec>>, pub min_item_test: Vec>, pub max_item_test: Vec>, pub min_max_item_test: Vec>, @@ -1735,8 +2796,7 @@ impl std::convert::TryFrom> for hyper::hea match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for NullableTest - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for NullableTest - value: {hdr_value} is invalid {e}")) } } } @@ -1751,17 +2811,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into NullableTest - {}", - value, err)) + format!("Unable to convert header value '{value}' into NullableTest - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into NullableTest - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl NullableTest { /// Helper function to allow us to convert this model to an XML string. @@ -1772,19 +2872,22 @@ impl NullableTest { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct ObjectHeader { #[serde(rename = "requiredObjectHeader")] + pub required_object_header: bool, #[serde(rename = "optionalObjectHeader")] + #[serde(skip_serializing_if="Option::is_none")] pub optional_object_header: Option, } + impl ObjectHeader { #[allow(clippy::new_without_default)] pub fn new(required_object_header: bool, ) -> ObjectHeader { @@ -1796,31 +2899,27 @@ impl ObjectHeader { } /// Converts the ObjectHeader value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for ObjectHeader { - fn to_string(&self) -> String { +impl std::fmt::Display for ObjectHeader { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - Some("requiredObjectHeader".to_string()), Some(self.required_object_header.to_string()), - - self.optional_object_header.as_ref().map(|optional_object_header| { [ "optionalObjectHeader".to_string(), optional_object_header.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a ObjectHeader value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for ObjectHeader { type Err = String; @@ -1880,8 +2979,7 @@ impl std::convert::TryFrom> for hyper::hea match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for ObjectHeader - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for ObjectHeader - value: {hdr_value} is invalid {e}")) } } } @@ -1896,17 +2994,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into ObjectHeader - {}", - value, err)) + format!("Unable to convert header value '{value}' into ObjectHeader - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ObjectHeader - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl ObjectHeader { /// Helper function to allow us to convert this model to an XML string. @@ -1917,19 +3055,22 @@ impl ObjectHeader { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct ObjectParam { #[serde(rename = "requiredParam")] + pub required_param: bool, #[serde(rename = "optionalParam")] + #[serde(skip_serializing_if="Option::is_none")] pub optional_param: Option, } + impl ObjectParam { #[allow(clippy::new_without_default)] pub fn new(required_param: bool, ) -> ObjectParam { @@ -1941,31 +3082,27 @@ impl ObjectParam { } /// Converts the ObjectParam value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for ObjectParam { - fn to_string(&self) -> String { +impl std::fmt::Display for ObjectParam { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - Some("requiredParam".to_string()), Some(self.required_param.to_string()), - - self.optional_param.as_ref().map(|optional_param| { [ "optionalParam".to_string(), optional_param.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a ObjectParam value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for ObjectParam { type Err = String; @@ -2025,8 +3162,7 @@ impl std::convert::TryFrom> for hyper::head match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for ObjectParam - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for ObjectParam - value: {hdr_value} is invalid {e}")) } } } @@ -2041,17 +3177,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into ObjectParam - {}", - value, err)) + format!("Unable to convert header value '{value}' into ObjectParam - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ObjectParam - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl ObjectParam { /// Helper function to allow us to convert this model to an XML string. @@ -2062,26 +3238,31 @@ impl ObjectParam { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct ObjectUntypedProps { #[serde(rename = "required_untyped")] + pub required_untyped: serde_json::Value, #[serde(rename = "required_untyped_nullable")] + pub required_untyped_nullable: swagger::Nullable, #[serde(rename = "not_required_untyped")] + #[serde(skip_serializing_if="Option::is_none")] pub not_required_untyped: Option, #[serde(rename = "not_required_untyped_nullable")] + #[serde(skip_serializing_if="Option::is_none")] pub not_required_untyped_nullable: Option, } + impl ObjectUntypedProps { #[allow(clippy::new_without_default)] pub fn new(required_untyped: serde_json::Value, required_untyped_nullable: swagger::Nullable, ) -> ObjectUntypedProps { @@ -2095,27 +3276,23 @@ impl ObjectUntypedProps { } /// Converts the ObjectUntypedProps value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for ObjectUntypedProps { - fn to_string(&self) -> String { +impl std::fmt::Display for ObjectUntypedProps { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - // Skipping required_untyped in query parameter serialization - - // Skipping required_untyped_nullable in query parameter serialization - - // Skipping not_required_untyped in query parameter serialization - - // Skipping not_required_untyped_nullable in query parameter serialization - + // Skipping non-primitive type required_untyped in query parameter serialization + // Skipping non-primitive type required_untyped_nullable in query parameter serialization + // Skipping non-primitive type not_required_untyped in query parameter serialization + // Skipping non-primitive type not_required_untyped_nullable in query parameter serialization ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a ObjectUntypedProps value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for ObjectUntypedProps { type Err = String; @@ -2126,7 +3303,7 @@ impl std::str::FromStr for ObjectUntypedProps { #[allow(dead_code)] struct IntermediateRep { pub required_untyped: Vec, - pub required_untyped_nullable: Vec, + pub required_untyped_nullable: Vec>, pub not_required_untyped: Vec, pub not_required_untyped_nullable: Vec, } @@ -2182,8 +3359,7 @@ impl std::convert::TryFrom> for hype match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for ObjectUntypedProps - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for ObjectUntypedProps - value: {hdr_value} is invalid {e}")) } } } @@ -2198,17 +3374,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into ObjectUntypedProps - {}", - value, err)) + format!("Unable to convert header value '{value}' into ObjectUntypedProps - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ObjectUntypedProps - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl ObjectUntypedProps { /// Helper function to allow us to convert this model to an XML string. @@ -2219,16 +3435,18 @@ impl ObjectUntypedProps { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct ObjectWithArrayOfObjects { #[serde(rename = "objectArray")] + #[serde(skip_serializing_if="Option::is_none")] pub object_array: Option>, } + impl ObjectWithArrayOfObjects { #[allow(clippy::new_without_default)] pub fn new() -> ObjectWithArrayOfObjects { @@ -2239,27 +3457,25 @@ impl ObjectWithArrayOfObjects { } /// Converts the ObjectWithArrayOfObjects value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for ObjectWithArrayOfObjects { - fn to_string(&self) -> String { +impl std::fmt::Display for ObjectWithArrayOfObjects { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.object_array.as_ref().map(|object_array| { [ "objectArray".to_string(), object_array.iter().map(|x| x.to_string()).collect::>().join(","), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a ObjectWithArrayOfObjects value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for ObjectWithArrayOfObjects { type Err = String; @@ -2314,8 +3530,7 @@ impl std::convert::TryFrom> fo match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for ObjectWithArrayOfObjects - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for ObjectWithArrayOfObjects - value: {hdr_value} is invalid {e}")) } } } @@ -2330,17 +3545,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into ObjectWithArrayOfObjects - {}", - value, err)) + format!("Unable to convert header value '{value}' into ObjectWithArrayOfObjects - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ObjectWithArrayOfObjects - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl ObjectWithArrayOfObjects { /// Helper function to allow us to convert this model to an XML string. @@ -2352,8 +3607,11 @@ impl ObjectWithArrayOfObjects { } #[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct Ok(String); +pub struct Ok( + String +); impl std::convert::From for Ok { fn from(x: String) -> Self { @@ -2361,19 +3619,6 @@ impl std::convert::From for Ok { } } -impl std::string::ToString for Ok { - fn to_string(&self) -> String { - self.0.to_string() - } -} - -impl std::str::FromStr for Ok { - type Err = std::string::ParseError; - fn from_str(x: &str) -> std::result::Result { - std::result::Result::Ok(Ok(x.to_string())) - } -} - impl std::convert::From for String { fn from(x: Ok) -> Self { x.0 @@ -2393,81 +3638,156 @@ impl std::ops::DerefMut for Ok { } } - -impl Ok { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. - #[allow(dead_code)] - pub(crate) fn as_xml(&self) -> String { - serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") +impl std::fmt::Display for Ok { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.clone()) } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] -#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct OneOfGet200Response { +impl std::str::FromStr for Ok { + type Err = ::std::convert::Infallible; + fn from_str(x: &str) -> std::result::Result { + std::result::Result::Ok(Ok(x.to_owned())) + } } +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue -impl OneOfGet200Response { - #[allow(clippy::new_without_default)] - pub fn new() -> OneOfGet200Response { - OneOfGet200Response { +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for Ok - value: {hdr_value} is invalid {e}")) } } } -/// Converts the OneOfGet200Response value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde serializer -impl std::string::ToString for OneOfGet200Response { - fn to_string(&self) -> String { - let params: Vec> = vec![ - ]; - - params.into_iter().flatten().collect::>().join(",") - } -} +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; -/// Converts Query Parameters representation (style=form, explode=false) to a OneOfGet200Response value -/// as specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde deserializer -impl std::str::FromStr for OneOfGet200Response { - type Err = String; - - fn from_str(s: &str) -> std::result::Result { - /// An intermediate representation of the struct to use for parsing. - #[derive(Default)] - #[allow(dead_code)] - struct IntermediateRep { + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into Ok - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } + } +} - let mut intermediate_rep = IntermediateRep::default(); +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; - // Parse into intermediate representation - let mut string_iter = s.split(','); - let mut key_result = string_iter.next(); + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); - while key_result.is_some() { - let val = match string_iter.next() { - Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing OneOfGet200Response".to_string()) - }; + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} - if let Some(key) = key_result { - #[allow(clippy::match_single_binding)] - match key { - _ => return std::result::Result::Err("Unexpected key while parsing OneOfGet200Response".to_string()) - } - } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; - // Get the next key - key_result = string_iter.next(); + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Ok - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), } + } +} - // Use the intermediate representation to return the struct - std::result::Result::Ok(OneOfGet200Response { - }) +impl Ok { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] + +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct OneOfGet200Response( + swagger::OneOf2> +); + +impl std::convert::From>> for OneOfGet200Response { + fn from(x: swagger::OneOf2>) -> Self { + OneOfGet200Response(x) + } +} + +impl std::convert::From for swagger::OneOf2> { + fn from(x: OneOfGet200Response) -> Self { + x.0 + } +} + +impl std::ops::Deref for OneOfGet200Response { + type Target = swagger::OneOf2>; + fn deref(&self) -> &swagger::OneOf2> { + &self.0 + } +} + +impl std::ops::DerefMut for OneOfGet200Response { + fn deref_mut(&mut self) -> &mut swagger::OneOf2> { + &mut self.0 + } +} + +/// Converts the OneOfGet200Response value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for OneOfGet200Response { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Display for this model is not supported + write!(f, "") + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a OneOfGet200Response value +/// as specified in +/// Should be implemented in a serde deserializer +impl ::std::str::FromStr for OneOfGet200Response { + type Err = &'static str; + + fn from_str(s: &str) -> std::result::Result { + std::result::Result::Err("Parsing OneOfGet200Response is not supported") } } @@ -2482,8 +3802,7 @@ impl std::convert::TryFrom> for hyp match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for OneOfGet200Response - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for OneOfGet200Response - value: {hdr_value} is invalid {e}")) } } } @@ -2498,17 +3817,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into OneOfGet200Response - {}", - value, err)) + format!("Unable to convert header value '{value}' into OneOfGet200Response - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into OneOfGet200Response - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl OneOfGet200Response { /// Helper function to allow us to convert this model to an XML string. @@ -2520,8 +3879,11 @@ impl OneOfGet200Response { } #[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct OptionalObjectHeader(i32); +pub struct OptionalObjectHeader( + i32 +); impl std::convert::From for OptionalObjectHeader { fn from(x: i32) -> Self { @@ -2548,6 +3910,106 @@ impl std::ops::DerefMut for OptionalObjectHeader { } } +/// Converts the OptionalObjectHeader value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for OptionalObjectHeader { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a OptionalObjectHeader value +/// as specified in +/// Should be implemented in a serde deserializer +impl ::std::str::FromStr for OptionalObjectHeader { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match std::str::FromStr::from_str(s) { + std::result::Result::Ok(r) => std::result::Result::Ok(OptionalObjectHeader(r)), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {s} to OptionalObjectHeader: {e:?}")), + } + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for OptionalObjectHeader - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into OptionalObjectHeader - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into OptionalObjectHeader - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl OptionalObjectHeader { /// Helper function to allow us to convert this model to an XML string. @@ -2559,8 +4021,11 @@ impl OptionalObjectHeader { } #[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct RequiredObjectHeader(bool); +pub struct RequiredObjectHeader( + bool +); impl std::convert::From for RequiredObjectHeader { fn from(x: bool) -> Self { @@ -2587,6 +4052,106 @@ impl std::ops::DerefMut for RequiredObjectHeader { } } +/// Converts the RequiredObjectHeader value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for RequiredObjectHeader { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a RequiredObjectHeader value +/// as specified in +/// Should be implemented in a serde deserializer +impl ::std::str::FromStr for RequiredObjectHeader { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match std::str::FromStr::from_str(s) { + std::result::Result::Ok(r) => std::result::Result::Ok(RequiredObjectHeader(r)), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {s} to RequiredObjectHeader: {e:?}")), + } + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for RequiredObjectHeader - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into RequiredObjectHeader - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into RequiredObjectHeader - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl RequiredObjectHeader { /// Helper function to allow us to convert this model to an XML string. @@ -2598,8 +4163,11 @@ impl RequiredObjectHeader { } #[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct Result(String); +pub struct Result( + String +); impl std::convert::From for Result { fn from(x: String) -> Self { @@ -2607,19 +4175,6 @@ impl std::convert::From for Result { } } -impl std::string::ToString for Result { - fn to_string(&self) -> String { - self.0.to_string() - } -} - -impl std::str::FromStr for Result { - type Err = std::string::ParseError; - fn from_str(x: &str) -> std::result::Result { - std::result::Result::Ok(Result(x.to_string())) - } -} - impl std::convert::From for String { fn from(x: Result) -> Self { x.0 @@ -2639,47 +4194,216 @@ impl std::ops::DerefMut for Result { } } +impl std::fmt::Display for Result { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.clone()) + } +} + +impl std::str::FromStr for Result { + type Err = ::std::convert::Infallible; + fn from_str(x: &str) -> std::result::Result { + std::result::Result::Ok(Result(x.to_owned())) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for Result - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into Result - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Result - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl Result { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] + +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum StringEnum { + #[serde(rename = "FOO")] + Foo, + #[serde(rename = "BAR")] + Bar, +} + +impl std::fmt::Display for StringEnum { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + StringEnum::Foo => write!(f, "FOO"), + StringEnum::Bar => write!(f, "BAR"), + } + } +} + +impl std::str::FromStr for StringEnum { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match s { + "FOO" => std::result::Result::Ok(StringEnum::Foo), + "BAR" => std::result::Result::Ok(StringEnum::Bar), + _ => std::result::Result::Err(format!("Value not valid: {s}")), + } + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for StringEnum - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into StringEnum - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl Result { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. - #[allow(dead_code)] - pub(crate) fn as_xml(&self) -> String { - serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") - } -} - -/// Enumeration of values. -/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` -/// which helps with FFI. -#[allow(non_camel_case_types)] -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)] -#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] -pub enum StringEnum { - #[serde(rename = "FOO")] - Foo, - #[serde(rename = "BAR")] - Bar, -} + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); -impl std::fmt::Display for StringEnum { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - StringEnum::Foo => write!(f, "FOO"), - StringEnum::Bar => write!(f, "BAR"), + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } -impl std::str::FromStr for StringEnum { - type Err = String; +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; - fn from_str(s: &str) -> std::result::Result { - match s { - "FOO" => std::result::Result::Ok(StringEnum::Foo), - "BAR" => std::result::Result::Ok(StringEnum::Bar), - _ => std::result::Result::Err(format!("Value not valid: {}", s)), + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into StringEnum - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), } } } @@ -2694,8 +4418,11 @@ impl StringEnum { } #[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct StringObject(String); +pub struct StringObject( + String +); impl std::convert::From for StringObject { fn from(x: String) -> Self { @@ -2703,19 +4430,6 @@ impl std::convert::From for StringObject { } } -impl std::string::ToString for StringObject { - fn to_string(&self) -> String { - self.0.to_string() - } -} - -impl std::str::FromStr for StringObject { - type Err = std::string::ParseError; - fn from_str(x: &str) -> std::result::Result { - std::result::Result::Ok(StringObject(x.to_string())) - } -} - impl std::convert::From for String { fn from(x: StringObject) -> Self { x.0 @@ -2735,6 +4449,96 @@ impl std::ops::DerefMut for StringObject { } } +impl std::fmt::Display for StringObject { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.clone()) + } +} + +impl std::str::FromStr for StringObject { + type Err = ::std::convert::Infallible; + fn from_str(x: &str) -> std::result::Result { + std::result::Result::Ok(StringObject(x.to_owned())) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for StringObject - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into StringObject - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into StringObject - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl StringObject { /// Helper function to allow us to convert this model to an XML string. @@ -2747,8 +4551,11 @@ impl StringObject { /// Test a model containing a UUID #[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct UuidObject(uuid::Uuid); +pub struct UuidObject( + uuid::Uuid +); impl std::convert::From for UuidObject { fn from(x: uuid::Uuid) -> Self { @@ -2775,6 +4582,106 @@ impl std::ops::DerefMut for UuidObject { } } +/// Converts the UuidObject value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for UuidObject { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a UuidObject value +/// as specified in +/// Should be implemented in a serde deserializer +impl ::std::str::FromStr for UuidObject { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match std::str::FromStr::from_str(s) { + std::result::Result::Ok(r) => std::result::Result::Ok(UuidObject(r)), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {s} to UuidObject: {e:?}")), + } + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for UuidObject - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into UuidObject - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into UuidObject - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl UuidObject { /// Helper function to allow us to convert this model to an XML string. @@ -2787,14 +4694,22 @@ impl UuidObject { // Utility function for wrapping list elements when serializing xml #[allow(non_snake_case)] -fn wrap_in_camelXmlInner(item: &Vec, serializer: S) -> std::result::Result +fn wrap_in_camelXmlInner(items: &Vec, serializer: S) -> std::result::Result where S: serde::ser::Serializer, { - serde_xml_rs::wrap_primitives(item, serializer, "camelXmlInner") + use serde::ser::SerializeMap; + + let mut map = serializer.serialize_map(None)?; + for ref item in items { + map.serialize_key("camelXmlInner")?; + map.serialize_value(item)?; + } + map.end() } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct XmlArray( #[serde(serialize_with = "wrap_in_camelXmlInner")] @@ -2860,16 +4775,16 @@ impl std::ops::DerefMut for XmlArray { } /// Converts the XmlArray value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for XmlArray { - fn to_string(&self) -> String { - self.iter().map(|x| x.to_string()).collect::>().join(",") +impl std::fmt::Display for XmlArray { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.iter().map(|x| x.to_string()).collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a XmlArray value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for XmlArray { type Err = ::Err; @@ -2896,8 +4811,7 @@ impl std::convert::TryFrom> for hyper::header: match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for XmlArray - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for XmlArray - value: {hdr_value} is invalid {e}")) } } } @@ -2912,17 +4826,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into XmlArray - {}", - value, err)) + format!("Unable to convert header value '{value}' into XmlArray - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into XmlArray - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl XmlArray { /// Helper function to allow us to convert this model to an XML string. @@ -2934,9 +4888,12 @@ impl XmlArray { } #[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] + #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] #[serde(rename = "camelXmlInner")] -pub struct XmlInner(String); +pub struct XmlInner( + String +); impl std::convert::From for XmlInner { fn from(x: String) -> Self { @@ -2944,19 +4901,6 @@ impl std::convert::From for XmlInner { } } -impl std::string::ToString for XmlInner { - fn to_string(&self) -> String { - self.0.to_string() - } -} - -impl std::str::FromStr for XmlInner { - type Err = std::string::ParseError; - fn from_str(x: &str) -> std::result::Result { - std::result::Result::Ok(XmlInner(x.to_string())) - } -} - impl std::convert::From for String { fn from(x: XmlInner) -> Self { x.0 @@ -2976,6 +4920,96 @@ impl std::ops::DerefMut for XmlInner { } } +impl std::fmt::Display for XmlInner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.clone()) + } +} + +impl std::str::FromStr for XmlInner { + type Err = ::std::convert::Infallible; + fn from_str(x: &str) -> std::result::Result { + std::result::Result::Ok(XmlInner(x.to_owned())) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for XmlInner - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into XmlInner - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into XmlInner - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl XmlInner { /// Helper function to allow us to convert this model to an XML string. @@ -2987,21 +5021,24 @@ impl XmlInner { } /// An XML object -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] #[serde(rename = "camelXmlObject")] pub struct XmlObject { #[serde(rename = "innerString")] + #[serde(skip_serializing_if="Option::is_none")] pub inner_string: Option, #[serde(rename = "other_inner_rename")] + #[serde(skip_serializing_if="Option::is_none")] pub other_inner_rename: Option, } + impl XmlObject { #[allow(clippy::new_without_default)] pub fn new() -> XmlObject { @@ -3013,35 +5050,31 @@ impl XmlObject { } /// Converts the XmlObject value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for XmlObject { - fn to_string(&self) -> String { +impl std::fmt::Display for XmlObject { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.inner_string.as_ref().map(|inner_string| { [ "innerString".to_string(), inner_string.to_string(), ].join(",") }), - - self.other_inner_rename.as_ref().map(|other_inner_rename| { [ "other_inner_rename".to_string(), other_inner_rename.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a XmlObject value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for XmlObject { type Err = String; @@ -3101,8 +5134,7 @@ impl std::convert::TryFrom> for hyper::header match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for XmlObject - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for XmlObject - value: {hdr_value} is invalid {e}")) } } } @@ -3117,17 +5149,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into XmlObject - {}", - value, err)) + format!("Unable to convert header value '{value}' into XmlObject - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into XmlObject - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl XmlObject { /// Associated constant for this model's XML namespace. @@ -3140,9 +5212,9 @@ impl XmlObject { /// Will panic if serialisation fails. #[allow(dead_code)] pub(crate) fn as_xml(&self) -> String { - let mut namespaces = std::collections::BTreeMap::new(); // An empty string is used to indicate a global namespace in xmltree. - namespaces.insert("".to_string(), Self::NAMESPACE.to_string()); - serde_xml_rs::to_string_with_namespaces(&self, namespaces).expect("impossible to fail to serialize") + let config = serde_xml_rs::SerdeXml::new() + .namespace("", Self::NAMESPACE); + config.to_string(&self).expect("impossible to fail to serialize") } } diff --git a/samples/server/petstore/rust-server/output/openapi-v3/src/server/callbacks.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/server/callbacks.rs index 5bda72e889d5..9a0c9e74650a 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/server/callbacks.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/server/callbacks.rs @@ -1,10 +1,12 @@ use async_trait::async_trait; +use bytes::Bytes; use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt}; +use http_body_util::{combinators::BoxBody, Full}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; -use hyper::{Body, Request, Response, service::Service, Uri}; +use hyper::{body::{Body, Incoming}, Request, Response, service::Service, Uri}; use percent_encoding::{utf8_percent_encode, AsciiSet}; use std::borrow::Cow; -use std::convert::TryInto; +use std::convert::{TryInto, Infallible}; use std::io::{ErrorKind, Read}; use std::error::Error; use std::future::Future; @@ -18,6 +20,7 @@ use std::string::ToString; use std::task::{Context, Poll}; use swagger::{ApiError, AuthData, BodyExt, Connector, DropContextService, Has, XSpanIdString}; use url::form_urlencoded; +use tower_service::Service as _; use crate::models; @@ -42,9 +45,8 @@ use crate::CallbackCallbackPostResponse; /// A client that implements the API by making HTTP calls out to a server. pub struct Client where S: Service< - (Request, C), - Response=Response, - Error=hyper::Error> + Clone + Send + Sync, + (Request>, C), + Response=Response> + Send + Sync + Clone, S::Future: Send + 'static, C: Clone + Send + Sync + 'static { @@ -57,9 +59,8 @@ pub struct Client where impl fmt::Debug for Client where S: Service< - (Request, C), - Response=Response, - Error=hyper::Error> + Clone + Send + Sync, + (Request>, C), + Response=Response> + Send + Sync + Clone, S::Future: Send + 'static, C: Clone + Send + Sync + 'static { @@ -70,9 +71,8 @@ impl fmt::Debug for Client where impl Clone for Client where S: Service< - (Request, C), - Response=Response, - Error=hyper::Error> + Clone + Send + Sync, + (Request>, C), + Response=Response> + Send + Sync + Clone, S::Future: Send + 'static, C: Clone + Send + Sync + 'static { @@ -84,8 +84,8 @@ impl Clone for Client where } } -impl Client, C>, C> where - Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static, +impl Client>>, C>, C> where + Connector: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static, C: Clone + Send + Sync + 'static { /// Create a client with a custom implementation of hyper::client::Connect. @@ -99,10 +99,11 @@ impl Client Self { - let client_service = hyper::client::Client::builder().build(connector); + let client_service = hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector); + let client_service = hyper_util::service::TowerToHyperService::new(client_service); let client_service = DropContextService::new(client_service); Self { @@ -112,7 +113,7 @@ impl Client Client, C>, C> where +impl Client>>, C>, C> where C: Clone + Send + Sync + 'static { /// Create an HTTP client. @@ -122,16 +123,17 @@ impl Client; +#[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] +type HttpsConnector = hyper_tls::HttpsConnector; -#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] -type HttpsConnector = hyper_openssl::HttpsConnector; +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HttpsConnector = hyper_openssl::client::legacy::HttpsConnector; -impl Client, C>, C> where +#[cfg(feature = "client-tls")] +impl Client>>, C>, C> where C: Clone + Send + Sync + 'static { - /// Create a client with a TLS connection to the server. + /// Create a client with a TLS connection to the server using native-tls. #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] pub fn new_https() -> Result { @@ -139,7 +141,7 @@ impl Client, C Ok(Self::new_with_connector(https_connector)) } - /// Create a client with a TLS connection to the server. + /// Create a client with a TLS connection to the server using OpenSSL. #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn new_https() -> Result { @@ -192,9 +194,8 @@ impl Client, C impl Client where S: Service< - (Request, C), - Response=Response, - Error=hyper::Error> + Clone + Send + Sync, + (Request>, C), + Response=Response> + Send + Sync + Clone, S::Future: Send + 'static, C: Clone + Send + Sync + 'static { @@ -214,21 +215,14 @@ impl Client where #[async_trait] impl CallbackApi for Client where S: Service< - (Request, C), - Response=Response, - Error=hyper::Error> + Clone + Send + Sync, + (Request>, C), + Response=Response> + Send + Sync + Clone, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Has + Has> + Clone + Send + Sync, { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - match self.client_service.clone().poll_ready(cx) { - Poll::Ready(Err(e)) => Poll::Ready(Err(Box::new(e))), - Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)), - Poll::Pending => Poll::Pending, - } - } + #[allow(clippy::vec_init_then_push)] async fn callback_callback_with_header_post( &self, callback_request_query_url: String, @@ -236,6 +230,7 @@ impl CallbackApi for Client where context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{request_query_url}/callback-with-header" ,request_query_url=callback_request_query_url @@ -253,21 +248,21 @@ impl CallbackApi for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); // Header parameters @@ -276,12 +271,12 @@ impl CallbackApi for Client where Some(param_information) => { request.headers_mut().append( HeaderName::from_static("information"), - #[allow(clippy::redundant_clone)] + #[allow(clippy::redundant_clone, clippy::clone_on_copy)] match header::IntoHeaderValue(param_information.clone()).try_into() { Ok(header) => header, Err(e) => { return Err(ApiError(format!( - "Invalid header information - {}", e))); + "Invalid header information - {e}"))); }, }); }, @@ -289,7 +284,7 @@ impl CallbackApi for Client where } let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 204 => { @@ -299,30 +294,30 @@ impl CallbackApi for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn callback_callback_post( &self, callback_request_query_url: String, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{request_query_url}/callback" ,request_query_url=callback_request_query_url @@ -340,25 +335,25 @@ impl CallbackApi for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 204 => { @@ -368,18 +363,16 @@ impl CallbackApi for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } diff --git a/samples/server/petstore/rust-server/output/openapi-v3/src/server/mod.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/server/mod.rs index 0c25b4b8887a..edd100657166 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/server/mod.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/server/mod.rs @@ -1,10 +1,14 @@ +use bytes::Bytes; use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt}; -use hyper::{Request, Response, StatusCode, Body, HeaderMap}; +use http_body_util::{combinators::BoxBody, Full}; +use hyper::{body::{Body, Incoming}, HeaderMap, Request, Response, StatusCode}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; use log::warn; +#[cfg(feature = "validate")] +use serde_valid::Validate; #[allow(unused_imports)] use std::convert::{TryFrom, TryInto}; -use std::error::Error; +use std::{convert::Infallible, error::Error}; use std::future::Future; use std::marker::PhantomData; use std::task::{Context, Poll}; @@ -18,13 +22,12 @@ use crate::{models, header, AuthenticationApi}; pub use crate::context; -type ServiceFuture = BoxFuture<'static, Result, crate::ServiceError>>; +type ServiceFuture = BoxFuture<'static, Result>, crate::ServiceError>>; use crate::{Api, AnyOfGetResponse, CallbackWithHeaderPostResponse, ComplexQueryParamGetResponse, - EnumInPathPathParamGetResponse, JsonComplexQueryParamGetResponse, MandatoryRequestHeaderGetResponse, MergePatchJsonGetResponse, @@ -45,6 +48,7 @@ use crate::{Api, XmlOtherPutResponse, XmlPostResponse, XmlPutResponse, + EnumInPathPathParamGetResponse, CreateRepoResponse, GetRepoInfoResponse }; @@ -124,28 +128,52 @@ mod paths { } -pub struct MakeService where +pub struct MakeService +where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { api_impl: T, marker: PhantomData, + validation: bool } -impl MakeService where +impl MakeService +where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { pub fn new(api_impl: T) -> Self { MakeService { api_impl, - marker: PhantomData + marker: PhantomData, + validation: false } } + + // Turn on/off validation for the service being made. + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation; + } } +impl Clone for MakeService +where + T: Api + Clone + Send + 'static, + C: Has + Has> + Send + Sync + 'static +{ + fn clone(&self) -> Self { + Self { + api_impl: self.api_impl.clone(), + marker: PhantomData, + validation: self.validation + } + } +} -impl hyper::service::Service for MakeService where +impl hyper::service::Service for MakeService +where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { @@ -153,43 +181,72 @@ impl hyper::service::Service for MakeService where type Error = crate::ServiceError; type Future = future::Ready>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } + fn call(&self, target: Target) -> Self::Future { + let service = Service::new(self.api_impl.clone(), self.validation); - fn call(&mut self, target: Target) -> Self::Future { - future::ok(Service::new( - self.api_impl.clone(), - )) + future::ok(service) } } -fn method_not_allowed() -> Result, crate::ServiceError> { +fn method_not_allowed() -> Result>, crate::ServiceError> { Ok( Response::builder().status(StatusCode::METHOD_NOT_ALLOWED) - .body(Body::empty()) + .body(BoxBody::new(http_body_util::Empty::new())) .expect("Unable to create Method Not Allowed response") ) } +#[allow(unused_macros)] +#[cfg(not(feature = "validate"))] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => (); +} + +#[allow(unused_macros)] +#[cfg(feature = "validate")] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => { + let $parameter = if $validation { + match $parameter.validate() { + Ok(()) => $parameter, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .header(CONTENT_TYPE, mime::TEXT_PLAIN.as_ref()) + .body(BoxBody::new(format!("Invalid value in body parameter {}: {}", $base_name, e))) + .expect(&format!("Unable to create Bad Request response for invalid value in body parameter {}", $base_name))), + } + } else { + $parameter + }; + } +} + pub struct Service where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { api_impl: T, marker: PhantomData, + // Enable regex pattern validation of received JSON models + validation: bool, } impl Service where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { - pub fn new(api_impl: T) -> Self { + pub fn new(api_impl: T, validation: bool) -> Self { Service { api_impl, - marker: PhantomData + marker: PhantomData, + validation, } } + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation + } + } impl Clone for Service where @@ -200,32 +257,50 @@ impl Clone for Service where Service { api_impl: self.api_impl.clone(), marker: self.marker, + validation: self.validation, } } } -impl hyper::service::Service<(Request, C)> for Service where +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + +fn body_from_str(s: &str) -> BoxBody { + BoxBody::new(Full::new(Bytes::copy_from_slice(s.as_bytes()))) +} + +impl hyper::service::Service<(Request, C)> for Service where T: Api + Clone + Send + Sync + 'static, - C: Has + Has> + Send + Sync + 'static + C: Has + Has> + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, { - type Response = Response; + type Response = Response>; type Error = crate::ServiceError; type Future = ServiceFuture; - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - self.api_impl.poll_ready(cx) - } - - fn call(&mut self, req: (Request, C)) -> Self::Future { async fn run(mut api_impl: T, req: (Request, C)) -> Result, crate::ServiceError> where - T: Api + Clone + Send + 'static, - C: Has + Has> + Send + Sync + 'static - { - let (request, context) = req; - let (parts, body) = request.into_parts(); - let (method, uri, headers) = (parts.method, parts.uri, parts.headers); - let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); - - match method { + fn call(&self, req: (Request, C)) -> Self::Future { + async fn run( + mut api_impl: T, + req: (Request, C), + validation: bool, + ) -> Result>, crate::ServiceError> + where + T: Api + Clone + Send + 'static, + C: Has + Has> + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, + { + let (request, context) = req; + let (parts, body) = request.into_parts(); + let (method, uri, headers) = (parts.method, parts.uri, parts.headers); + let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); + + match method { // AnyOfGet - GET /any-of hyper::Method::GET if path.matched(paths::ID_ANY_OF) => { @@ -244,7 +319,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_any_of.as_ref(), &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -258,10 +333,11 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for ANY_OF_GET_SUCCESS")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, AnyOfGetResponse::AlternateSuccess (body) @@ -269,10 +345,11 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(201).expect("Unable to turn 201 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for ANY_OF_GET_ALTERNATE_SUCCESS")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, AnyOfGetResponse::AnyOfSuccess (body) @@ -280,17 +357,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(202).expect("Unable to turn 202 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for ANY_OF_GET_ANY_OF_SUCCESS")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -312,7 +390,7 @@ impl hyper::service::Service<(Request, C)> for Service where Ok(param_url) => Some(param_url), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse query parameter url - doesn't match schema: {}", e))) + .body(body_from_string(format!("Couldn't parse query parameter url - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid query parameter url")), } }, @@ -322,7 +400,7 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_url) => param_url, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required query parameter url")) + .body(body_from_str("Missing required query parameter url")) .expect("Unable to create Bad Request response for missing query parameter url")), }; @@ -330,7 +408,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_url, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -341,13 +419,14 @@ impl hyper::service::Service<(Request, C)> for Service where CallbackWithHeaderPostResponse::OK => { *response.status_mut() = StatusCode::from_u16(204).expect("Unable to turn 204 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -371,7 +450,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_list_of_strings.as_ref(), &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -382,66 +461,14 @@ impl hyper::service::Service<(Request, C)> for Service where ComplexQueryParamGetResponse::Success => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); - }, - } - - Ok(response) - }, - - // EnumInPathPathParamGet - GET /enum_in_path/{path_param} - hyper::Method::GET if path.matched(paths::ID_ENUM_IN_PATH_PATH_PARAM) => { - // Path parameters - let path: &str = uri.path(); - let path_params = - paths::REGEX_ENUM_IN_PATH_PATH_PARAM - .captures(path) - .unwrap_or_else(|| - panic!("Path {} matched RE ENUM_IN_PATH_PATH_PARAM in set but failed match against \"{}\"", path, paths::REGEX_ENUM_IN_PATH_PATH_PARAM.as_str()) - ); - - let param_path_param = match percent_encoding::percent_decode(path_params["path_param"].as_bytes()).decode_utf8() { - Ok(param_path_param) => match param_path_param.parse::() { - Ok(param_path_param) => param_path_param, - Err(e) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse path parameter path_param: {}", e))) - .expect("Unable to create Bad Request response for invalid path parameter")), - }, - Err(_) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["path_param"]))) - .expect("Unable to create Bad Request response for invalid percent decode")) - }; - let result = api_impl.enum_in_path_path_param_get( - param_path_param, - &context - ).await; - let mut response = Response::new(Body::empty()); - response.headers_mut().insert( - HeaderName::from_static("x-span-id"), - HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) - .expect("Unable to create X-Span-ID header value")); - - match result { - Ok(rsp) => match rsp { - EnumInPathPathParamGetResponse::Success - => { - *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -463,7 +490,7 @@ impl hyper::service::Service<(Request, C)> for Service where Ok(param_list_of_strings) => Some(param_list_of_strings), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse query parameter list-of-strings - doesn't match schema: {}", e))) + .body(body_from_string(format!("Couldn't parse query parameter list-of-strings - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid query parameter list-of-strings")), } }, @@ -474,7 +501,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_list_of_strings.as_ref(), &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -485,13 +512,14 @@ impl hyper::service::Service<(Request, C)> for Service where JsonComplexQueryParamGetResponse::Success => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -510,7 +538,7 @@ impl hyper::service::Service<(Request, C)> for Service where Err(err) => { return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Invalid header X-Header - {}", err))) + .body(body_from_string(format!("Invalid header X-Header - {err}"))) .expect("Unable to create Bad Request response for invalid header X-Header")); }, @@ -518,7 +546,7 @@ impl hyper::service::Service<(Request, C)> for Service where None => { return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required header X-Header")) + .body(body_from_str("Missing required header X-Header")) .expect("Unable to create Bad Request response for missing required header X-Header")); } }; @@ -527,7 +555,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_x_header, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -538,13 +566,14 @@ impl hyper::service::Service<(Request, C)> for Service where MandatoryRequestHeaderGetResponse::Success => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -556,7 +585,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.merge_patch_json_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -570,17 +599,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/merge-patch+json") - .expect("Unable to create Content-Type header for MERGE_PATCH_JSON_GET_MERGE")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/merge-patch+json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -592,7 +622,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.multiget_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -606,10 +636,11 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for MULTIGET_GET_JSON_RSP")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, MultigetGetResponse::XMLRsp (body) @@ -617,10 +648,11 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(201).expect("Unable to turn 201 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/xml") - .expect("Unable to create Content-Type header for MULTIGET_GET_XML_RSP")); - let body_content = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/xml")); + // XML Body + let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, MultigetGetResponse::OctetRsp (body) @@ -628,10 +660,10 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(202).expect("Unable to turn 202 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/octet-stream") - .expect("Unable to create Content-Type header for MULTIGET_GET_OCTET_RSP")); - let body_content = body.0; - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/octet-stream")); + // Binary Body + *response.body_mut() = BoxBody::new(Full::new(Bytes::from(body.0))); + }, MultigetGetResponse::StringRsp (body) @@ -639,10 +671,10 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(203).expect("Unable to turn 203 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("text/plain") - .expect("Unable to create Content-Type header for MULTIGET_GET_STRING_RSP")); - let body_content = body; - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("text/plain")); + // Plain text Body + *response.body_mut() = body_from_string(body); + }, MultigetGetResponse::DuplicateResponseLongText (body) @@ -650,10 +682,11 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(204).expect("Unable to turn 204 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for MULTIGET_GET_DUPLICATE_RESPONSE_LONG_TEXT")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, MultigetGetResponse::DuplicateResponseLongText_2 (body) @@ -661,10 +694,11 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(205).expect("Unable to turn 205 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for MULTIGET_GET_DUPLICATE_RESPONSE_LONG_TEXT_2")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, MultigetGetResponse::DuplicateResponseLongText_3 (body) @@ -672,17 +706,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(206).expect("Unable to turn 206 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for MULTIGET_GET_DUPLICATE_RESPONSE_LONG_TEXT_3")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -696,7 +731,7 @@ impl hyper::service::Service<(Request, C)> for Service where Some(ref authorization) => authorization, None => return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) + .body(body_from_str("Unauthenticated")) .expect("Unable to create Authentication Forbidden response")), }; @@ -711,9 +746,9 @@ impl hyper::service::Service<(Request, C)> for Service where let missing_scopes = required_scopes.difference(scopes); return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from(missing_scopes.fold( + .body(BoxBody::new(missing_scopes.fold( "Insufficient authorization, missing scopes".to_string(), - |s, scope| format!("{} {}", s, scope)) + |s, scope| format!("{s} {scope}")) )) .expect("Unable to create Authentication Insufficient response") ); @@ -724,7 +759,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.multiple_auth_scheme_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -735,13 +770,14 @@ impl hyper::service::Service<(Request, C)> for Service where MultipleAuthSchemeGetResponse::CheckThatLimitingToMultipleRequiredAuthSchemesWorks => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -753,7 +789,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.one_of_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -767,17 +803,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for ONE_OF_GET_SUCCESS")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -789,7 +826,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.override_server_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -800,13 +837,14 @@ impl hyper::service::Service<(Request, C)> for Service where OverrideServerGetResponse::Success => { *response.status_mut() = StatusCode::from_u16(204).expect("Unable to turn 204 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -828,7 +866,7 @@ impl hyper::service::Service<(Request, C)> for Service where Ok(param_uuid) => Some(param_uuid), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse query parameter uuid - doesn't match schema: {}", e))) + .body(body_from_string(format!("Couldn't parse query parameter uuid - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid query parameter uuid")), } }, @@ -845,12 +883,14 @@ impl hyper::service::Service<(Request, C)> for Service where Ok(param_some_object) => Some(param_some_object), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse query parameter someObject - doesn't match schema: {}", e))) + .body(body_from_string(format!("Couldn't parse query parameter someObject - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid query parameter someObject")), } }, None => None, }; + #[cfg(not(feature = "validate"))] + run_validation!(param_some_object, "someObject", validation); let param_some_list = query_params.iter().filter(|e| e.0 == "someList").map(|e| e.1.clone()) .next(); let param_some_list = match param_some_list { @@ -862,12 +902,14 @@ impl hyper::service::Service<(Request, C)> for Service where Ok(param_some_list) => Some(param_some_list), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse query parameter someList - doesn't match schema: {}", e))) + .body(body_from_string(format!("Couldn't parse query parameter someList - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid query parameter someList")), } }, None => None, }; + #[cfg(not(feature = "validate"))] + run_validation!(param_some_list, "someList", validation); let result = api_impl.paramget_get( param_uuid, @@ -875,7 +917,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_some_list, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -889,17 +931,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for PARAMGET_GET_JSON_RSP")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -913,7 +956,7 @@ impl hyper::service::Service<(Request, C)> for Service where Some(ref authorization) => authorization, None => return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) + .body(body_from_str("Unauthenticated")) .expect("Unable to create Authentication Forbidden response")), }; @@ -927,9 +970,9 @@ impl hyper::service::Service<(Request, C)> for Service where let missing_scopes = required_scopes.difference(scopes); return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from(missing_scopes.fold( + .body(BoxBody::new(missing_scopes.fold( "Insufficient authorization, missing scopes".to_string(), - |s, scope| format!("{} {}", s, scope)) + |s, scope| format!("{s} {scope}")) )) .expect("Unable to create Authentication Insufficient response") ); @@ -940,7 +983,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.readonly_auth_scheme_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -951,13 +994,14 @@ impl hyper::service::Service<(Request, C)> for Service where ReadonlyAuthSchemeGetResponse::CheckThatLimitingToASingleRequiredAuthSchemeWorks => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -979,7 +1023,7 @@ impl hyper::service::Service<(Request, C)> for Service where Ok(param_url) => Some(param_url), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse query parameter url - doesn't match schema: {}", e))) + .body(body_from_string(format!("Couldn't parse query parameter url - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid query parameter url")), } }, @@ -989,7 +1033,7 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_url) => param_url, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required query parameter url")) + .body(body_from_str("Missing required query parameter url")) .expect("Unable to create Bad Request response for missing query parameter url")), }; @@ -997,7 +1041,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_url, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1008,13 +1052,14 @@ impl hyper::service::Service<(Request, C)> for Service where RegisterCallbackPostResponse::OK => { *response.status_mut() = StatusCode::from_u16(204).expect("Unable to turn 204 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1023,12 +1068,12 @@ impl hyper::service::Service<(Request, C)> for Service where // RequiredOctetStreamPut - PUT /required_octet_stream hyper::Method::PUT if path.matched(paths::ID_REQUIRED_OCTET_STREAM) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { + Ok(body) => { let param_body: Option = if !body.is_empty() { Some(swagger::ByteArray(body.to_vec())) } else { @@ -1038,15 +1083,16 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_body) => param_body, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter body")) + .body(BoxBody::new("Missing required body parameter body".to_string())) .expect("Unable to create Bad Request response for missing body parameter body")), }; + let result = api_impl.required_octet_stream_put( param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1057,13 +1103,14 @@ impl hyper::service::Service<(Request, C)> for Service where RequiredOctetStreamPutResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1071,8 +1118,8 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, @@ -1081,7 +1128,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.responses_with_headers_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1097,12 +1144,14 @@ impl hyper::service::Service<(Request, C)> for Service where object_header } => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + let success_info = match header::IntoHeaderValue(success_info).try_into() { Ok(val) => val, Err(e) => { return Ok(Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Body::from(format!("An internal server error occurred handling success_info header - {}", e))) + .body(body_from_string(format!("An internal server error occurred handling success_info header - {e}"))) .expect("Unable to create Internal Server Error for invalid response header")) } }; @@ -1111,13 +1160,14 @@ impl hyper::service::Service<(Request, C)> for Service where HeaderName::from_static("success-info"), success_info ); + if let Some(bool_header) = bool_header { let bool_header = match header::IntoHeaderValue(bool_header).try_into() { Ok(val) => val, Err(e) => { return Ok(Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Body::from(format!("An internal server error occurred handling bool_header header - {}", e))) + .body(body_from_string(format!("An internal server error occurred handling bool_header header - {e}"))) .expect("Unable to create Internal Server Error for invalid response header")) } }; @@ -1127,13 +1177,14 @@ impl hyper::service::Service<(Request, C)> for Service where bool_header ); } + if let Some(object_header) = object_header { let object_header = match header::IntoHeaderValue(object_header).try_into() { Ok(val) => val, Err(e) => { return Ok(Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Body::from(format!("An internal server error occurred handling object_header header - {}", e))) + .body(body_from_string(format!("An internal server error occurred handling object_header header - {e}"))) .expect("Unable to create Internal Server Error for invalid response header")) } }; @@ -1143,13 +1194,13 @@ impl hyper::service::Service<(Request, C)> for Service where object_header ); } - *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for RESPONSES_WITH_HEADERS_GET_SUCCESS")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, ResponsesWithHeadersGetResponse::PreconditionFailed { @@ -1157,13 +1208,15 @@ impl hyper::service::Service<(Request, C)> for Service where failure_info } => { + *response.status_mut() = StatusCode::from_u16(412).expect("Unable to turn 412 into a StatusCode"); + if let Some(further_info) = further_info { let further_info = match header::IntoHeaderValue(further_info).try_into() { Ok(val) => val, Err(e) => { return Ok(Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Body::from(format!("An internal server error occurred handling further_info header - {}", e))) + .body(body_from_string(format!("An internal server error occurred handling further_info header - {e}"))) .expect("Unable to create Internal Server Error for invalid response header")) } }; @@ -1173,13 +1226,14 @@ impl hyper::service::Service<(Request, C)> for Service where further_info ); } + if let Some(failure_info) = failure_info { let failure_info = match header::IntoHeaderValue(failure_info).try_into() { Ok(val) => val, Err(e) => { return Ok(Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Body::from(format!("An internal server error occurred handling failure_info header - {}", e))) + .body(body_from_string(format!("An internal server error occurred handling failure_info header - {e}"))) .expect("Unable to create Internal Server Error for invalid response header")) } }; @@ -1189,14 +1243,14 @@ impl hyper::service::Service<(Request, C)> for Service where failure_info ); } - *response.status_mut() = StatusCode::from_u16(412).expect("Unable to turn 412 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1208,7 +1262,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.rfc7807_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1222,10 +1276,11 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(204).expect("Unable to turn 204 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for RFC7807_GET_OK")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, Rfc7807GetResponse::NotFound (body) @@ -1233,10 +1288,11 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/problem+json") - .expect("Unable to create Content-Type header for RFC7807_GET_NOT_FOUND")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/problem+json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, Rfc7807GetResponse::NotAcceptable (body) @@ -1244,17 +1300,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(406).expect("Unable to turn 406 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/problem+xml") - .expect("Unable to create Content-Type header for RFC7807_GET_NOT_ACCEPTABLE")); - let body_content = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/problem+xml")); + // XML Body + let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1263,31 +1320,32 @@ impl hyper::service::Service<(Request, C)> for Service where // UntypedPropertyGet - GET /untyped_property hyper::Method::GET if path.matched(paths::ID_UNTYPED_PROPERTY) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_object_untyped_props: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); - match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) { - Ok(param_object_untyped_props) => param_object_untyped_props, - Err(_) => None, - } + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {path}"); + unused_elements.push(path.to_string()); + }).unwrap_or_default() + } else { None }; + #[cfg(not(feature = "validate"))] + run_validation!(param_object_untyped_props, "ObjectUntypedProps", validation); + let result = api_impl.untyped_property_get( param_object_untyped_props, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1296,22 +1354,22 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { UntypedPropertyGetResponse::CheckThatUntypedPropertiesWorks => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1319,8 +1377,8 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter ObjectUntypedProps: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter ObjectUntypedProps")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, @@ -1329,7 +1387,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.uuid_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1343,17 +1401,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for UUID_GET_DUPLICATE_RESPONSE_LONG_TEXT")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1362,31 +1421,32 @@ impl hyper::service::Service<(Request, C)> for Service where // XmlExtraPost - POST /xml_extra hyper::Method::POST if path.matched(paths::ID_XML_EXTRA) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_duplicate_xml_object: Option = if !body.is_empty() { let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); - match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) { - Ok(param_duplicate_xml_object) => param_duplicate_xml_object, - Err(_) => None, - } + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {path}"); + unused_elements.push(path.to_string()); + }).unwrap_or_default() + } else { None }; + #[cfg(not(feature = "validate"))] + run_validation!(param_duplicate_xml_object, "DuplicateXmlObject", validation); + let result = api_impl.xml_extra_post( param_duplicate_xml_object, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1395,26 +1455,27 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { XmlExtraPostResponse::OK => { *response.status_mut() = StatusCode::from_u16(201).expect("Unable to turn 201 into a StatusCode"); + }, XmlExtraPostResponse::BadRequest => { *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1422,38 +1483,39 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter DuplicateXmlObject: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter DuplicateXmlObject")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, // XmlOtherPost - POST /xml_other hyper::Method::POST if path.matched(paths::ID_XML_OTHER) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_another_xml_object: Option = if !body.is_empty() { let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); - match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) { - Ok(param_another_xml_object) => param_another_xml_object, - Err(_) => None, - } + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {path}"); + unused_elements.push(path.to_string()); + }).unwrap_or_default() + } else { None }; + #[cfg(not(feature = "validate"))] + run_validation!(param_another_xml_object, "AnotherXmlObject", validation); + let result = api_impl.xml_other_post( param_another_xml_object, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1462,10 +1524,9 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { XmlOtherPostResponse::OK @@ -1474,25 +1535,26 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(201).expect("Unable to turn 201 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("text/xml") - .expect("Unable to create Content-Type header for XML_OTHER_POST_OK")); - let mut namespaces = std::collections::BTreeMap::new(); - + HeaderValue::from_static("text/xml")); + // XML Body // An empty string is used to indicate a global namespace in xmltree. - namespaces.insert("".to_string(), models::AnotherXmlObject::NAMESPACE.to_string()); - let body_content = serde_xml_rs::to_string_with_namespaces(&body, namespaces).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + let config = serde_xml_rs::SerdeXml::new() + .namespace("", models::AnotherXmlObject::NAMESPACE); + let body = config.to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, XmlOtherPostResponse::BadRequest => { *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1500,38 +1562,39 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter AnotherXmlObject: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter AnotherXmlObject")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, // XmlOtherPut - PUT /xml_other hyper::Method::PUT if path.matched(paths::ID_XML_OTHER) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_another_xml_array: Option = if !body.is_empty() { let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); - match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) { - Ok(param_another_xml_array) => param_another_xml_array, - Err(_) => None, - } + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {path}"); + unused_elements.push(path.to_string()); + }).unwrap_or_default() + } else { None }; + #[cfg(not(feature = "validate"))] + run_validation!(param_another_xml_array, "AnotherXmlArray", validation); + let result = api_impl.xml_other_put( param_another_xml_array, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1540,26 +1603,27 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { XmlOtherPutResponse::OK => { *response.status_mut() = StatusCode::from_u16(201).expect("Unable to turn 201 into a StatusCode"); + }, XmlOtherPutResponse::BadRequest => { *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1567,38 +1631,39 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter AnotherXmlArray: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter AnotherXmlArray")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, // XmlPost - POST /xml hyper::Method::POST if path.matched(paths::ID_XML) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_xml_array: Option = if !body.is_empty() { let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); - match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) { - Ok(param_xml_array) => param_xml_array, - Err(_) => None, - } + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {path}"); + unused_elements.push(path.to_string()); + }).unwrap_or_default() + } else { None }; + #[cfg(not(feature = "validate"))] + run_validation!(param_xml_array, "XmlArray", validation); + let result = api_impl.xml_post( param_xml_array, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1607,26 +1672,27 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { XmlPostResponse::OK => { *response.status_mut() = StatusCode::from_u16(201).expect("Unable to turn 201 into a StatusCode"); + }, XmlPostResponse::BadRequest => { *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1634,38 +1700,39 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter XmlArray: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter XmlArray")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, // XmlPut - PUT /xml hyper::Method::PUT if path.matched(paths::ID_XML) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_xml_object: Option = if !body.is_empty() { let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); - match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) { - Ok(param_xml_object) => param_xml_object, - Err(_) => None, - } + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {path}"); + unused_elements.push(path.to_string()); + }).unwrap_or_default() + } else { None }; + #[cfg(not(feature = "validate"))] + run_validation!(param_xml_object, "XmlObject", validation); + let result = api_impl.xml_put( param_xml_object, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1674,26 +1741,27 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { XmlPutResponse::OK => { *response.status_mut() = StatusCode::from_u16(201).expect("Unable to turn 201 into a StatusCode"); + }, XmlPutResponse::BadRequest => { *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1701,32 +1769,87 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter XmlObject: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter XmlObject")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, + // EnumInPathPathParamGet - GET /enum_in_path/{path_param} + hyper::Method::GET if path.matched(paths::ID_ENUM_IN_PATH_PATH_PARAM) => { + // Path parameters + let path: &str = uri.path(); + let path_params = + paths::REGEX_ENUM_IN_PATH_PATH_PARAM + .captures(path) + .unwrap_or_else(|| + panic!("Path {} matched RE ENUM_IN_PATH_PATH_PARAM in set but failed match against \"{}\"", path, paths::REGEX_ENUM_IN_PATH_PATH_PARAM.as_str()) + ); + + let param_path_param = match percent_encoding::percent_decode(path_params["path_param"].as_bytes()).decode_utf8() { + Ok(param_path_param) => match param_path_param.parse::() { + Ok(param_path_param) => param_path_param, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Couldn't parse path parameter path_param: {e}"))) + .expect("Unable to create Bad Request response for invalid path parameter")), + }, + Err(_) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["path_param"]))) + .expect("Unable to create Bad Request response for invalid percent decode")) + }; + + let result = api_impl.enum_in_path_path_param_get( + param_path_param, + &context + ).await; + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) + .expect("Unable to create X-Span-ID header value")); + + match result { + Ok(rsp) => match rsp { + EnumInPathPathParamGetResponse::Success + => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = body_from_str("An internal error occurred"); + }, + } + + Ok(response) + }, + // CreateRepo - POST /repos hyper::Method::POST if path.matched(paths::ID_REPOS) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_object_param: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); + warn!("Ignoring unknown field in body: {path}"); unused_elements.push(path.to_string()); }) { Ok(param_object_param) => param_object_param, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter ObjectParam - doesn't match schema: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter ObjectParam - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter ObjectParam due to schema")), } + } else { None }; @@ -1734,15 +1857,18 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_object_param) => param_object_param, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter ObjectParam")) + .body(BoxBody::new("Missing required body parameter ObjectParam".to_string())) .expect("Unable to create Bad Request response for missing body parameter ObjectParam")), }; + #[cfg(not(feature = "validate"))] + run_validation!(param_object_param, "ObjectParam", validation); + let result = api_impl.create_repo( param_object_param, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1751,22 +1877,22 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { CreateRepoResponse::Success => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1774,8 +1900,8 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter ObjectParam: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter ObjectParam")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, @@ -1795,12 +1921,12 @@ impl hyper::service::Service<(Request, C)> for Service where Ok(param_repo_id) => param_repo_id, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse path parameter repoId: {}", e))) + .body(body_from_string(format!("Couldn't parse path parameter repoId: {e}"))) .expect("Unable to create Bad Request response for invalid path parameter")), }, Err(_) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["repoId"]))) + .body(body_from_string(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["repoId"]))) .expect("Unable to create Bad Request response for invalid percent decode")) }; @@ -1808,7 +1934,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_repo_id, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1822,17 +1948,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for GET_REPO_INFO_OK")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1863,11 +1990,17 @@ impl hyper::service::Service<(Request, C)> for Service where _ if path.matched(paths::ID_XML) => method_not_allowed(), _ if path.matched(paths::ID_XML_EXTRA) => method_not_allowed(), _ if path.matched(paths::ID_XML_OTHER) => method_not_allowed(), - _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) - .body(Body::empty()) - .expect("Unable to create Not Found response")) + _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) + .body(BoxBody::new(http_body_util::Empty::new())) + .expect("Unable to create Not Found response")) + } } - } Box::pin(run(self.api_impl.clone(), req)) } + Box::pin(run( + self.api_impl.clone(), + req, + self.validation + )) + } } /// Request parser for `Api`. @@ -1882,8 +2015,6 @@ impl RequestParser for ApiRequestParser { hyper::Method::POST if path.matched(paths::ID_CALLBACK_WITH_HEADER) => Some("CallbackWithHeaderPost"), // ComplexQueryParamGet - GET /complex-query-param hyper::Method::GET if path.matched(paths::ID_COMPLEX_QUERY_PARAM) => Some("ComplexQueryParamGet"), - // EnumInPathPathParamGet - GET /enum_in_path/{path_param} - hyper::Method::GET if path.matched(paths::ID_ENUM_IN_PATH_PATH_PARAM) => Some("EnumInPathPathParamGet"), // JsonComplexQueryParamGet - GET /json-complex-query-param hyper::Method::GET if path.matched(paths::ID_JSON_COMPLEX_QUERY_PARAM) => Some("JsonComplexQueryParamGet"), // MandatoryRequestHeaderGet - GET /mandatory-request-header @@ -1924,6 +2055,8 @@ impl RequestParser for ApiRequestParser { hyper::Method::POST if path.matched(paths::ID_XML) => Some("XmlPost"), // XmlPut - PUT /xml hyper::Method::PUT if path.matched(paths::ID_XML) => Some("XmlPut"), + // EnumInPathPathParamGet - GET /enum_in_path/{path_param} + hyper::Method::GET if path.matched(paths::ID_ENUM_IN_PATH_PATH_PARAM) => Some("EnumInPathPathParamGet"), // CreateRepo - POST /repos hyper::Method::POST if path.matched(paths::ID_REPOS) => Some("CreateRepo"), // GetRepoInfo - GET /repos/{repoId} diff --git a/samples/server/petstore/rust-server/output/openapi-v3/src/server/server_auth.rs b/samples/server/petstore/rust-server/output/openapi-v3/src/server/server_auth.rs index ba78eb2f3f5d..21b1d7babd03 100644 --- a/samples/server/petstore/rust-server/output/openapi-v3/src/server/server_auth.rs +++ b/samples/server/petstore/rust-server/output/openapi-v3/src/server/server_auth.rs @@ -1,11 +1,12 @@ use super::Service; use crate::{Api, AuthenticationApi}; +use headers::authorization::{Basic, Bearer}; use swagger::{ ApiError, - Authorization, - auth::{Basic, Bearer}, - Has, - XSpanIdString}; + Authorization, + Has, + XSpanIdString +}; impl AuthenticationApi for Service where T: Api + Clone + Send + 'static + AuthenticationApi, diff --git a/samples/server/petstore/rust-server/output/ops-v3/.cargo/config.toml b/samples/server/petstore/rust-server/output/ops-v3/.cargo/config.toml new file mode 100644 index 000000000000..df91f0f117f3 --- /dev/null +++ b/samples/server/petstore/rust-server/output/ops-v3/.cargo/config.toml @@ -0,0 +1,19 @@ +[build] +rustflags = [ + "-W", "missing_docs", # detects missing documentation for public members + + "-W", "trivial_casts", # detects trivial casts which could be removed + + "-W", "trivial_numeric_casts", # detects trivial casts of numeric types which could be removed + + # unsafe is used in `TokioIo` bridging code copied from `hyper`. + # "-W", "unsafe_code", # usage of `unsafe` code + + "-W", "unused_qualifications", # detects unnecessarily qualified names + + "-W", "unused_extern_crates", # extern crates that are never used + + "-W", "unused_import_braces", # unnecessary braces around an imported item + + "-D", "warnings", # all warnings should be denied +] diff --git a/samples/server/petstore/rust-server/output/ops-v3/.openapi-generator/FILES b/samples/server/petstore/rust-server/output/ops-v3/.openapi-generator/FILES index f67b7ce47ca8..913ced3d98a4 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/.openapi-generator/FILES +++ b/samples/server/petstore/rust-server/output/ops-v3/.openapi-generator/FILES @@ -1,8 +1,9 @@ -.cargo/config +.cargo/config.toml .gitignore Cargo.toml README.md api/openapi.yaml +bin/cli.rs docs/default_api.md examples/ca.pem examples/client/client_auth.rs diff --git a/samples/server/petstore/rust-server/output/ops-v3/.openapi-generator/VERSION b/samples/server/petstore/rust-server/output/ops-v3/.openapi-generator/VERSION index f1358e30d8ae..f7962df3e243 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/.openapi-generator/VERSION +++ b/samples/server/petstore/rust-server/output/ops-v3/.openapi-generator/VERSION @@ -1 +1 @@ -8.0.0-SNAPSHOT +7.22.0-SNAPSHOT diff --git a/samples/server/petstore/rust-server/output/ops-v3/Cargo.toml b/samples/server/petstore/rust-server/output/ops-v3/Cargo.toml index 10c46d9c2cd1..12c55c614ae5 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/Cargo.toml +++ b/samples/server/petstore/rust-server/output/ops-v3/Cargo.toml @@ -8,74 +8,122 @@ license = "Unlicense" edition = "2018" [features] -default = ["client", "server"] +default = ["client", "server", "client-tls"] client = [ - "hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url" + "hyper", "percent-encoding", "hyper-util/http1", "hyper-util/http2", "url" +] +# TLS support - automatically selects backend based on target OS: +# - macOS/Windows/iOS: native-tls via hyper-tls +# - Other platforms: OpenSSL via hyper-openssl +# Dependencies are in target-specific sections below +client-tls = [ + "client", + "dep:native-tls", + "dep:hyper-tls", + "dep:openssl", + "dep:hyper-openssl", + "swagger/tls" ] server = [ - "serde_ignored", "hyper", "regex", "percent-encoding", "url", "lazy_static" + "serde_ignored", "hyper", "percent-encoding", "url", + "lazy_static", "regex" +] +cli = [ + "anyhow", "clap", "clap-verbosity-flag", "simple_logger", "tokio" ] conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"] -[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] -native-tls = { version = "0.2", optional = true } -hyper-tls = { version = "0.5", optional = true } - -[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] -hyper-openssl = { version = "0.9", optional = true } -openssl = {version = "0.10", optional = true } +mock = ["mockall"] +validate = ["regex", "serde_valid", "swagger/serdevalid"] [dependencies] # Common -async-trait = "0.1.24" +async-trait = "0.1.89" chrono = { version = "0.4", features = ["serde"] } futures = "0.3" -swagger = { version = "6.1", features = ["serdejson", "server", "client", "tls", "tcp"] } -log = "0.4.0" +swagger = { version = "7.0.0", features = ["serdejson", "server", "client"] } +headers = "0.4.1" +log = "0.4.29" + mime = "0.3" +mockall = { version = "0.14", optional = true } + serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -validator = { version = "0.16", features = ["derive"] } +serde_valid = { version = "2.0", optional = true } + +validator = { version = "0.20", features = ["derive"] } # Crates included if required by the API definition # Common between server and client features -hyper = {version = "0.14", features = ["full"], optional = true} -serde_ignored = {version = "0.1.1", optional = true} -url = {version = "2.1", optional = true} +bytes = "1.11" +http-body-util = "0.1.3" +hyper = { version = "1.9.0", features = ["full"], optional = true } +hyper-util = { version = "0.1.20", features = ["service"] } +serde_ignored = { version = "0.1.14", optional = true } +url = { version = "2.5", optional = true } # Client-specific +tower-service = "0.3.3" # Server, and client callback-specific -lazy_static = { version = "1.4", optional = true } -percent-encoding = {version = "2.1.0", optional = true} -regex = {version = "1.3", optional = true} +lazy_static = { version = "1.5", optional = true } +regex = { version = "1.12", optional = true } +percent-encoding = { version = "2.3.2", optional = true } + +# CLI-specific +anyhow = { version = "1", optional = true } +clap = { version = "4.6.0", features = ["env"], optional = true } +clap-verbosity-flag = { version = "3.0", optional = true } +simple_logger = { version = "5.2.0", features = ["stderr"], optional = true } +tokio = { version = "1.50.0", features = ["rt-multi-thread", "macros"], optional = true } # Conversion -frunk = { version = "0.3.0", optional = true } -frunk_derives = { version = "0.3.0", optional = true } -frunk_core = { version = "0.3.0", optional = true } -frunk-enum-derive = { version = "0.2.0", optional = true } -frunk-enum-core = { version = "0.2.0", optional = true } +frunk = { version = "0.4.4", optional = true } +frunk_derives = { version = "0.4.4", optional = true } +frunk_core = { version = "0.4.4", optional = true } +frunk-enum-derive = { version = "0.3.0", optional = true } +frunk-enum-core = { version = "0.3.0", optional = true } -# Bearer authentication -jsonwebtoken = { version = "9.3.0", optional = false } +# TLS dependencies - platform-specific backends +# On macOS/Windows/iOS, use native-tls via hyper-tls +[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] +native-tls = { version = "0.2", optional = true } +hyper-tls = { version = "0.6", optional = true } + +# On other platforms (Linux, etc.), use OpenSSL via hyper-openssl +[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] +openssl = { version = "0.10", optional = true } +hyper-openssl = { version = "0.10", optional = true } [dev-dependencies] -clap = "2.25" -env_logger = "0.7" -tokio = { version = "1.14", features = ["full"] } +always_send = "0.1.1" +clap = "4.6.0" +env_logger = "0.11" +tokio = { version = "1.50.0", features = ["full"] } native-tls = "0.2" +pin-project = "1.1.11" + +# Bearer authentication, used in examples +jsonwebtoken = {version = "10.3.0", features = ["rust_crypto"]} [target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies] -tokio-openssl = "0.6" openssl = "0.10" +tokio-openssl = "0.6" [[example]] -name = "client" +name = "ops-v3-client" +path = "examples/client/main.rs" required-features = ["client"] [[example]] -name = "server" +name = "ops-v3-server" +path = "examples/server/main.rs" required-features = ["server"] + +[[bin]] +name = "ops-v3" +path = "bin/cli.rs" +required-features = ["client", "cli"] diff --git a/samples/server/petstore/rust-server/output/ops-v3/README.md b/samples/server/petstore/rust-server/output/ops-v3/README.md index ffc0a7f123d9..177864b06c73 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/README.md +++ b/samples/server/petstore/rust-server/output/ops-v3/README.md @@ -14,7 +14,7 @@ To see how to make this your own, look here: [README]((https://openapi-generator.tech)) - API version: 0.0.1 -- Generator version: 8.0.0-SNAPSHOT +- Generator version: 7.22.0-SNAPSHOT @@ -23,6 +23,7 @@ This autogenerated project defines an API crate `ops-v3` which contains: * Data types representing the underlying data model. * A `Client` type which implements `Api` and issues HTTP requests for each operation. * A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. +* A CLI tool to drive basic API operations from the command line. It also contains an example server and client which make use of `ops-v3`: @@ -34,77 +35,101 @@ It also contains an example server and client which make use of `ops-v3`: arguments on the command line. You can use the example server and client as a basis for your own code. -See below for [more detail on implementing a server](#writing-a-server). +See below for [more detail on the examples](#using-the-generated-library). + +## CLI + +Run the included CLI tool with: + +``` +cargo run --bin cli --features=cli +``` + +To pass in arguments, put them after `--`, for example: + +``` +cargo run --bin cli --features=cli -- --help +``` + +See the help text for available options. + +To build a standalone tool, use: + +``` +cargo build --bin cli --features=cli --release +``` + +You'll find the binary at `target/release/cli`. ## Examples Run examples with: ``` -cargo run --example +cargo run --example ops-v3- ``` To pass in arguments to the examples, put them after `--`, for example: ``` -cargo run --example client -- --help +cargo run --example ops-v3-client -- --help ``` ### Running the example server To run the server, follow these simple steps: ``` -cargo run --example server +cargo run --example ops-v3-server ``` ### Running the example client To run a client, follow one of the following simple steps: ``` -cargo run --example client Op10Get -cargo run --example client Op11Get -cargo run --example client Op12Get -cargo run --example client Op13Get -cargo run --example client Op14Get -cargo run --example client Op15Get -cargo run --example client Op16Get -cargo run --example client Op17Get -cargo run --example client Op18Get -cargo run --example client Op19Get -cargo run --example client Op1Get -cargo run --example client Op20Get -cargo run --example client Op21Get -cargo run --example client Op22Get -cargo run --example client Op23Get -cargo run --example client Op24Get -cargo run --example client Op25Get -cargo run --example client Op26Get -cargo run --example client Op27Get -cargo run --example client Op28Get -cargo run --example client Op29Get -cargo run --example client Op2Get -cargo run --example client Op30Get -cargo run --example client Op31Get -cargo run --example client Op32Get -cargo run --example client Op33Get -cargo run --example client Op34Get -cargo run --example client Op35Get -cargo run --example client Op36Get -cargo run --example client Op37Get -cargo run --example client Op3Get -cargo run --example client Op4Get -cargo run --example client Op5Get -cargo run --example client Op6Get -cargo run --example client Op7Get -cargo run --example client Op8Get -cargo run --example client Op9Get +cargo run --example ops-v3-client Op10Get +cargo run --example ops-v3-client Op11Get +cargo run --example ops-v3-client Op12Get +cargo run --example ops-v3-client Op13Get +cargo run --example ops-v3-client Op14Get +cargo run --example ops-v3-client Op15Get +cargo run --example ops-v3-client Op16Get +cargo run --example ops-v3-client Op17Get +cargo run --example ops-v3-client Op18Get +cargo run --example ops-v3-client Op19Get +cargo run --example ops-v3-client Op1Get +cargo run --example ops-v3-client Op20Get +cargo run --example ops-v3-client Op21Get +cargo run --example ops-v3-client Op22Get +cargo run --example ops-v3-client Op23Get +cargo run --example ops-v3-client Op24Get +cargo run --example ops-v3-client Op25Get +cargo run --example ops-v3-client Op26Get +cargo run --example ops-v3-client Op27Get +cargo run --example ops-v3-client Op28Get +cargo run --example ops-v3-client Op29Get +cargo run --example ops-v3-client Op2Get +cargo run --example ops-v3-client Op30Get +cargo run --example ops-v3-client Op31Get +cargo run --example ops-v3-client Op32Get +cargo run --example ops-v3-client Op33Get +cargo run --example ops-v3-client Op34Get +cargo run --example ops-v3-client Op35Get +cargo run --example ops-v3-client Op36Get +cargo run --example ops-v3-client Op37Get +cargo run --example ops-v3-client Op3Get +cargo run --example ops-v3-client Op4Get +cargo run --example ops-v3-client Op5Get +cargo run --example ops-v3-client Op6Get +cargo run --example ops-v3-client Op7Get +cargo run --example ops-v3-client Op8Get +cargo run --example ops-v3-client Op9Get ``` ### HTTPS The examples can be run in HTTPS mode by passing in the flag `--https`, for example: ``` -cargo run --example server -- --https +cargo run --example ops-v3-server -- --https ``` This will use the keys/certificates from the examples directory. Note that the @@ -120,8 +145,36 @@ The generated library has a few optional features that can be activated through * `client` * This defaults to enabled and creates the basic skeleton of a client implementation based on hyper * The constructed client implements the API trait by making remote API call. +* `client-tls` + * This default to enabled and provides HTTPS support with automatic TLS backend selection: + - macOS/Windows/iOS: native-tls + hyper-tls + - Linux/Unix/others: OpenSSL + hyper-openssl * `conversions` * This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types. +* `cli` + * This defaults to disabled and is required for building the included CLI tool. +* `validate` + * This defaults to disabled and allows JSON Schema validation of received data using `MakeService::set_validation` or `Service::set_validation`. + * Note, enabling validation will have a performance penalty, especially if the API heavily uses regex based checks. + +### HTTPS/TLS Support + +HTTPS support is included by default. To disable it (for example, to reduce dependencies), you can: + +```toml +[dependencies] +ops-v3 = { version = "0.0.1", default-features = false, features = ["client", "server"] } +``` + +**For server with callbacks that need HTTPS:** +```toml +[dependencies] +ops-v3 = { version = "0.0.1", features = ["server", "client-tls"] } +``` + +The TLS backend is automatically selected based on your target platform: +- **macOS, Windows, iOS**: Uses `native-tls` (system TLS libraries) +- **Linux, Unix, other platforms**: Uses `openssl` See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`. diff --git a/samples/server/petstore/rust-server/output/ops-v3/bin/cli.rs b/samples/server/petstore/rust-server/output/ops-v3/bin/cli.rs new file mode 100644 index 000000000000..372f0362e2bf --- /dev/null +++ b/samples/server/petstore/rust-server/output/ops-v3/bin/cli.rs @@ -0,0 +1,767 @@ +//! CLI tool driving the API client +use anyhow::{anyhow, Context, Result}; +use clap::Parser; +use log::{debug, info}; +// models may be unused if all inputs are primitive types +#[allow(unused_imports)] +use ops_v3::{ + models, ApiNoContext, Client, ContextWrapperExt, + Op10GetResponse, + Op11GetResponse, + Op12GetResponse, + Op13GetResponse, + Op14GetResponse, + Op15GetResponse, + Op16GetResponse, + Op17GetResponse, + Op18GetResponse, + Op19GetResponse, + Op1GetResponse, + Op20GetResponse, + Op21GetResponse, + Op22GetResponse, + Op23GetResponse, + Op24GetResponse, + Op25GetResponse, + Op26GetResponse, + Op27GetResponse, + Op28GetResponse, + Op29GetResponse, + Op2GetResponse, + Op30GetResponse, + Op31GetResponse, + Op32GetResponse, + Op33GetResponse, + Op34GetResponse, + Op35GetResponse, + Op36GetResponse, + Op37GetResponse, + Op3GetResponse, + Op4GetResponse, + Op5GetResponse, + Op6GetResponse, + Op7GetResponse, + Op8GetResponse, + Op9GetResponse, +}; +use simple_logger::SimpleLogger; +use swagger::{AuthData, ContextBuilder, EmptyContext, Push, XSpanIdString}; + +type ClientContext = swagger::make_context_ty!( + ContextBuilder, + EmptyContext, + Option, + XSpanIdString +); + +#[derive(Parser, Debug)] +#[clap( + name = "Regression test for large number of operations", + version = "0.0.1", + about = "CLI access to Regression test for large number of operations" +)] +struct Cli { + #[clap(subcommand)] + operation: Operation, + + /// Address or hostname of the server hosting this API, including optional port + #[clap(short = 'a', long, default_value = "http://localhost")] + server_address: String, + + /// Path to the client private key if using client-side TLS authentication + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_certificate", "server_certificate"]))] + client_key: Option, + + /// Path to the client's public certificate associated with the private key + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_key", "server_certificate"]))] + client_certificate: Option, + + /// Path to CA certificate used to authenticate the server + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long)] + server_certificate: Option, + + /// If set, write output to file instead of stdout + #[clap(short, long)] + output_file: Option, + + #[command(flatten)] + verbosity: clap_verbosity_flag::Verbosity, +} + +#[derive(Parser, Debug)] +enum Operation { + Op10Get { + }, + Op11Get { + }, + Op12Get { + }, + Op13Get { + }, + Op14Get { + }, + Op15Get { + }, + Op16Get { + }, + Op17Get { + }, + Op18Get { + }, + Op19Get { + }, + Op1Get { + }, + Op20Get { + }, + Op21Get { + }, + Op22Get { + }, + Op23Get { + }, + Op24Get { + }, + Op25Get { + }, + Op26Get { + }, + Op27Get { + }, + Op28Get { + }, + Op29Get { + }, + Op2Get { + }, + Op30Get { + }, + Op31Get { + }, + Op32Get { + }, + Op33Get { + }, + Op34Get { + }, + Op35Get { + }, + Op36Get { + }, + Op37Get { + }, + Op3Get { + }, + Op4Get { + }, + Op5Get { + }, + Op6Get { + }, + Op7Get { + }, + Op8Get { + }, + Op9Get { + }, +} + +// On Linux/Unix with OpenSSL (client-tls feature), support certificate pinning and mutual TLS +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + if args.client_certificate.is_some() { + debug!("Using mutual TLS"); + let client = Client::try_new_https_mutual( + &args.server_address, + args.server_certificate.clone().unwrap(), + args.client_key.clone().unwrap(), + args.client_certificate.clone().unwrap(), + ) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else if args.server_certificate.is_some() { + debug!("Using TLS with pinned server certificate"); + let client = + Client::try_new_https_pinned(&args.server_address, args.server_certificate.clone().unwrap()) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else { + debug!("Using client without certificates"); + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) + } +} + +// On macOS/Windows/iOS or without client-tls feature, use simple client (no cert pinning/mutual TLS) +#[cfg(any( + not(feature = "client-tls"), + all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")) +))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + // Client::try_new() automatically detects the URL scheme (http:// or https://) + // and creates the appropriate client. + // Note: Certificate pinning and mutual TLS are only available on Linux/Unix with OpenSSL + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) +} + +#[tokio::main] +async fn main() -> Result<()> { + let args = Cli::parse(); + if let Some(log_level) = args.verbosity.log_level() { + SimpleLogger::new().with_level(log_level.to_level_filter()).init()?; + } + + debug!("Arguments: {:?}", &args); + + let auth_data: Option = None; + + #[allow(trivial_casts)] + let context = swagger::make_context!( + ContextBuilder, + EmptyContext, + auth_data, + XSpanIdString::default() + ); + + let client = create_client(&args, context)?; + + let result = match args.operation { + Operation::Op10Get { + } => { + info!("Performing a Op10Get request"); + + let result = client.op10_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op10GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op11Get { + } => { + info!("Performing a Op11Get request"); + + let result = client.op11_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op11GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op12Get { + } => { + info!("Performing a Op12Get request"); + + let result = client.op12_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op12GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op13Get { + } => { + info!("Performing a Op13Get request"); + + let result = client.op13_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op13GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op14Get { + } => { + info!("Performing a Op14Get request"); + + let result = client.op14_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op14GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op15Get { + } => { + info!("Performing a Op15Get request"); + + let result = client.op15_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op15GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op16Get { + } => { + info!("Performing a Op16Get request"); + + let result = client.op16_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op16GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op17Get { + } => { + info!("Performing a Op17Get request"); + + let result = client.op17_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op17GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op18Get { + } => { + info!("Performing a Op18Get request"); + + let result = client.op18_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op18GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op19Get { + } => { + info!("Performing a Op19Get request"); + + let result = client.op19_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op19GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op1Get { + } => { + info!("Performing a Op1Get request"); + + let result = client.op1_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op1GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op20Get { + } => { + info!("Performing a Op20Get request"); + + let result = client.op20_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op20GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op21Get { + } => { + info!("Performing a Op21Get request"); + + let result = client.op21_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op21GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op22Get { + } => { + info!("Performing a Op22Get request"); + + let result = client.op22_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op22GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op23Get { + } => { + info!("Performing a Op23Get request"); + + let result = client.op23_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op23GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op24Get { + } => { + info!("Performing a Op24Get request"); + + let result = client.op24_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op24GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op25Get { + } => { + info!("Performing a Op25Get request"); + + let result = client.op25_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op25GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op26Get { + } => { + info!("Performing a Op26Get request"); + + let result = client.op26_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op26GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op27Get { + } => { + info!("Performing a Op27Get request"); + + let result = client.op27_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op27GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op28Get { + } => { + info!("Performing a Op28Get request"); + + let result = client.op28_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op28GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op29Get { + } => { + info!("Performing a Op29Get request"); + + let result = client.op29_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op29GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op2Get { + } => { + info!("Performing a Op2Get request"); + + let result = client.op2_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op2GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op30Get { + } => { + info!("Performing a Op30Get request"); + + let result = client.op30_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op30GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op31Get { + } => { + info!("Performing a Op31Get request"); + + let result = client.op31_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op31GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op32Get { + } => { + info!("Performing a Op32Get request"); + + let result = client.op32_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op32GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op33Get { + } => { + info!("Performing a Op33Get request"); + + let result = client.op33_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op33GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op34Get { + } => { + info!("Performing a Op34Get request"); + + let result = client.op34_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op34GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op35Get { + } => { + info!("Performing a Op35Get request"); + + let result = client.op35_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op35GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op36Get { + } => { + info!("Performing a Op36Get request"); + + let result = client.op36_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op36GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op37Get { + } => { + info!("Performing a Op37Get request"); + + let result = client.op37_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op37GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op3Get { + } => { + info!("Performing a Op3Get request"); + + let result = client.op3_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op3GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op4Get { + } => { + info!("Performing a Op4Get request"); + + let result = client.op4_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op4GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op5Get { + } => { + info!("Performing a Op5Get request"); + + let result = client.op5_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op5GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op6Get { + } => { + info!("Performing a Op6Get request"); + + let result = client.op6_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op6GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op7Get { + } => { + info!("Performing a Op7Get request"); + + let result = client.op7_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op7GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op8Get { + } => { + info!("Performing a Op8Get request"); + + let result = client.op8_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op8GetResponse::OK + => "OK\n".to_string() + , + } + } + Operation::Op9Get { + } => { + info!("Performing a Op9Get request"); + + let result = client.op9_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + Op9GetResponse::OK + => "OK\n".to_string() + , + } + } + }; + + if let Some(output_file) = args.output_file { + std::fs::write(output_file, result)? + } else { + println!("{}", result); + } + Ok(()) +} + +// May be unused if all inputs are primitive types +#[allow(dead_code)] +fn parse_json(json_string: &str) -> Result { + serde_json::from_str(json_string).map_err(|err| anyhow!("Error parsing input: {}", err)) +} diff --git a/samples/server/petstore/rust-server/output/ops-v3/examples/client/main.rs b/samples/server/petstore/rust-server/output/ops-v3/examples/client/main.rs index 570a14467c92..6a5096b74b0a 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/examples/client/main.rs +++ b/samples/server/petstore/rust-server/output/ops-v3/examples/client/main.rs @@ -43,7 +43,7 @@ use ops_v3::{Api, ApiNoContext, Claims, Client, ContextWrapperExt, models, Op8GetResponse, Op9GetResponse, }; -use clap::{App, Arg}; +use clap::{Command, Arg}; // NOTE: Set environment variable RUST_LOG to the name of the executable (or "cargo run") to activate console logging for all loglevels. // See https://docs.rs/env_logger/latest/env_logger/ for more details @@ -66,61 +66,59 @@ use client_auth::build_token; fn main() { env_logger::init(); - let matches = App::new("client") - .arg(Arg::with_name("operation") + let matches = Command::new("client") + .arg(Arg::new("operation") .help("Sets the operation to run") - .possible_values(&[ - "Op10Get", - "Op11Get", - "Op12Get", - "Op13Get", - "Op14Get", - "Op15Get", - "Op16Get", - "Op17Get", - "Op18Get", - "Op19Get", - "Op1Get", - "Op20Get", - "Op21Get", - "Op22Get", - "Op23Get", - "Op24Get", - "Op25Get", - "Op26Get", - "Op27Get", - "Op28Get", - "Op29Get", - "Op2Get", - "Op30Get", - "Op31Get", - "Op32Get", - "Op33Get", - "Op34Get", - "Op35Get", - "Op36Get", - "Op37Get", - "Op3Get", - "Op4Get", - "Op5Get", - "Op6Get", - "Op7Get", - "Op8Get", - "Op9Get", - ]) + .value_parser(Vec::<&str>::from([ + "Op10Get", + "Op11Get", + "Op12Get", + "Op13Get", + "Op14Get", + "Op15Get", + "Op16Get", + "Op17Get", + "Op18Get", + "Op19Get", + "Op1Get", + "Op20Get", + "Op21Get", + "Op22Get", + "Op23Get", + "Op24Get", + "Op25Get", + "Op26Get", + "Op27Get", + "Op28Get", + "Op29Get", + "Op2Get", + "Op30Get", + "Op31Get", + "Op32Get", + "Op33Get", + "Op34Get", + "Op35Get", + "Op36Get", + "Op37Get", + "Op3Get", + "Op4Get", + "Op5Get", + "Op6Get", + "Op7Get", + "Op8Get", + "Op9Get", + ])) .required(true) .index(1)) - .arg(Arg::with_name("https") + .arg(Arg::new("https") .long("https") .help("Whether to use HTTPS or not")) - .arg(Arg::with_name("host") + .arg(Arg::new("host") .long("host") - .takes_value(true) .default_value("localhost") .help("Hostname to contact")) - .arg(Arg::with_name("port") + .arg(Arg::new("port") .long("port") - .takes_value(true) .default_value("8080") .help("Port to contact")) .get_matches(); @@ -129,53 +127,68 @@ fn main() { // In a real (production) system this Bearer token should be obtained via an external Identity/Authentication-server // Ensure that you set the correct algorithm and encodingkey that matches what is used on the server side. // See https://github.com/Keats/jsonwebtoken for more information - let auth_token = build_token( Claims { - sub: "tester@acme.com".to_owned(), + sub: "tester@acme.com".to_owned(), company: "ACME".to_owned(), iss: "my_identity_provider".to_owned(), // added a very long expiry time aud: "org.acme.Resource_Server".to_string(), exp: 10000000000, // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ - ].join(", ") - }, + scopes: + "".to_owned() + }, b"secret").unwrap(); let auth_data = if !auth_token.is_empty() { - Some(AuthData::Bearer(swagger::auth::Bearer { token: auth_token})) + Some(AuthData::Bearer(auth_token)) } else { // No Bearer-token available, so return None None }; - let is_https = matches.is_present("https"); + let is_https = matches.contains_id("https"); let base_url = format!("{}://{}:{}", if is_https { "https" } else { "http" }, - matches.value_of("host").unwrap(), - matches.value_of("port").unwrap()); + matches.get_one::("host").unwrap(), + matches.get_one::("port").unwrap()); let context: ClientContext = swagger::make_context!(ContextBuilder, EmptyContext, auth_data, XSpanIdString::default()); - let mut client : Box> = if matches.is_present("https") { - // Using Simple HTTPS - let client = Box::new(Client::try_new_https(&base_url) - .expect("Failed to create HTTPS client")); - Box::new(client.with_context(context)) - } else { - // Using HTTP - let client = Box::new(Client::try_new_http( - &base_url) - .expect("Failed to create HTTP client")); - Box::new(client.with_context(context)) + let mut client : Box> = { + #[cfg(feature = "client-tls")] + { + if is_https { + // Using HTTPS with native-tls + let client = Box::new(Client::try_new_https(&base_url) + .expect("Failed to create HTTPS client")); + Box::new(client.with_context(context)) + } else { + // Using HTTP + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } + } + + #[cfg(not(feature = "client-tls"))] + { + if is_https { + panic!("HTTPS requested but TLS support not enabled. \ + Enable the 'client-tls' feature to use HTTPS."); + } + // Using HTTP only + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } }; let mut rt = tokio::runtime::Runtime::new().unwrap(); - match matches.value_of("operation") { + match matches.get_one::("operation").map(String::as_str) { Some("Op10Get") => { let result = rt.block_on(client.op10_get( )); diff --git a/samples/server/petstore/rust-server/output/ops-v3/examples/server/main.rs b/samples/server/petstore/rust-server/output/ops-v3/examples/server/main.rs index 227fe7e73155..b1a734a43442 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/examples/server/main.rs +++ b/samples/server/petstore/rust-server/output/ops-v3/examples/server/main.rs @@ -3,26 +3,26 @@ #![allow(missing_docs)] - -use clap::{App, Arg}; +use clap::{Arg, Command}; mod server; mod server_auth; - /// Create custom server, wire it to the autogenerated router, /// and pass it to the web server. #[tokio::main] async fn main() { env_logger::init(); - let matches = App::new("server") - .arg(Arg::with_name("https") - .long("https") - .help("Whether to use HTTPS or not")) + let matches = Command::new("server") + .arg( + Arg::new("https") + .long("https") + .help("Whether to use HTTPS or not"), + ) .get_matches(); let addr = "127.0.0.1:8080"; - server::create(addr, matches.is_present("https")).await; + server::create(addr, matches.contains_id("https")).await; } diff --git a/samples/server/petstore/rust-server/output/ops-v3/examples/server/server.rs b/samples/server/petstore/rust-server/output/ops-v3/examples/server/server.rs index 9f97fa0f3b4f..9aa4b96bdf32 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/examples/server/server.rs +++ b/samples/server/petstore/rust-server/output/ops-v3/examples/server/server.rs @@ -4,8 +4,9 @@ use async_trait::async_trait; use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt}; -use hyper::server::conn::Http; -use hyper::service::Service; +use hyper::server::conn::http1; +use hyper_util::rt::TokioIo; +use hyper::service::{service_fn, Service}; use log::info; use std::future::Future; use std::marker::PhantomData; @@ -24,15 +25,13 @@ use ops_v3::models; /// Builds an SSL implementation for Simple HTTPS from some hard-coded file names pub async fn create(addr: &str, https: bool) { - let addr = addr.parse().expect("Failed to parse bind address"); + let addr: SocketAddr = addr.parse().expect("Failed to parse bind address"); + let listener = TcpListener::bind(&addr).await.unwrap(); let server = Server::new(); let service = MakeService::new(server); - - // This pushes a fourth layer of the middleware-stack even though Swagger assumes only three levels. - // This fourth layer creates an accept-all policy, hower the example-code already acchieves the same via a Bearer-token with full permissions, so next line is not needed (anymore). - // let service = MakeAllowAllAuthenticator::new(service, "cosmo"); + let service = MakeAllowAllAuthenticator::new(service, "cosmo"); #[allow(unused_mut)] let mut service = @@ -56,21 +55,19 @@ pub async fn create(addr: &str, https: bool) { ssl.check_private_key().expect("Failed to check private key"); let tls_acceptor = ssl.build(); - let tcp_listener = TcpListener::bind(&addr).await.unwrap(); info!("Starting a server (with https)"); loop { - if let Ok((tcp, _)) = tcp_listener.accept().await { + if let Ok((tcp, addr)) = listener.accept().await { let ssl = Ssl::new(tls_acceptor.context()).unwrap(); - let addr = tcp.peer_addr().expect("Unable to get remote address"); let service = service.call(addr); tokio::spawn(async move { let tls = tokio_openssl::SslStream::new(ssl, tcp).map_err(|_| ())?; let service = service.await.map_err(|_| ())?; - Http::new() - .serve_connection(tls, service) + http1::Builder::new() + .serve_connection(TokioIo::new(tls), service) .await .map_err(|_| ()) }); @@ -79,12 +76,40 @@ pub async fn create(addr: &str, https: bool) { } } else { info!("Starting a server (over http, so no TLS)"); - // Using HTTP - hyper::server::Server::bind(&addr).serve(service).await.unwrap() + println!("Listening on http://{}", addr); + + loop { + // When an incoming TCP connection is received grab a TCP stream for + // client<->server communication. + // + // Note, this is a .await point, this loop will loop forever but is not a busy loop. The + // .await point allows the Tokio runtime to pull the task off of the thread until the task + // has work to do. In this case, a connection arrives on the port we are listening on and + // the task is woken up, at which point the task is then put back on a thread, and is + // driven forward by the runtime, eventually yielding a TCP stream. + let (tcp_stream, addr) = listener.accept().await.expect("Failed to accept connection"); + + let service = service.call(addr).await.unwrap(); + let io = TokioIo::new(tcp_stream); + // Spin up a new task in Tokio so we can continue to listen for new TCP connection on the + // current task without waiting for the processing of the HTTP1 connection we just received + // to finish + tokio::task::spawn(async move { + // Handle the connection from the client using HTTP1 and pass any + // HTTP requests received on that connection to the `hello` function + let result = http1::Builder::new() + .serve_connection(io, service) + .await; + if let Err(err) = result + { + println!("Error serving connection: {err:?}"); + } + }); + } } } -#[derive(Copy, Clone)] +#[derive(Copy)] pub struct Server { marker: PhantomData, } @@ -95,6 +120,14 @@ impl Server { } } +impl Clone for Server { + fn clone(&self) -> Self { + Self { + marker: PhantomData, + } + } +} + use jsonwebtoken::{decode, encode, errors::Error as JwtError, Algorithm, DecodingKey, EncodingKey, Header, TokenData, Validation}; use serde::{Deserialize, Serialize}; diff --git a/samples/server/petstore/rust-server/output/ops-v3/examples/server/server_auth.rs b/samples/server/petstore/rust-server/output/ops-v3/examples/server/server_auth.rs index 07851419c3e6..6e331a6b7ab1 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/examples/server/server_auth.rs +++ b/samples/server/petstore/rust-server/output/ops-v3/examples/server/server_auth.rs @@ -1,8 +1,8 @@ use swagger::{ ApiError, - auth::{Basic, Bearer}, - Has, + Has, XSpanIdString}; +use headers::authorization::{Basic, Bearer}; use ops_v3::{AuthenticationApi, Claims}; use crate::server::Server; use jsonwebtoken::{decode, errors as JwtError, decode_header, DecodingKey, TokenData, Validation}; @@ -15,24 +15,24 @@ use log::{error, debug}; /// Get a dummy claim with full permissions (all scopes) for testing purposes fn full_permission_claim() -> Claims { - Claims { - sub: "tester@acme.com".to_owned(), - company: "ACME".to_owned(), - iss: "mini-bank-IDP".to_owned(), - aud: "org.acme.Resource_Server".to_string(), - // added a very long expiry time - exp: 10000000000, - // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ - ].join(", ") - } + // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. + Claims { + sub: "tester@acme.com".to_owned(), + company: "ACME".to_owned(), + iss: "mini-bank-IDP".to_owned(), + aud: "org.acme.Resource_Server".to_string(), + // added a very long expiry time + exp: 10000000000, + scopes: + "".to_owned() + } } -/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. +/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. fn extract_token_data(token: &str, key: &[u8]) -> Result, JwtError::Error> { - + // Ensure that you set the correct algorithm and correct key. // See https://github.com/Keats/jsonwebtoken for more information. let header = decode_header(token)?; @@ -63,8 +63,8 @@ fn build_authorization(claims: Claims) -> Authorization { let scopes = swagger::auth::Scopes::Some(scopes); Authorization{ - subject: claims.sub, - scopes, + subject: claims.sub, + scopes, issuer: Some(claims.iss)} } @@ -87,7 +87,7 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn bearer_authorization(&self, bearer: &Bearer) -> Result { debug!("\tAuthorizationApi: Received Bearer-token, {bearer:#?}"); - match extract_token_data(&bearer.token, b"secret") { + match extract_token_data(&bearer.token(), b"secret") { Ok(auth_data) => { debug!("\tUnpack auth_data as: {auth_data:#?}"); let authorization = build_authorization(auth_data.claims); @@ -105,23 +105,22 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn apikey_authorization(&self, api_key: &str) -> Result { debug!("\tAuthorizationApi: Received api-key, {api_key:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } - + /// Implementation of the method to map a basic authentication (username and password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result { debug!("\tAuthorizationApi: Received Basic-token, {basic:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } -} - +} diff --git a/samples/server/petstore/rust-server/output/ops-v3/src/auth.rs b/samples/server/petstore/rust-server/output/ops-v3/src/auth.rs index cbaba3dca7c6..a6a39f79450f 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/src/auth.rs +++ b/samples/server/petstore/rust-server/output/ops-v3/src/auth.rs @@ -1,8 +1,7 @@ use std::collections::BTreeSet; -use crate::server::Authorization; use serde::{Deserialize, Serialize}; -use swagger::{ApiError, auth::{Basic, Bearer}}; - +use swagger::{ApiError, auth::Authorization}; +use headers::authorization::{Basic, Bearer}; #[derive(Debug, Serialize, Deserialize)] pub struct Claims { pub sub: String, @@ -24,7 +23,7 @@ pub trait AuthenticationApi { /// Method should be implemented (see example-code) to map Basic (Username:password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result; -} +} // Implement it for AllowAllAuthenticator (dummy is needed, but should not used as we have Bearer authorization) use swagger::auth::{AllowAllAuthenticator, RcBound, Scopes}; @@ -34,7 +33,7 @@ fn dummy_authorization() -> Authorization { // However, if you want to use it anyway this can not be unimplemented, so dummy implementation added. // unimplemented!() Authorization{ - subject: "Dummmy".to_owned(), + subject: "Dummy".to_owned(), scopes: Scopes::Some(BTreeSet::new()), // create an empty scope, as this should not be used issuer: None } diff --git a/samples/server/petstore/rust-server/output/ops-v3/src/client/mod.rs b/samples/server/petstore/rust-server/output/ops-v3/src/client/mod.rs index f3dbc73c9892..b9035f6e45b0 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/src/client/mod.rs +++ b/samples/server/petstore/rust-server/output/ops-v3/src/client/mod.rs @@ -1,10 +1,12 @@ use async_trait::async_trait; +use bytes::Bytes; use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt}; +use http_body_util::{combinators::BoxBody, Full}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; -use hyper::{Body, Request, Response, service::Service, Uri}; +use hyper::{body::{Body, Incoming}, Request, Response, service::Service, Uri}; use percent_encoding::{utf8_percent_encode, AsciiSet}; use std::borrow::Cow; -use std::convert::TryInto; +use std::convert::{TryInto, Infallible}; use std::io::{ErrorKind, Read}; use std::error::Error; use std::future::Future; @@ -18,6 +20,7 @@ use std::string::ToString; use std::task::{Context, Poll}; use swagger::{ApiError, AuthData, BodyExt, Connector, DropContextService, Has, XSpanIdString}; use url::form_urlencoded; +use tower_service::Service as _; use crate::models; @@ -90,15 +93,14 @@ fn into_base_path(input: impl TryInto, } let host = uri.host().ok_or(ClientInitError::MissingHost)?; - let port = uri.port_u16().map(|x| format!(":{}", x)).unwrap_or_default(); - Ok(format!("{}://{}{}{}", scheme, host, port, uri.path().trim_end_matches('/'))) + let port = uri.port_u16().map(|x| format!(":{x}")).unwrap_or_default(); + Ok(format!("{scheme}://{host}{port}{}", uri.path().trim_end_matches('/'))) } /// A client that implements the API by making HTTP calls out to a server. pub struct Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -115,8 +117,7 @@ pub struct Client where impl fmt::Debug for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -128,8 +129,7 @@ impl fmt::Debug for Client where impl Clone for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -143,8 +143,19 @@ impl Clone for Client where } } -impl Client, C>, C> where - Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static, +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + Connector, + BoxBody + > + >, + C + >, + C +> where + Connector: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static, C: Clone + Send + Sync + 'static, { /// Create a client with a custom implementation of hyper::client::Connect. @@ -158,7 +169,7 @@ impl Client" /// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")` /// * `connector` - Implementation of `hyper::client::Connect` to use for the client pub fn try_new_with_connector( @@ -167,8 +178,8 @@ impl Client Result { - let client_service = hyper::client::Client::builder().build(connector); - let client_service = DropContextService::new(client_service); + let client_service = hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector); + let client_service = DropContextService::new(hyper_util::service::TowerToHyperService::new(client_service)); Ok(Self { client_service, @@ -178,28 +189,29 @@ impl Client; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HyperHttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + #[derive(Debug, Clone)] pub enum HyperClient { - Http(hyper::client::Client), - Https(hyper::client::Client), + Http(hyper_util::client::legacy::Client>), + #[cfg(feature = "client-tls")] + Https(hyper_util::client::legacy::Client>), } -impl Service> for HyperClient { - type Response = Response; - type Error = hyper::Error; - type Future = hyper::client::ResponseFuture; - - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - match self { - HyperClient::Http(client) => client.poll_ready(cx), - HyperClient::Https(client) => client.poll_ready(cx), - } - } +impl Service>> for HyperClient { + type Response = Response; + type Error = hyper_util::client::legacy::Error; + type Future = hyper_util::client::legacy::ResponseFuture; - fn call(&mut self, req: Request) -> Self::Future { + fn call(&self, req: Request>) -> Self::Future { match self { - HyperClient::Http(client) => client.call(req), - HyperClient::Https(client) => client.call(req) + HyperClient::Http(client) => client.request(req), + #[cfg(feature = "client-tls")] + HyperClient::Https(client) => client.request(req), } } } @@ -210,7 +222,7 @@ impl Client, C> where /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new( base_path: &str, ) -> Result { @@ -223,13 +235,19 @@ impl Client, C> where let client_service = match scheme.as_str() { "http" => { - HyperClient::Http(hyper::client::Client::builder().build(connector.build())) + HyperClient::Http(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector.build())) + }, + #[cfg(feature = "client-tls")] + "https" => { + let https_connector = connector + .https() + .build() + .map_err(ClientInitError::SslError)?; + HyperClient::Https(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(https_connector)) }, + #[cfg(not(feature = "client-tls"))] "https" => { - let connector = connector.https() - .build() - .map_err(ClientInitError::SslError)?; - HyperClient::Https(hyper::client::Client::builder().build(connector)) + return Err(ClientInitError::TlsNotEnabled); }, _ => { return Err(ClientInitError::InvalidScheme); @@ -246,13 +264,24 @@ impl Client, C> where } } -impl Client, C>, C> where +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + hyper_util::client::legacy::connect::HttpConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new_http( base_path: &str, ) -> Result { @@ -262,19 +291,46 @@ impl Client; - -#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] -type HttpsConnector = hyper_openssl::HttpsConnector; - -impl Client, C>, C> where +#[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] +type HttpsConnector = hyper_tls::HttpsConnector; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + +#[cfg(feature = "client-tls")] +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + HttpsConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { - /// Create a client with a TLS connection to the server + /// Create a client with a TLS connection to the server. + /// + /// # Arguments + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + pub fn try_new_https(base_path: &str) -> Result + { + let https_connector = Connector::builder() + .https() + .build() + .map_err(ClientInitError::SslError)?; + Self::try_new_with_connector(base_path, Some("https"), https_connector) + } + + /// Create a client with a TLS connection to the server using OpenSSL via swagger. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn try_new_https(base_path: &str) -> Result { let https_connector = Connector::builder() @@ -284,10 +340,10 @@ impl Client, C Self::try_new_with_connector(base_path, Some("https"), https_connector) } - /// Create a client with a TLS connection to the server using a pinned certificate + /// Create a client with a TLS connection to the server using a pinned certificate. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn try_new_https_pinned( @@ -308,7 +364,7 @@ impl Client, C /// Create a client with a mutually authenticated TLS connection to the server. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server /// * `client_key` - Path to the client private key /// * `client_certificate` - Path to the client's public certificate associated with the private key @@ -336,8 +392,7 @@ impl Client, C impl Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -371,12 +426,15 @@ pub enum ClientInitError { /// Missing Hostname MissingHost, + /// HTTPS requested but TLS features not enabled + TlsNotEnabled, + /// SSL Connection Error - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + #[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] SslError(native_tls::Error), /// SSL Connection Error - #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] SslError(openssl::error::ErrorStack), } @@ -399,28 +457,31 @@ impl Error for ClientInitError { } } +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + #[async_trait] -impl Api for Client where +impl Api for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C), + Response=Response> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Has + Clone + Send + Sync + 'static, + B: hyper::body::Body + Send + 'static + Unpin, + B::Data: Send, + B::Error: Into>, { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - match self.client_service.clone().poll_ready(cx) { - Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())), - Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)), - Poll::Pending => Poll::Pending, - } - } + #[allow(clippy::vec_init_then_push)] async fn op10_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op10", self.base_path @@ -438,25 +499,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -466,29 +527,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op11_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op11", self.base_path @@ -506,25 +567,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -534,29 +595,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op12_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op12", self.base_path @@ -574,25 +635,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -602,29 +663,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op13_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op13", self.base_path @@ -642,25 +703,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -670,29 +731,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op14_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op14", self.base_path @@ -710,25 +771,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -738,29 +799,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op15_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op15", self.base_path @@ -778,25 +839,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -806,29 +867,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op16_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op16", self.base_path @@ -846,25 +907,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -874,29 +935,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op17_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op17", self.base_path @@ -914,25 +975,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -942,29 +1003,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op18_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op18", self.base_path @@ -982,25 +1043,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1010,29 +1071,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op19_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op19", self.base_path @@ -1050,25 +1111,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1078,29 +1139,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op1_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op1", self.base_path @@ -1118,25 +1179,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1146,29 +1207,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op20_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op20", self.base_path @@ -1186,25 +1247,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1214,29 +1275,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op21_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op21", self.base_path @@ -1254,25 +1315,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1282,29 +1343,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op22_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op22", self.base_path @@ -1322,25 +1383,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1350,29 +1411,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op23_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op23", self.base_path @@ -1390,25 +1451,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1418,29 +1479,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op24_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op24", self.base_path @@ -1458,25 +1519,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1486,29 +1547,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op25_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op25", self.base_path @@ -1526,25 +1587,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1554,29 +1615,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op26_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op26", self.base_path @@ -1594,25 +1655,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1622,29 +1683,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op27_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op27", self.base_path @@ -1662,25 +1723,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1690,29 +1751,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op28_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op28", self.base_path @@ -1730,25 +1791,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1758,29 +1819,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op29_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op29", self.base_path @@ -1798,25 +1859,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1826,29 +1887,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op2_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op2", self.base_path @@ -1866,25 +1927,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1894,29 +1955,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op30_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op30", self.base_path @@ -1934,25 +1995,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1962,29 +2023,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op31_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op31", self.base_path @@ -2002,25 +2063,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2030,29 +2091,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op32_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op32", self.base_path @@ -2070,25 +2131,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2098,29 +2159,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op33_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op33", self.base_path @@ -2138,25 +2199,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2166,29 +2227,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op34_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op34", self.base_path @@ -2206,25 +2267,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2234,29 +2295,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op35_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op35", self.base_path @@ -2274,25 +2335,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2302,29 +2363,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op36_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op36", self.base_path @@ -2342,25 +2403,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2370,29 +2431,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op37_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op37", self.base_path @@ -2410,25 +2471,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2438,29 +2499,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op3_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op3", self.base_path @@ -2478,25 +2539,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2506,29 +2567,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op4_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op4", self.base_path @@ -2546,25 +2607,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2574,29 +2635,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op5_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op5", self.base_path @@ -2614,25 +2675,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2642,29 +2703,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op6_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op6", self.base_path @@ -2682,25 +2743,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2710,29 +2771,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op7_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op7", self.base_path @@ -2750,25 +2811,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2778,29 +2839,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op8_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op8", self.base_path @@ -2818,25 +2879,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2846,29 +2907,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn op9_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/op9", self.base_path @@ -2886,25 +2947,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -2914,18 +2975,16 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } diff --git a/samples/server/petstore/rust-server/output/ops-v3/src/context.rs b/samples/server/petstore/rust-server/output/ops-v3/src/context.rs index ee8e118587bb..45180a543112 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/src/context.rs +++ b/samples/server/petstore/rust-server/output/ops-v3/src/context.rs @@ -6,9 +6,9 @@ use std::default::Default; use std::io; use std::marker::PhantomData; use std::task::{Poll, Context}; -use swagger::auth::{AuthData, Authorization, Bearer, Scopes}; +use swagger::auth::{AuthData, Authorization, Scopes}; use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString}; -use crate::{Api, AuthenticationApi}; +use crate::Api; use log::error; pub struct MakeAddContext { @@ -16,11 +16,11 @@ pub struct MakeAddContext { marker: PhantomData, } -impl MakeAddContext +impl MakeAddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, + C: Send + 'static, { pub fn new(inner: T) -> MakeAddContext { MakeAddContext { @@ -30,27 +30,34 @@ where } } +impl Clone for MakeAddContext +where + T: Clone, +{ + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + // Make a service that adds context. -impl Service for +impl Service for MakeAddContext where Target: Send, A: Default + Push + Send, B: Push, Result = C>, - C: Push, Result = D>, - D: Send + 'static, + C: Send + 'static, T: Service + Send, T::Future: Send + 'static { type Error = T::Error; - type Response = AddContext; + type Response = AddContext; type Future = BoxFuture<'static, Result>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, target: Target) -> Self::Future { + fn call(&self, target: Target) -> Self::Future { let service = self.inner.call(target); Box::pin(async move { @@ -60,21 +67,17 @@ where } /// Middleware to add context data from the request -pub struct AddContext -where - A: Default + Push, - B: Push, Result = C>, - C: Push, Result = D> +#[derive(Debug, Clone)] +pub struct AddContext { inner: T, marker: PhantomData, } -impl AddContext +impl AddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, { pub fn new(inner: T) -> Self { AddContext { @@ -84,30 +87,23 @@ where } } -impl Service> for AddContext +impl Service> for AddContext where A: Default + Push, B: Push, Result=C>, - C: Push, Result=D>, - D: Send + 'static, - T: Service<(Request, D)> + AuthenticationApi + C: Send + 'static, + T: Service<(Request, C)> { type Error = T::Error; type Future = T::Future; type Response = T::Response; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - - fn call(&mut self, request: Request) -> Self::Future { + fn call(&self, request: Request) -> Self::Future { let context = A::default().push(XSpanIdString::get_or_generate(&request)); let headers = request.headers(); let context = context.push(None::); - let context = context.push(None::); self.inner.call((request, context)) } diff --git a/samples/server/petstore/rust-server/output/ops-v3/src/header.rs b/samples/server/petstore/rust-server/output/ops-v3/src/header.rs index 5bc6ebe929b9..823d2779b31f 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/src/header.rs +++ b/samples/server/petstore/rust-server/output/ops-v3/src/header.rs @@ -31,11 +31,9 @@ macro_rules! ihv_generate { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse::<$t>() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse {} as a string: {}", - stringify!($t), e)), + Err(e) => Err(format!("Unable to parse {} as a string: {e}", stringify!($t))), }, - Err(e) => Err(format!("Unable to parse header {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header {hdr_value:?} as a string - {e}")), } } } @@ -76,8 +74,7 @@ impl TryFrom for IntoHeaderValue> { y => Some(y.to_string()), }) .collect())), - Err(e) => Err(format!("Unable to parse header: {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header: {hdr_value:?} as a string - {e}")), } } } @@ -88,8 +85,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(&hdr_value.0.join(", ")) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} into a header - {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} into a header - {e}")) } } } @@ -102,8 +98,7 @@ impl TryFrom for IntoHeaderValue { fn try_from(hdr_value: HeaderValue) -> Result { match hdr_value.to_str() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())), - Err(e) => Err(format!("Unable to convert header {:?} to {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to {e}")), } } } @@ -114,8 +109,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")) } } } @@ -128,11 +122,9 @@ impl TryFrom for IntoHeaderValue { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse bool from {} - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse bool from {hdr_value} - {e}")), }, - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")), } } } @@ -143,8 +135,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0.to_string()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert: {:?} into a header: {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert: {hdr_value:?} into a header: {e}")) } } } @@ -158,11 +149,9 @@ impl TryFrom for IntoHeaderValue> { match hdr_value.to_str() { Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) { Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))), - Err(e) => Err(format!("Unable to parse: {} as date - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse: {hdr_value} as date - {e}")), }, - Err(e) => Err(format!("Unable to convert header {:?} to string {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to string {e}")), } } } @@ -173,8 +162,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} to a header: {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} to a header: {e}")), } } } diff --git a/samples/server/petstore/rust-server/output/ops-v3/src/lib.rs b/samples/server/petstore/rust-server/output/ops-v3/src/lib.rs index 866ce4e4654a..35752b9d32fd 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/src/lib.rs +++ b/samples/server/petstore/rust-server/output/ops-v3/src/lib.rs @@ -3,14 +3,15 @@ use async_trait::async_trait; use futures::Stream; +#[cfg(feature = "mock")] +use mockall::automock; use std::error::Error; use std::collections::BTreeSet; use std::task::{Poll, Context}; -use swagger::{ApiError, ContextWrapper}; +use swagger::{ApiError, ContextWrapper, auth::Authorization}; use serde::{Serialize, Deserialize}; -use crate::server::Authorization; - +#[cfg(any(feature = "client", feature = "server"))] type ServiceError = Box; pub const BASE_PATH: &str = ""; @@ -243,13 +244,10 @@ pub enum Op9GetResponse { } /// API +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait Api { - fn poll_ready(&self, _cx: &mut Context) -> Poll>> { - Poll::Ready(Ok(())) - } - async fn op10_get( &self, context: &C) -> Result; @@ -401,11 +399,14 @@ pub trait Api { } /// API where `Context` isn't passed on every API call +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait ApiNoContext { - - fn poll_ready(&self, _cx: &mut Context) -> Poll>>; + // The std::task::Context struct houses a reference to std::task::Waker with the lifetime <'a>. + // Adding an anonymous lifetime `'a` to allow mockall to create a mock object with the right lifetimes. + // This is needed because the compiler is unable to determine the lifetimes on F's trait bound + // where F is the closure created by mockall. We use higher-rank trait bounds here to get around this. fn context(&self) -> &C; @@ -574,10 +575,6 @@ impl + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt for T #[async_trait] impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for ContextWrapper { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - self.api().poll_ready(cx) - } - fn context(&self) -> &C { ContextWrapper::context(self) } diff --git a/samples/server/petstore/rust-server/output/ops-v3/src/models.rs b/samples/server/petstore/rust-server/output/ops-v3/src/models.rs index f0f5817e64e9..e37352d5d2af 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/src/models.rs +++ b/samples/server/petstore/rust-server/output/ops-v3/src/models.rs @@ -1,7 +1,9 @@ #![allow(unused_qualifications)] - +#[cfg(not(feature = "validate"))] use validator::Validate; use crate::models; #[cfg(any(feature = "client", feature = "server"))] use crate::header; +#[cfg(feature = "validate")] +use serde_valid::Validate; diff --git a/samples/server/petstore/rust-server/output/ops-v3/src/server/mod.rs b/samples/server/petstore/rust-server/output/ops-v3/src/server/mod.rs index 80e243436911..294a1dd10f43 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/src/server/mod.rs +++ b/samples/server/petstore/rust-server/output/ops-v3/src/server/mod.rs @@ -1,10 +1,14 @@ +use bytes::Bytes; use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt}; -use hyper::{Request, Response, StatusCode, Body, HeaderMap}; +use http_body_util::{combinators::BoxBody, Full}; +use hyper::{body::{Body, Incoming}, HeaderMap, Request, Response, StatusCode}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; use log::warn; +#[cfg(feature = "validate")] +use serde_valid::Validate; #[allow(unused_imports)] use std::convert::{TryFrom, TryInto}; -use std::error::Error; +use std::{convert::Infallible, error::Error}; use std::future::Future; use std::marker::PhantomData; use std::task::{Context, Poll}; @@ -18,7 +22,7 @@ use crate::{models, header, AuthenticationApi}; pub use crate::context; -type ServiceFuture = BoxFuture<'static, Result, crate::ServiceError>>; +type ServiceFuture = BoxFuture<'static, Result>, crate::ServiceError>>; use crate::{Api, Op10GetResponse, @@ -147,28 +151,52 @@ mod paths { } -pub struct MakeService where +pub struct MakeService +where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { api_impl: T, marker: PhantomData, + validation: bool } -impl MakeService where +impl MakeService +where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { pub fn new(api_impl: T) -> Self { MakeService { api_impl, - marker: PhantomData + marker: PhantomData, + validation: false } } + + // Turn on/off validation for the service being made. + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation; + } } +impl Clone for MakeService +where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static +{ + fn clone(&self) -> Self { + Self { + api_impl: self.api_impl.clone(), + marker: PhantomData, + validation: self.validation + } + } +} -impl hyper::service::Service for MakeService where +impl hyper::service::Service for MakeService +where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { @@ -176,43 +204,72 @@ impl hyper::service::Service for MakeService where type Error = crate::ServiceError; type Future = future::Ready>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } + fn call(&self, target: Target) -> Self::Future { + let service = Service::new(self.api_impl.clone(), self.validation); - fn call(&mut self, target: Target) -> Self::Future { - future::ok(Service::new( - self.api_impl.clone(), - )) + future::ok(service) } } -fn method_not_allowed() -> Result, crate::ServiceError> { +fn method_not_allowed() -> Result>, crate::ServiceError> { Ok( Response::builder().status(StatusCode::METHOD_NOT_ALLOWED) - .body(Body::empty()) + .body(BoxBody::new(http_body_util::Empty::new())) .expect("Unable to create Method Not Allowed response") ) } +#[allow(unused_macros)] +#[cfg(not(feature = "validate"))] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => (); +} + +#[allow(unused_macros)] +#[cfg(feature = "validate")] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => { + let $parameter = if $validation { + match $parameter.validate() { + Ok(()) => $parameter, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .header(CONTENT_TYPE, mime::TEXT_PLAIN.as_ref()) + .body(BoxBody::new(format!("Invalid value in body parameter {}: {}", $base_name, e))) + .expect(&format!("Unable to create Bad Request response for invalid value in body parameter {}", $base_name))), + } + } else { + $parameter + }; + } +} + pub struct Service where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { api_impl: T, marker: PhantomData, + // Enable regex pattern validation of received JSON models + validation: bool, } impl Service where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { - pub fn new(api_impl: T) -> Self { + pub fn new(api_impl: T, validation: bool) -> Self { Service { api_impl, - marker: PhantomData + marker: PhantomData, + validation, } } + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation + } + } impl Clone for Service where @@ -223,39 +280,57 @@ impl Clone for Service where Service { api_impl: self.api_impl.clone(), marker: self.marker, + validation: self.validation, } } } -impl hyper::service::Service<(Request, C)> for Service where +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + +fn body_from_str(s: &str) -> BoxBody { + BoxBody::new(Full::new(Bytes::copy_from_slice(s.as_bytes()))) +} + +impl hyper::service::Service<(Request, C)> for Service where T: Api + Clone + Send + Sync + 'static, - C: Has + Send + Sync + 'static + C: Has + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, { - type Response = Response; + type Response = Response>; type Error = crate::ServiceError; type Future = ServiceFuture; - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - self.api_impl.poll_ready(cx) - } - - fn call(&mut self, req: (Request, C)) -> Self::Future { async fn run(mut api_impl: T, req: (Request, C)) -> Result, crate::ServiceError> where - T: Api + Clone + Send + 'static, - C: Has + Send + Sync + 'static - { - let (request, context) = req; - let (parts, body) = request.into_parts(); - let (method, uri, headers) = (parts.method, parts.uri, parts.headers); - let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); - - match method { + fn call(&self, req: (Request, C)) -> Self::Future { + async fn run( + mut api_impl: T, + req: (Request, C), + validation: bool, + ) -> Result>, crate::ServiceError> + where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, + { + let (request, context) = req; + let (parts, body) = request.into_parts(); + let (method, uri, headers) = (parts.method, parts.uri, parts.headers); + let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); + + match method { // Op10Get - GET /op10 hyper::Method::GET if path.matched(paths::ID_OP10) => { let result = api_impl.op10_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -266,13 +341,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op10GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -284,7 +360,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op11_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -295,13 +371,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op11GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -313,7 +390,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op12_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -324,13 +401,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op12GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -342,7 +420,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op13_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -353,13 +431,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op13GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -371,7 +450,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op14_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -382,13 +461,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op14GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -400,7 +480,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op15_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -411,13 +491,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op15GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -429,7 +510,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op16_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -440,13 +521,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op16GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -458,7 +540,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op17_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -469,13 +551,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op17GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -487,7 +570,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op18_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -498,13 +581,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op18GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -516,7 +600,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op19_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -527,13 +611,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op19GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -545,7 +630,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op1_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -556,13 +641,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op1GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -574,7 +660,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op20_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -585,13 +671,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op20GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -603,7 +690,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op21_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -614,13 +701,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op21GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -632,7 +720,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op22_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -643,13 +731,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op22GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -661,7 +750,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op23_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -672,13 +761,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op23GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -690,7 +780,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op24_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -701,13 +791,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op24GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -719,7 +810,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op25_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -730,13 +821,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op25GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -748,7 +840,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op26_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -759,13 +851,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op26GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -777,7 +870,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op27_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -788,13 +881,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op27GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -806,7 +900,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op28_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -817,13 +911,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op28GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -835,7 +930,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op29_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -846,13 +941,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op29GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -864,7 +960,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op2_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -875,13 +971,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op2GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -893,7 +990,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op30_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -904,13 +1001,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op30GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -922,7 +1020,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op31_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -933,13 +1031,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op31GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -951,7 +1050,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op32_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -962,13 +1061,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op32GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -980,7 +1080,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op33_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -991,13 +1091,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op33GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1009,7 +1110,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op34_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1020,13 +1121,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op34GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1038,7 +1140,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op35_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1049,13 +1151,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op35GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1067,7 +1170,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op36_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1078,13 +1181,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op36GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1096,7 +1200,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op37_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1107,13 +1211,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op37GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1125,7 +1230,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op3_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1136,13 +1241,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op3GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1154,7 +1260,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op4_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1165,13 +1271,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op4GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1183,7 +1290,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op5_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1194,13 +1301,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op5GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1212,7 +1320,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op6_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1223,13 +1331,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op6GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1241,7 +1350,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op7_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1252,13 +1361,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op7GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1270,7 +1380,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op8_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1281,13 +1391,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op8GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1299,7 +1410,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.op9_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1310,13 +1421,14 @@ impl hyper::service::Service<(Request, C)> for Service where Op9GetResponse::OK => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1360,11 +1472,17 @@ impl hyper::service::Service<(Request, C)> for Service where _ if path.matched(paths::ID_OP7) => method_not_allowed(), _ if path.matched(paths::ID_OP8) => method_not_allowed(), _ if path.matched(paths::ID_OP9) => method_not_allowed(), - _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) - .body(Body::empty()) - .expect("Unable to create Not Found response")) + _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) + .body(BoxBody::new(http_body_util::Empty::new())) + .expect("Unable to create Not Found response")) + } } - } Box::pin(run(self.api_impl.clone(), req)) } + Box::pin(run( + self.api_impl.clone(), + req, + self.validation + )) + } } /// Request parser for `Api`. diff --git a/samples/server/petstore/rust-server/output/ops-v3/src/server/server_auth.rs b/samples/server/petstore/rust-server/output/ops-v3/src/server/server_auth.rs index ba78eb2f3f5d..21b1d7babd03 100644 --- a/samples/server/petstore/rust-server/output/ops-v3/src/server/server_auth.rs +++ b/samples/server/petstore/rust-server/output/ops-v3/src/server/server_auth.rs @@ -1,11 +1,12 @@ use super::Service; use crate::{Api, AuthenticationApi}; +use headers::authorization::{Basic, Bearer}; use swagger::{ ApiError, - Authorization, - auth::{Basic, Bearer}, - Has, - XSpanIdString}; + Authorization, + Has, + XSpanIdString +}; impl AuthenticationApi for Service where T: Api + Clone + Send + 'static + AuthenticationApi, diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/.cargo/config.toml b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/.cargo/config.toml new file mode 100644 index 000000000000..df91f0f117f3 --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/.cargo/config.toml @@ -0,0 +1,19 @@ +[build] +rustflags = [ + "-W", "missing_docs", # detects missing documentation for public members + + "-W", "trivial_casts", # detects trivial casts which could be removed + + "-W", "trivial_numeric_casts", # detects trivial casts of numeric types which could be removed + + # unsafe is used in `TokioIo` bridging code copied from `hyper`. + # "-W", "unsafe_code", # usage of `unsafe` code + + "-W", "unused_qualifications", # detects unnecessarily qualified names + + "-W", "unused_extern_crates", # extern crates that are never used + + "-W", "unused_import_braces", # unnecessary braces around an imported item + + "-D", "warnings", # all warnings should be denied +] diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/.openapi-generator/FILES b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/.openapi-generator/FILES index d72d04fabfab..5332ab08344d 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/.openapi-generator/FILES +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/.openapi-generator/FILES @@ -1,8 +1,9 @@ -.cargo/config +.cargo/config.toml .gitignore Cargo.toml README.md api/openapi.yaml +bin/cli.rs docs/AdditionalPropertiesClass.md docs/Animal.md docs/AnimalFarm.md @@ -16,14 +17,21 @@ docs/Category.md docs/ClassModel.md docs/Client.md docs/Dog.md -docs/DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket.md +docs/DollarSpecialLeftSquareBracketModelNameRightSquareBracket.md docs/EnumArrays.md +docs/EnumArraysArrayArrayEnumInnerInner.md +docs/EnumArraysArrayEnumInner.md +docs/EnumArraysJustSymbol.md docs/EnumClass.md docs/EnumTest.md +docs/EnumTestEnumInteger.md +docs/EnumTestEnumString.md +docs/FindPetsByStatusStatusParameterInner.md docs/FormatTest.md docs/HasOnlyReadOnly.md docs/List.md docs/MapTest.md +docs/MapTestMapMapOfEnumValueValue.md docs/MixedPropertiesAndAdditionalPropertiesClass.md docs/Model200Response.md docs/Name.md @@ -31,15 +39,22 @@ docs/NumberOnly.md docs/ObjectContainingObjectWithOnlyAdditionalProperties.md docs/ObjectWithOnlyAdditionalProperties.md docs/Order.md +docs/OrderStatus.md docs/OuterBoolean.md docs/OuterComposite.md docs/OuterEnum.md docs/OuterNumber.md docs/OuterString.md docs/Pet.md +docs/PetStatus.md docs/ReadOnlyFirst.md docs/Return.md docs/Tag.md +docs/TestEnumParametersEnumHeaderStringArrayParameterInner.md +docs/TestEnumParametersEnumHeaderStringParameter.md +docs/TestEnumParametersEnumQueryDoubleParameter.md +docs/TestEnumParametersEnumQueryIntegerParameter.md +docs/TestEnumParametersRequestEnumFormString.md docs/User.md docs/another_fake_api.md docs/fake_api.md diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/.openapi-generator/VERSION b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/.openapi-generator/VERSION index f1358e30d8ae..f7962df3e243 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/.openapi-generator/VERSION +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/.openapi-generator/VERSION @@ -1 +1 @@ -8.0.0-SNAPSHOT +7.22.0-SNAPSHOT diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/Cargo.toml b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/Cargo.toml index f26d4ca2528e..3835cb94a4b1 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/Cargo.toml +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/Cargo.toml @@ -8,86 +8,132 @@ edition = "2018" publish = ["crates-io"] [features] -default = ["client", "server"] +default = ["client", "server", "client-tls"] client = [ - "mime_0_2", "multipart", "multipart/client", "swagger/multipart_form", "serde_urlencoded", - "hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url" + "hyper", "percent-encoding", "hyper-util/http1", "hyper-util/http2", "url" +] +# TLS support - automatically selects backend based on target OS: +# - macOS/Windows/iOS: native-tls via hyper-tls +# - Other platforms: OpenSSL via hyper-openssl +# Dependencies are in target-specific sections below +client-tls = [ + "client", + "dep:native-tls", + "dep:hyper-tls", + "dep:openssl", + "dep:hyper-openssl", + "swagger/tls" ] server = [ - "mime_0_2", "multipart", "multipart/server", "swagger/multipart_form", - "serde_ignored", "hyper", "regex", "percent-encoding", "url", "lazy_static" + "serde_ignored", "hyper", "percent-encoding", "url", + +] +cli = [ + "dialoguer", + "anyhow", "clap", "clap-verbosity-flag", "simple_logger", "tokio" ] conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"] -[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] -native-tls = { version = "0.2", optional = true } -hyper-tls = { version = "0.5", optional = true } - -[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] -hyper-openssl = { version = "0.9", optional = true } -openssl = {version = "0.10", optional = true } +mock = ["mockall"] +validate = [ "serde_valid", "swagger/serdevalid"] [dependencies] # Common -async-trait = "0.1.24" +async-trait = "0.1.89" chrono = { version = "0.4", features = ["serde"] } futures = "0.3" -swagger = { version = "6.1", features = ["serdejson", "server", "client", "tls", "tcp"] } -log = "0.4.0" +swagger = { version = "7.0.0", features = ["serdejson", "server", "client"] } +headers = "0.4.1" +log = "0.4.29" + mime = "0.3" +mockall = { version = "0.14", optional = true } +lazy_static = "1.5" +regex = "1.12" + serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -validator = { version = "0.16", features = ["derive"] } +serde_repr = "0.1" +serde_valid = { version = "2.0", optional = true } + +validator = { version = "0.20", features = ["derive"] } # Crates included if required by the API definition -# TODO: this should be updated to point at the official crate once -# https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream -serde-xml-rs = {git = "https://github.com/Metaswitch/serde-xml-rs" , branch = "master"} -mime_0_2 = { package = "mime", version = "0.2.6", optional = true } -multipart = { version = "0.16", default-features = false, optional = true } -uuid = {version = "1.3.1", features = ["serde", "v4"]} +serde-xml-rs = "0.8" +multipart = { version = "0.18", default-features = false, optional = true } +uuid = { version = "1.23.0", features = ["serde", "v4"]} # Common between server and client features -hyper = {version = "0.14", features = ["full"], optional = true} -serde_ignored = {version = "0.1.1", optional = true} -url = {version = "2.1", optional = true} +bytes = "1.11" +http-body-util = "0.1.3" +hyper = { version = "1.9.0", features = ["full"], optional = true } +hyper-util = { version = "0.1.20", features = ["service"] } +serde_ignored = { version = "0.1.14", optional = true } +url = { version = "2.5", optional = true } # Client-specific -serde_urlencoded = {version = "0.6.1", optional = true} +serde_urlencoded = { version = "0.7.1", optional = true } +tower-service = "0.3.3" # Server, and client callback-specific -lazy_static = { version = "1.4", optional = true } -percent-encoding = {version = "2.1.0", optional = true} -regex = {version = "1.3", optional = true} +percent-encoding = { version = "2.3.2", optional = true } + +# CLI-specific +anyhow = { version = "1", optional = true } +clap = { version = "4.6.0", features = ["env"], optional = true } +clap-verbosity-flag = { version = "3.0", optional = true } +simple_logger = { version = "5.2.0", features = ["stderr"], optional = true } +tokio = { version = "1.50.0", features = ["rt-multi-thread", "macros"], optional = true } +dialoguer = { version = "0.12", optional = true } # Conversion -frunk = { version = "0.3.0", optional = true } -frunk_derives = { version = "0.3.0", optional = true } -frunk_core = { version = "0.3.0", optional = true } -frunk-enum-derive = { version = "0.2.0", optional = true } -frunk-enum-core = { version = "0.2.0", optional = true } +frunk = { version = "0.4.4", optional = true } +frunk_derives = { version = "0.4.4", optional = true } +frunk_core = { version = "0.4.4", optional = true } +frunk-enum-derive = { version = "0.3.0", optional = true } +frunk-enum-core = { version = "0.3.0", optional = true } -# Bearer authentication -jsonwebtoken = { version = "9.3.0", optional = false } +# TLS dependencies - platform-specific backends +# On macOS/Windows/iOS, use native-tls via hyper-tls +[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] +native-tls = { version = "0.2", optional = true } +hyper-tls = { version = "0.6", optional = true } + +# On other platforms (Linux, etc.), use OpenSSL via hyper-openssl +[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] +openssl = { version = "0.10", optional = true } +hyper-openssl = { version = "0.10", optional = true } [dev-dependencies] -clap = "2.25" -env_logger = "0.7" -tokio = { version = "1.14", features = ["full"] } +always_send = "0.1.1" +clap = "4.6.0" +env_logger = "0.11" +tokio = { version = "1.50.0", features = ["full"] } native-tls = "0.2" +pin-project = "1.1.11" + +# Bearer authentication, used in examples +jsonwebtoken = {version = "10.3.0", features = ["rust_crypto"]} [target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies] -tokio-openssl = "0.6" openssl = "0.10" +tokio-openssl = "0.6" [[example]] -name = "client" +name = "petstore-with-fake-endpoints-models-for-testing-client" +path = "examples/client/main.rs" required-features = ["client"] [[example]] -name = "server" +name = "petstore-with-fake-endpoints-models-for-testing-server" +path = "examples/server/main.rs" required-features = ["server"] + +[[bin]] +name = "petstore-with-fake-endpoints-models-for-testing" +path = "bin/cli.rs" +required-features = ["client", "cli"] diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/README.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/README.md index 6a84e77f5462..9c6172e6b56c 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/README.md +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/README.md @@ -14,7 +14,7 @@ To see how to make this your own, look here: [README]((https://openapi-generator.tech)) - API version: 1.0.0 -- Generator version: 8.0.0-SNAPSHOT +- Generator version: 7.22.0-SNAPSHOT @@ -23,6 +23,7 @@ This autogenerated project defines an API crate `petstore-with-fake-endpoints-mo * Data types representing the underlying data model. * A `Client` type which implements `Api` and issues HTTP requests for each operation. * A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. +* A CLI tool to drive basic API operations from the command line. It also contains an example server and client which make use of `petstore-with-fake-endpoints-models-for-testing`: @@ -34,65 +35,84 @@ It also contains an example server and client which make use of `petstore-with-f arguments on the command line. You can use the example server and client as a basis for your own code. -See below for [more detail on implementing a server](#writing-a-server). +See below for [more detail on the examples](#using-the-generated-library). + +## CLI + +Run the included CLI tool with: + +``` +cargo run --bin cli --features=cli +``` + +To pass in arguments, put them after `--`, for example: + +``` +cargo run --bin cli --features=cli -- --help +``` + +See the help text for available options. + +To build a standalone tool, use: + +``` +cargo build --bin cli --features=cli --release +``` + +You'll find the binary at `target/release/cli`. ## Examples Run examples with: ``` -cargo run --example +cargo run --example petstore-with-fake-endpoints-models-for-testing- ``` To pass in arguments to the examples, put them after `--`, for example: ``` -cargo run --example client -- --help +cargo run --example petstore-with-fake-endpoints-models-for-testing-client -- --help ``` ### Running the example server To run the server, follow these simple steps: ``` -cargo run --example server +cargo run --example petstore-with-fake-endpoints-models-for-testing-server ``` ### Running the example client To run a client, follow one of the following simple steps: ``` -cargo run --example client Call123example -cargo run --example client FakeOuterBooleanSerialize -cargo run --example client FakeOuterCompositeSerialize -cargo run --example client FakeOuterNumberSerialize -cargo run --example client FakeOuterStringSerialize -cargo run --example client FakeResponseWithNumericalDescription -cargo run --example client HyphenParam -cargo run --example client TestEndpointParameters -cargo run --example client TestEnumParameters -cargo run --example client TestJsonFormData -cargo run --example client DeletePet -cargo run --example client FindPetsByStatus -cargo run --example client FindPetsByTags -cargo run --example client GetPetById -cargo run --example client UpdatePetWithForm -cargo run --example client UploadFile -cargo run --example client DeleteOrder -cargo run --example client GetInventory -cargo run --example client GetOrderById -cargo run --example client CreateUsersWithArrayInput -cargo run --example client CreateUsersWithListInput -cargo run --example client DeleteUser -cargo run --example client GetUserByName -cargo run --example client LoginUser -cargo run --example client LogoutUser +cargo run --example petstore-with-fake-endpoints-models-for-testing-client Call123example +cargo run --example petstore-with-fake-endpoints-models-for-testing-client FakeOuterBooleanSerialize +cargo run --example petstore-with-fake-endpoints-models-for-testing-client FakeOuterCompositeSerialize +cargo run --example petstore-with-fake-endpoints-models-for-testing-client FakeOuterNumberSerialize +cargo run --example petstore-with-fake-endpoints-models-for-testing-client FakeOuterStringSerialize +cargo run --example petstore-with-fake-endpoints-models-for-testing-client FakeResponseWithNumericalDescription +cargo run --example petstore-with-fake-endpoints-models-for-testing-client TestEndpointParameters +cargo run --example petstore-with-fake-endpoints-models-for-testing-client TestEnumParameters +cargo run --example petstore-with-fake-endpoints-models-for-testing-client TestJsonFormData +cargo run --example petstore-with-fake-endpoints-models-for-testing-client FindPetsByStatus +cargo run --example petstore-with-fake-endpoints-models-for-testing-client FindPetsByTags +cargo run --example petstore-with-fake-endpoints-models-for-testing-client DeletePet +cargo run --example petstore-with-fake-endpoints-models-for-testing-client GetPetById +cargo run --example petstore-with-fake-endpoints-models-for-testing-client UpdatePetWithForm +cargo run --example petstore-with-fake-endpoints-models-for-testing-client UploadFile +cargo run --example petstore-with-fake-endpoints-models-for-testing-client GetInventory +cargo run --example petstore-with-fake-endpoints-models-for-testing-client GetOrderById +cargo run --example petstore-with-fake-endpoints-models-for-testing-client CreateUsersWithArrayInput +cargo run --example petstore-with-fake-endpoints-models-for-testing-client CreateUsersWithListInput +cargo run --example petstore-with-fake-endpoints-models-for-testing-client LogoutUser ``` ### HTTPS The examples can be run in HTTPS mode by passing in the flag `--https`, for example: ``` -cargo run --example server -- --https +cargo run --example petstore-with-fake-endpoints-models-for-testing-server -- --https ``` This will use the keys/certificates from the examples directory. Note that the @@ -108,8 +128,36 @@ The generated library has a few optional features that can be activated through * `client` * This defaults to enabled and creates the basic skeleton of a client implementation based on hyper * The constructed client implements the API trait by making remote API call. +* `client-tls` + * This default to enabled and provides HTTPS support with automatic TLS backend selection: + - macOS/Windows/iOS: native-tls + hyper-tls + - Linux/Unix/others: OpenSSL + hyper-openssl * `conversions` * This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types. +* `cli` + * This defaults to disabled and is required for building the included CLI tool. +* `validate` + * This defaults to disabled and allows JSON Schema validation of received data using `MakeService::set_validation` or `Service::set_validation`. + * Note, enabling validation will have a performance penalty, especially if the API heavily uses regex based checks. + +### HTTPS/TLS Support + +HTTPS support is included by default. To disable it (for example, to reduce dependencies), you can: + +```toml +[dependencies] +petstore-with-fake-endpoints-models-for-testing = { version = "1.0.0", default-features = false, features = ["client", "server"] } +``` + +**For server with callbacks that need HTTPS:** +```toml +[dependencies] +petstore-with-fake-endpoints-models-for-testing = { version = "1.0.0", features = ["server", "client-tls"] } +``` + +The TLS backend is automatically selected based on your target platform: +- **macOS, Windows, iOS**: Uses `native-tls` (system TLS libraries) +- **Linux, Unix, other platforms**: Uses `openssl` See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`. @@ -126,33 +174,33 @@ Method | HTTP request | Description [**fakeOuterNumberSerialize**](docs/fake_api.md#fakeOuterNumberSerialize) | **POST** /fake/outer/number | [**fakeOuterStringSerialize**](docs/fake_api.md#fakeOuterStringSerialize) | **POST** /fake/outer/string | [**fake_response_with_numerical_description**](docs/fake_api.md#fake_response_with_numerical_description) | **GET** /fake/response-with-numerical-description | -[**hyphenParam**](docs/fake_api.md#hyphenParam) | **GET** /fake/hyphenParam/{hyphen-param} | [**testBodyWithQueryParams**](docs/fake_api.md#testBodyWithQueryParams) | **PUT** /fake/body-with-query-params | [**testClientModel**](docs/fake_api.md#testClientModel) | **PATCH** /fake | To test \"client\" model [**testEndpointParameters**](docs/fake_api.md#testEndpointParameters) | **POST** /fake | Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트 [**testEnumParameters**](docs/fake_api.md#testEnumParameters) | **GET** /fake | To test enum parameters [**testInlineAdditionalProperties**](docs/fake_api.md#testInlineAdditionalProperties) | **POST** /fake/inline-additionalProperties | test inline additionalProperties [**testJsonFormData**](docs/fake_api.md#testJsonFormData) | **GET** /fake/jsonFormData | test json serialization of form data +[**hyphenParam**](docs/fake_api.md#hyphenParam) | **GET** /fake/hyphenParam/{hyphen-param} | [**testClassname**](docs/fake_classname_tags123_api.md#testClassname) | **PATCH** /fake_classname_test | To test class name in snake case [**addPet**](docs/pet_api.md#addPet) | **POST** /pet | Add a new pet to the store -[**deletePet**](docs/pet_api.md#deletePet) | **DELETE** /pet/{petId} | Deletes a pet [**findPetsByStatus**](docs/pet_api.md#findPetsByStatus) | **GET** /pet/findByStatus | Finds Pets by status [**findPetsByTags**](docs/pet_api.md#findPetsByTags) | **GET** /pet/findByTags | Finds Pets by tags -[**getPetById**](docs/pet_api.md#getPetById) | **GET** /pet/{petId} | Find pet by ID [**updatePet**](docs/pet_api.md#updatePet) | **PUT** /pet | Update an existing pet +[**deletePet**](docs/pet_api.md#deletePet) | **DELETE** /pet/{petId} | Deletes a pet +[**getPetById**](docs/pet_api.md#getPetById) | **GET** /pet/{petId} | Find pet by ID [**updatePetWithForm**](docs/pet_api.md#updatePetWithForm) | **POST** /pet/{petId} | Updates a pet in the store with form data [**uploadFile**](docs/pet_api.md#uploadFile) | **POST** /pet/{petId}/uploadImage | uploads an image -[**deleteOrder**](docs/store_api.md#deleteOrder) | **DELETE** /store/order/{order_id} | Delete purchase order by ID [**getInventory**](docs/store_api.md#getInventory) | **GET** /store/inventory | Returns pet inventories by status -[**getOrderById**](docs/store_api.md#getOrderById) | **GET** /store/order/{order_id} | Find purchase order by ID [**placeOrder**](docs/store_api.md#placeOrder) | **POST** /store/order | Place an order for a pet +[**deleteOrder**](docs/store_api.md#deleteOrder) | **DELETE** /store/order/{order_id} | Delete purchase order by ID +[**getOrderById**](docs/store_api.md#getOrderById) | **GET** /store/order/{order_id} | Find purchase order by ID [**createUser**](docs/user_api.md#createUser) | **POST** /user | Create user [**createUsersWithArrayInput**](docs/user_api.md#createUsersWithArrayInput) | **POST** /user/createWithArray | Creates list of users with given input array [**createUsersWithListInput**](docs/user_api.md#createUsersWithListInput) | **POST** /user/createWithList | Creates list of users with given input array -[**deleteUser**](docs/user_api.md#deleteUser) | **DELETE** /user/{username} | Delete user -[**getUserByName**](docs/user_api.md#getUserByName) | **GET** /user/{username} | Get user by user name [**loginUser**](docs/user_api.md#loginUser) | **GET** /user/login | Logs user into the system [**logoutUser**](docs/user_api.md#logoutUser) | **GET** /user/logout | Logs out current logged in user session +[**deleteUser**](docs/user_api.md#deleteUser) | **DELETE** /user/{username} | Delete user +[**getUserByName**](docs/user_api.md#getUserByName) | **GET** /user/{username} | Get user by user name [**updateUser**](docs/user_api.md#updateUser) | **PUT** /user/{username} | Updated user @@ -171,14 +219,21 @@ Method | HTTP request | Description - [ClassModel](docs/ClassModel.md) - [Client](docs/Client.md) - [Dog](docs/Dog.md) - - [DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket](docs/DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket.md) + - [DollarSpecialLeftSquareBracketModelNameRightSquareBracket](docs/DollarSpecialLeftSquareBracketModelNameRightSquareBracket.md) - [EnumArrays](docs/EnumArrays.md) + - [EnumArraysArrayArrayEnumInnerInner](docs/EnumArraysArrayArrayEnumInnerInner.md) + - [EnumArraysArrayEnumInner](docs/EnumArraysArrayEnumInner.md) + - [EnumArraysJustSymbol](docs/EnumArraysJustSymbol.md) - [EnumClass](docs/EnumClass.md) - [EnumTest](docs/EnumTest.md) + - [EnumTestEnumInteger](docs/EnumTestEnumInteger.md) + - [EnumTestEnumString](docs/EnumTestEnumString.md) + - [FindPetsByStatusStatusParameterInner](docs/FindPetsByStatusStatusParameterInner.md) - [FormatTest](docs/FormatTest.md) - [HasOnlyReadOnly](docs/HasOnlyReadOnly.md) - [List](docs/List.md) - [MapTest](docs/MapTest.md) + - [MapTestMapMapOfEnumValueValue](docs/MapTestMapMapOfEnumValueValue.md) - [MixedPropertiesAndAdditionalPropertiesClass](docs/MixedPropertiesAndAdditionalPropertiesClass.md) - [Model200Response](docs/Model200Response.md) - [Name](docs/Name.md) @@ -186,15 +241,22 @@ Method | HTTP request | Description - [ObjectContainingObjectWithOnlyAdditionalProperties](docs/ObjectContainingObjectWithOnlyAdditionalProperties.md) - [ObjectWithOnlyAdditionalProperties](docs/ObjectWithOnlyAdditionalProperties.md) - [Order](docs/Order.md) + - [OrderStatus](docs/OrderStatus.md) - [OuterBoolean](docs/OuterBoolean.md) - [OuterComposite](docs/OuterComposite.md) - [OuterEnum](docs/OuterEnum.md) - [OuterNumber](docs/OuterNumber.md) - [OuterString](docs/OuterString.md) - [Pet](docs/Pet.md) + - [PetStatus](docs/PetStatus.md) - [ReadOnlyFirst](docs/ReadOnlyFirst.md) - [Return](docs/Return.md) - [Tag](docs/Tag.md) + - [TestEnumParametersEnumHeaderStringArrayParameterInner](docs/TestEnumParametersEnumHeaderStringArrayParameterInner.md) + - [TestEnumParametersEnumHeaderStringParameter](docs/TestEnumParametersEnumHeaderStringParameter.md) + - [TestEnumParametersEnumQueryDoubleParameter](docs/TestEnumParametersEnumQueryDoubleParameter.md) + - [TestEnumParametersEnumQueryIntegerParameter](docs/TestEnumParametersEnumQueryIntegerParameter.md) + - [TestEnumParametersRequestEnumFormString](docs/TestEnumParametersRequestEnumFormString.md) - [User](docs/User.md) diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/api/openapi.yaml b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/api/openapi.yaml index 534372bf58f9..c9cac8905821 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/api/openapi.yaml +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/api/openapi.yaml @@ -25,10 +25,10 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Pet' + $ref: "#/components/schemas/Pet" application/xml: schema: - $ref: '#/components/schemas/Pet' + $ref: "#/components/schemas/Pet" description: Pet object that needs to be added to the store required: true responses: @@ -49,10 +49,10 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Pet' + $ref: "#/components/schemas/Pet" application/xml: schema: - $ref: '#/components/schemas/Pet' + $ref: "#/components/schemas/Pet" description: Pet object that needs to be added to the store required: true responses: @@ -85,12 +85,7 @@ paths: required: true schema: items: - default: available - enum: - - available - - pending - - sold - type: string + $ref: "#/components/schemas/findPetsByStatus_status_parameter_inner" type: array style: form responses: @@ -99,12 +94,12 @@ paths: application/xml: schema: items: - $ref: '#/components/schemas/Pet' + $ref: "#/components/schemas/Pet" type: array application/json: schema: items: - $ref: '#/components/schemas/Pet' + $ref: "#/components/schemas/Pet" type: array description: successful operation "400": @@ -140,12 +135,12 @@ paths: application/xml: schema: items: - $ref: '#/components/schemas/Pet' + $ref: "#/components/schemas/Pet" type: array application/json: schema: items: - $ref: '#/components/schemas/Pet' + $ref: "#/components/schemas/Pet" type: array description: successful operation "400": @@ -200,10 +195,10 @@ paths: content: application/xml: schema: - $ref: '#/components/schemas/Pet' + $ref: "#/components/schemas/Pet" application/json: schema: - $ref: '#/components/schemas/Pet' + $ref: "#/components/schemas/Pet" description: successful operation "400": content: {} @@ -230,7 +225,7 @@ paths: content: application/x-www-form-urlencoded: schema: - $ref: '#/components/schemas/updatePetWithForm_request' + $ref: "#/components/schemas/updatePetWithForm_request" responses: "405": content: {} @@ -257,13 +252,13 @@ paths: content: multipart/form-data: schema: - $ref: '#/components/schemas/uploadFile_request' + $ref: "#/components/schemas/uploadFile_request" responses: "200": content: application/json: schema: - $ref: '#/components/schemas/ApiResponse' + $ref: "#/components/schemas/ApiResponse" description: successful operation security: - petstore_auth: @@ -298,7 +293,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/Order' + $ref: "#/components/schemas/Order" description: order placed for purchasing the pet required: true responses: @@ -306,10 +301,10 @@ paths: content: application/xml: schema: - $ref: '#/components/schemas/Order' + $ref: "#/components/schemas/Order" application/json: schema: - $ref: '#/components/schemas/Order' + $ref: "#/components/schemas/Order" description: successful operation "400": content: {} @@ -359,10 +354,10 @@ paths: content: application/xml: schema: - $ref: '#/components/schemas/Order' + $ref: "#/components/schemas/Order" application/json: schema: - $ref: '#/components/schemas/Order' + $ref: "#/components/schemas/Order" description: successful operation "400": content: {} @@ -381,7 +376,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" description: Created user object required: true responses: @@ -400,7 +395,7 @@ paths: '*/*': schema: items: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" type: array description: List of user object required: true @@ -420,7 +415,7 @@ paths: '*/*': schema: items: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" type: array description: List of user object required: true @@ -520,10 +515,10 @@ paths: content: application/xml: schema: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" application/json: schema: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" description: successful operation "400": content: {} @@ -548,7 +543,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" description: Updated user object required: true responses: @@ -570,7 +565,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Client' + $ref: "#/components/schemas/Client" description: client model required: true responses: @@ -578,7 +573,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Client' + $ref: "#/components/schemas/Client" description: successful operation security: - api_key_query: [] @@ -597,69 +592,43 @@ paths: name: enum_header_string_array schema: items: - default: $ - enum: - - '>' - - $ - type: string + $ref: "#/components/schemas/testEnumParameters_enum_header_string_array_parameter_inner" type: array style: simple - description: Header parameter enum test (string) in: header name: enum_header_string schema: - default: -efg - enum: - - _abc - - -efg - - (xyz) - type: string + $ref: "#/components/schemas/testEnumParameters_enum_header_string_parameter" - description: Query parameter enum test (string array) explode: false in: query name: enum_query_string_array schema: items: - default: $ - enum: - - '>' - - $ - type: string + $ref: "#/components/schemas/testEnumParameters_enum_header_string_array_parameter_inner" type: array style: form - description: Query parameter enum test (string) in: query name: enum_query_string schema: - default: -efg - enum: - - _abc - - -efg - - (xyz) - type: string + $ref: "#/components/schemas/testEnumParameters_enum_header_string_parameter" - description: Query parameter enum test (double) in: query name: enum_query_integer schema: - enum: - - 1 - - -2 - format: int32 - type: integer + $ref: "#/components/schemas/testEnumParameters_enum_query_integer_parameter" - description: Query parameter enum test (double) in: query name: enum_query_double schema: - enum: - - 1.1 - - -1.2 - format: double - type: number + $ref: "#/components/schemas/testEnumParameters_enum_query_double_parameter" requestBody: content: application/x-www-form-urlencoded: schema: - $ref: '#/components/schemas/testEnumParameters_request' + $ref: "#/components/schemas/testEnumParameters_request" responses: "400": content: {} @@ -677,7 +646,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Client' + $ref: "#/components/schemas/Client" description: client model required: true responses: @@ -685,7 +654,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Client' + $ref: "#/components/schemas/Client" description: successful operation summary: To test "client" model tags: @@ -702,7 +671,7 @@ paths: content: application/x-www-form-urlencoded: schema: - $ref: '#/components/schemas/testEndpointParameters_request' + $ref: "#/components/schemas/testEndpointParameters_request" required: true responses: "400": @@ -728,7 +697,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/OuterNumber' + $ref: "#/components/schemas/OuterNumber" description: Input number as post body required: false responses: @@ -736,7 +705,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/OuterNumber' + $ref: "#/components/schemas/OuterNumber" description: Output number tags: - fake @@ -749,7 +718,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/OuterString' + $ref: "#/components/schemas/OuterString" description: Input string as post body required: false responses: @@ -757,7 +726,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/OuterString' + $ref: "#/components/schemas/OuterString" description: Output string tags: - fake @@ -770,7 +739,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/OuterBoolean' + $ref: "#/components/schemas/OuterBoolean" description: Input boolean as post body required: false responses: @@ -778,7 +747,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/OuterBoolean' + $ref: "#/components/schemas/OuterBoolean" description: Output boolean tags: - fake @@ -791,7 +760,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/OuterComposite' + $ref: "#/components/schemas/OuterComposite" description: Input composite as post body required: false responses: @@ -799,7 +768,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/OuterComposite' + $ref: "#/components/schemas/OuterComposite" description: Output composite tags: - fake @@ -811,7 +780,7 @@ paths: content: application/x-www-form-urlencoded: schema: - $ref: '#/components/schemas/testJsonFormData_request' + $ref: "#/components/schemas/testJsonFormData_request" required: true responses: "200": @@ -853,7 +822,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/User' + $ref: "#/components/schemas/User" required: true responses: "200": @@ -870,7 +839,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Client' + $ref: "#/components/schemas/Client" description: client model required: true responses: @@ -878,7 +847,7 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/Client' + $ref: "#/components/schemas/Client" description: successful operation summary: To test special tags tags: @@ -943,12 +912,7 @@ components: format: date-time type: string status: - description: Order Status - enum: - - placed - - approved - - delivered - type: string + $ref: "#/components/schemas/Order_status" complete: default: false type: boolean @@ -1037,7 +1001,7 @@ components: type: integer x-is-unique: true category: - $ref: '#/components/schemas/Category' + $ref: "#/components/schemas/Category" name: example: doggie type: string @@ -1050,18 +1014,13 @@ components: wrapped: true tags: items: - $ref: '#/components/schemas/Tag' + $ref: "#/components/schemas/Tag" type: array xml: name: tag wrapped: true status: - description: pet status in the store - enum: - - available - - pending - - sold - type: string + $ref: "#/components/schemas/Pet_status" required: - name - photoUrls @@ -1138,14 +1097,14 @@ components: type: object Dog: allOf: - - $ref: '#/components/schemas/Animal' + - $ref: "#/components/schemas/Animal" - properties: breed: type: string type: object Cat: allOf: - - $ref: '#/components/schemas/Animal' + - $ref: "#/components/schemas/Animal" - properties: declawed: type: boolean @@ -1164,7 +1123,7 @@ components: type: object AnimalFarm: items: - $ref: '#/components/schemas/Animal' + $ref: "#/components/schemas/Animal" type: array format_test: properties: @@ -1234,31 +1193,15 @@ components: Enum_Test: properties: enum_string: - enum: - - UPPER - - lower - - "" - type: string + $ref: "#/components/schemas/Enum_Test_enum_string" enum_string_required: - enum: - - UPPER - - lower - - "" - type: string + $ref: "#/components/schemas/Enum_Test_enum_string" enum_integer: - enum: - - 1 - - -1 - format: int32 - type: integer + $ref: "#/components/schemas/Enum_Test_enum_integer" enum_number: - enum: - - 1.1 - - -1.2 - format: double - type: number + $ref: "#/components/schemas/testEnumParameters_enum_query_double_parameter" outerEnum: - $ref: '#/components/schemas/OuterEnum' + $ref: "#/components/schemas/OuterEnum" required: - enum_string_required type: object @@ -1285,13 +1228,13 @@ components: type: string map: additionalProperties: - $ref: '#/components/schemas/Animal' + $ref: "#/components/schemas/Animal" type: object type: object ObjectContainingObjectWithOnlyAdditionalProperties: properties: inner: - $ref: '#/components/schemas/ObjectWithOnlyAdditionalProperties' + $ref: "#/components/schemas/ObjectWithOnlyAdditionalProperties" type: object ObjectWithOnlyAdditionalProperties: additionalProperties: @@ -1354,18 +1297,12 @@ components: map_map_of_enum: additionalProperties: additionalProperties: - enum: - - UPPER - - lower - type: string + $ref: "#/components/schemas/MapTest_map_map_of_enum_value_value" type: object type: object map_of_enum_string: additionalProperties: - enum: - - UPPER - - lower - type: string + $ref: "#/components/schemas/MapTest_map_map_of_enum_value_value" type: object type: object ArrayTest: @@ -1384,15 +1321,12 @@ components: array_array_of_model: items: items: - $ref: '#/components/schemas/ReadOnlyFirst' + $ref: "#/components/schemas/ReadOnlyFirst" type: array type: array array_of_enum: items: - enum: - - UPPER - - lower - type: string + $ref: "#/components/schemas/MapTest_map_map_of_enum_value_value" type: array type: object NumberOnly: @@ -1419,24 +1353,15 @@ components: EnumArrays: properties: just_symbol: - enum: - - '>=' - - $ - type: string + $ref: "#/components/schemas/EnumArrays_just_symbol" array_enum: items: - enum: - - fish - - crab - type: string + $ref: "#/components/schemas/EnumArrays_array_enum_inner" type: array array_array_enum: items: items: - enum: - - Cat - - Dog - type: string + $ref: "#/components/schemas/EnumArrays_array_array_enum_inner_inner" type: array type: array type: object @@ -1467,6 +1392,13 @@ components: OuterBoolean: type: boolean x-codegen-body-parameter-name: boolean_post_body + findPetsByStatus_status_parameter_inner: + default: available + enum: + - available + - pending + - sold + type: string updatePetWithForm_request: properties: name: @@ -1486,17 +1418,44 @@ components: format: binary type: string type: object + testEnumParameters_request_enum_form_string: + default: -efg + description: Form parameter enum test (string) + enum: + - _abc + - -efg + - (xyz) + type: string testEnumParameters_request: properties: enum_form_string: - default: -efg - description: Form parameter enum test (string) - enum: - - _abc - - -efg - - (xyz) - type: string + $ref: "#/components/schemas/testEnumParameters_request_enum_form_string" type: object + testEnumParameters_enum_header_string_array_parameter_inner: + default: $ + enum: + - '>' + - $ + type: string + testEnumParameters_enum_header_string_parameter: + default: -efg + enum: + - _abc + - -efg + - (xyz) + type: string + testEnumParameters_enum_query_integer_parameter: + enum: + - 1 + - -2 + format: int32 + type: integer + testEnumParameters_enum_query_double_parameter: + enum: + - 1.1 + - -1.2 + format: double + type: number testEndpointParameters_request: properties: integer: @@ -1582,6 +1541,52 @@ components: - param - param2 type: object + Order_status: + description: Order Status + enum: + - placed + - approved + - delivered + type: string + Pet_status: + description: pet status in the store + enum: + - available + - pending + - sold + type: string + Enum_Test_enum_string: + enum: + - UPPER + - lower + - "" + type: string + Enum_Test_enum_integer: + enum: + - 1 + - -1 + format: int32 + type: integer + MapTest_map_map_of_enum_value_value: + enum: + - UPPER + - lower + type: string + EnumArrays_just_symbol: + enum: + - '>=' + - $ + type: string + EnumArrays_array_enum_inner: + enum: + - fish + - crab + type: string + EnumArrays_array_array_enum_inner_inner: + enum: + - Cat + - Dog + type: string securitySchemes: petstore_auth: flows: diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/bin/cli.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/bin/cli.rs new file mode 100644 index 000000000000..9ebc7336a225 --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/bin/cli.rs @@ -0,0 +1,1169 @@ +//! CLI tool driving the API client +use anyhow::{anyhow, Context, Result}; +use clap::Parser; +use dialoguer::Confirm; +use log::{debug, info}; +// models may be unused if all inputs are primitive types +#[allow(unused_imports)] +use petstore_with_fake_endpoints_models_for_testing::{ + models, ApiNoContext, Client, ContextWrapperExt, + TestSpecialTagsResponse, + Call123exampleResponse, + FakeOuterBooleanSerializeResponse, + FakeOuterCompositeSerializeResponse, + FakeOuterNumberSerializeResponse, + FakeOuterStringSerializeResponse, + FakeResponseWithNumericalDescriptionResponse, + TestBodyWithQueryParamsResponse, + TestClientModelResponse, + TestEndpointParametersResponse, + TestEnumParametersResponse, + TestInlineAdditionalPropertiesResponse, + TestJsonFormDataResponse, + HyphenParamResponse, + TestClassnameResponse, + AddPetResponse, + FindPetsByStatusResponse, + FindPetsByTagsResponse, + UpdatePetResponse, + DeletePetResponse, + GetPetByIdResponse, + UpdatePetWithFormResponse, + UploadFileResponse, + GetInventoryResponse, + PlaceOrderResponse, + DeleteOrderResponse, + GetOrderByIdResponse, + CreateUserResponse, + CreateUsersWithArrayInputResponse, + CreateUsersWithListInputResponse, + LoginUserResponse, + LogoutUserResponse, + DeleteUserResponse, + GetUserByNameResponse, + UpdateUserResponse, +}; +use simple_logger::SimpleLogger; +use swagger::{AuthData, ContextBuilder, EmptyContext, Push, XSpanIdString}; + +type ClientContext = swagger::make_context_ty!( + ContextBuilder, + EmptyContext, + Option, + XSpanIdString +); + +#[derive(Parser, Debug)] +#[clap( + name = "OpenAPI Petstore", + version = "1.0.0", + about = "CLI access to OpenAPI Petstore" +)] +struct Cli { + #[clap(subcommand)] + operation: Operation, + + /// Address or hostname of the server hosting this API, including optional port + #[clap(short = 'a', long, default_value = "http://localhost")] + server_address: String, + + /// Path to the client private key if using client-side TLS authentication + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_certificate", "server_certificate"]))] + client_key: Option, + + /// Path to the client's public certificate associated with the private key + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_key", "server_certificate"]))] + client_certificate: Option, + + /// Path to CA certificate used to authenticate the server + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long)] + server_certificate: Option, + + /// If set, write output to file instead of stdout + #[clap(short, long)] + output_file: Option, + + #[command(flatten)] + verbosity: clap_verbosity_flag::Verbosity, + + /// Don't ask for any confirmation prompts + #[allow(dead_code)] + #[clap(short, long)] + force: bool, + + /// Bearer token if used for authentication + #[arg(env = "PETSTORE_WITH_FAKE_ENDPOINTS_MODELS_FOR_TESTING_BEARER_TOKEN", hide_env = true)] + bearer_token: Option, + + /// API key for authentication + #[arg(long, env = "PETSTORE_WITH_FAKE_ENDPOINTS_MODELS_FOR_TESTING_API_KEY", hide_env = true)] + api_key: Option, +} + +#[derive(Parser, Debug)] +enum Operation { + /// To test special tags + TestSpecialTags { + /// client model + #[clap(value_parser = parse_json::)] + body: models::Client, + }, + Call123example { + }, + FakeOuterBooleanSerialize { + /// Input boolean as post body + #[clap(value_parser = parse_json::)] + body: Option, + }, + FakeOuterCompositeSerialize { + /// Input composite as post body + #[clap(value_parser = parse_json::)] + body: Option, + }, + FakeOuterNumberSerialize { + /// Input number as post body + #[clap(value_parser = parse_json::)] + body: Option, + }, + FakeOuterStringSerialize { + /// Input string as post body + #[clap(value_parser = parse_json::)] + body: Option, + }, + FakeResponseWithNumericalDescription { + }, + TestBodyWithQueryParams { + query: String, + #[clap(value_parser = parse_json::)] + body: models::User, + }, + /// To test \"client\" model + TestClientModel { + /// client model + #[clap(value_parser = parse_json::)] + body: models::Client, + }, + /// Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트 + TestEndpointParameters { + /// None + number: f64, + /// None + double: f64, + /// None + pattern_without_delimiter: String, + /// None + #[clap(value_parser = parse_json::)] + byte: swagger::ByteArray, + /// None + integer: Option, + /// None + int32: Option, + /// None + int64: Option, + /// None + float: Option, + /// None + string: Option, + /// None + #[clap(value_parser = parse_json::)] + binary: Option, + /// None + date: Option, + /// None + date_time: Option>, + /// None + password: Option, + /// None + callback: Option, + }, + /// To test enum parameters + TestEnumParameters { + /// Header parameter enum test (string array) + #[clap(value_parser = parse_json::>, long)] + enum_header_string_array: Option>, + /// Header parameter enum test (string) + #[clap(value_parser = parse_json::)] + enum_header_string: Option, + /// Query parameter enum test (string array) + #[clap(value_parser = parse_json::>, long)] + enum_query_string_array: Option>, + /// Query parameter enum test (string) + #[clap(value_parser = parse_json::)] + enum_query_string: Option, + /// Query parameter enum test (double) + #[clap(value_parser = parse_json::)] + enum_query_integer: Option, + /// Query parameter enum test (double) + #[clap(value_parser = parse_json::)] + enum_query_double: Option, + #[clap(value_parser = parse_json::)] + enum_form_string: Option, + }, + /// test inline additionalProperties + TestInlineAdditionalProperties { + /// request body + #[clap(value_parser = parse_json::>)] + param: std::collections::HashMap, + }, + /// test json serialization of form data + TestJsonFormData { + /// field1 + param: String, + /// field2 + param2: String, + }, + HyphenParam { + /// Parameter with hyphen in name + hyphen_param: String, + }, + /// To test class name in snake case + TestClassname { + /// client model + #[clap(value_parser = parse_json::)] + body: models::Client, + }, + /// Add a new pet to the store + AddPet { + /// Pet object that needs to be added to the store + #[clap(value_parser = parse_json::)] + body: models::Pet, + }, + /// Finds Pets by status + FindPetsByStatus { + /// Status values that need to be considered for filter + #[clap(value_parser = parse_json::>, long)] + status: Vec, + }, + /// Finds Pets by tags + FindPetsByTags { + /// Tags to filter by + #[clap(value_parser = parse_json::>, long)] + tags: Vec, + }, + /// Update an existing pet + UpdatePet { + /// Pet object that needs to be added to the store + #[clap(value_parser = parse_json::)] + body: models::Pet, + }, + /// Deletes a pet + DeletePet { + /// Pet id to delete + pet_id: i64, + api_key: Option, + }, + /// Find pet by ID + GetPetById { + /// ID of pet to return + pet_id: i64, + }, + /// Updates a pet in the store with form data + UpdatePetWithForm { + /// ID of pet that needs to be updated + pet_id: i64, + /// Updated name of the pet + name: Option, + /// Updated status of the pet + status: Option, + }, + /// uploads an image + UploadFile { + /// ID of pet to update + pet_id: i64, + /// Additional data to pass to server + additional_metadata: Option, + /// file to upload + #[clap(value_parser = parse_json::)] + file: Option, + }, + /// Returns pet inventories by status + GetInventory { + }, + /// Place an order for a pet + PlaceOrder { + /// order placed for purchasing the pet + #[clap(value_parser = parse_json::)] + body: models::Order, + }, + /// Delete purchase order by ID + DeleteOrder { + /// ID of the order that needs to be deleted + order_id: String, + }, + /// Find purchase order by ID + GetOrderById { + /// ID of pet that needs to be fetched + order_id: u64, + }, + /// Create user + CreateUser { + /// Created user object + #[clap(value_parser = parse_json::)] + body: models::User, + }, + /// Creates list of users with given input array + CreateUsersWithArrayInput { + /// List of user object + #[clap(value_parser = parse_json::>, long)] + body: Vec, + }, + /// Creates list of users with given input array + CreateUsersWithListInput { + /// List of user object + #[clap(value_parser = parse_json::>, long)] + body: Vec, + }, + /// Logs user into the system + LoginUser { + /// The user name for login + username: String, + /// The password for login in clear text + password: String, + }, + /// Logs out current logged in user session + LogoutUser { + }, + /// Delete user + DeleteUser { + /// The name that needs to be deleted + username: String, + }, + /// Get user by user name + GetUserByName { + /// The name that needs to be fetched. Use user1 for testing. + username: String, + }, + /// Updated user + UpdateUser { + /// name that need to be deleted + username: String, + /// Updated user object + #[clap(value_parser = parse_json::)] + body: models::User, + }, +} + +// On Linux/Unix with OpenSSL (client-tls feature), support certificate pinning and mutual TLS +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + if args.client_certificate.is_some() { + debug!("Using mutual TLS"); + let client = Client::try_new_https_mutual( + &args.server_address, + args.server_certificate.clone().unwrap(), + args.client_key.clone().unwrap(), + args.client_certificate.clone().unwrap(), + ) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else if args.server_certificate.is_some() { + debug!("Using TLS with pinned server certificate"); + let client = + Client::try_new_https_pinned(&args.server_address, args.server_certificate.clone().unwrap()) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else { + debug!("Using client without certificates"); + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) + } +} + +// On macOS/Windows/iOS or without client-tls feature, use simple client (no cert pinning/mutual TLS) +#[cfg(any( + not(feature = "client-tls"), + all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")) +))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + // Client::try_new() automatically detects the URL scheme (http:// or https://) + // and creates the appropriate client. + // Note: Certificate pinning and mutual TLS are only available on Linux/Unix with OpenSSL + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) +} + +#[tokio::main] +async fn main() -> Result<()> { + let args = Cli::parse(); + if let Some(log_level) = args.verbosity.log_level() { + SimpleLogger::new().with_level(log_level.to_level_filter()).init()?; + } + + debug!("Arguments: {:?}", &args); + + let mut auth_data: Option = None; + + if let Some(ref bearer_token) = args.bearer_token { + debug!("Using bearer token"); + auth_data = AuthData::bearer(bearer_token); + } + if let Some(ref api_key) = args.api_key { + debug!("Using API key"); + auth_data = Some(AuthData::apikey(api_key)); + } + + #[allow(trivial_casts)] + let context = swagger::make_context!( + ContextBuilder, + EmptyContext, + auth_data, + XSpanIdString::default() + ); + + let client = create_client(&args, context)?; + + let result = match args.operation { + Operation::TestSpecialTags { + body, + } => { + info!("Performing a TestSpecialTags request"); + + let result = client.test_special_tags( + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + TestSpecialTagsResponse::SuccessfulOperation + (body) + => "SuccessfulOperation\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::Call123example { + } => { + info!("Performing a Call123example request"); + + let result = client.call123example( + ).await?; + debug!("Result: {:?}", result); + + match result { + Call123exampleResponse::Success + => "Success\n".to_string() + , + } + } + Operation::FakeOuterBooleanSerialize { + body, + } => { + info!("Performing a FakeOuterBooleanSerialize request"); + + let result = client.fake_outer_boolean_serialize( + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + FakeOuterBooleanSerializeResponse::OutputBoolean + (body) + => "OutputBoolean\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::FakeOuterCompositeSerialize { + body, + } => { + info!("Performing a FakeOuterCompositeSerialize request"); + + let result = client.fake_outer_composite_serialize( + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + FakeOuterCompositeSerializeResponse::OutputComposite + (body) + => "OutputComposite\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::FakeOuterNumberSerialize { + body, + } => { + info!("Performing a FakeOuterNumberSerialize request"); + + let result = client.fake_outer_number_serialize( + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + FakeOuterNumberSerializeResponse::OutputNumber + (body) + => "OutputNumber\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::FakeOuterStringSerialize { + body, + } => { + info!("Performing a FakeOuterStringSerialize request"); + + let result = client.fake_outer_string_serialize( + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + FakeOuterStringSerializeResponse::OutputString + (body) + => "OutputString\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::FakeResponseWithNumericalDescription { + } => { + info!("Performing a FakeResponseWithNumericalDescription request"); + + let result = client.fake_response_with_numerical_description( + ).await?; + debug!("Result: {:?}", result); + + match result { + FakeResponseWithNumericalDescriptionResponse::Status200 + => "Status200\n".to_string() + , + } + } + Operation::TestBodyWithQueryParams { + query, + body, + } => { + info!("Performing a TestBodyWithQueryParams request"); + + let result = client.test_body_with_query_params( + query, + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + TestBodyWithQueryParamsResponse::Success + => "Success\n".to_string() + , + } + } + Operation::TestClientModel { + body, + } => { + info!("Performing a TestClientModel request"); + + let result = client.test_client_model( + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + TestClientModelResponse::SuccessfulOperation + (body) + => "SuccessfulOperation\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::TestEndpointParameters { + number, + double, + pattern_without_delimiter, + byte, + integer, + int32, + int64, + float, + string, + binary, + date, + date_time, + password, + callback, + } => { + info!("Performing a TestEndpointParameters request"); + + let result = client.test_endpoint_parameters( + number, + double, + pattern_without_delimiter, + byte, + integer, + int32, + int64, + float, + string, + binary, + date, + date_time, + password, + callback, + ).await?; + debug!("Result: {:?}", result); + + match result { + TestEndpointParametersResponse::InvalidUsernameSupplied + => "InvalidUsernameSupplied\n".to_string() + , + TestEndpointParametersResponse::UserNotFound + => "UserNotFound\n".to_string() + , + } + } + Operation::TestEnumParameters { + enum_header_string_array, + enum_header_string, + enum_query_string_array, + enum_query_string, + enum_query_integer, + enum_query_double, + enum_form_string, + } => { + info!("Performing a TestEnumParameters request"); + + let result = client.test_enum_parameters( + enum_header_string_array.as_ref(), + enum_header_string, + enum_query_string_array.as_ref(), + enum_query_string, + enum_query_integer, + enum_query_double, + enum_form_string, + ).await?; + debug!("Result: {:?}", result); + + match result { + TestEnumParametersResponse::InvalidRequest + => "InvalidRequest\n".to_string() + , + TestEnumParametersResponse::NotFound + => "NotFound\n".to_string() + , + } + } + Operation::TestInlineAdditionalProperties { + param, + } => { + info!("Performing a TestInlineAdditionalProperties request"); + + let result = client.test_inline_additional_properties( + param, + ).await?; + debug!("Result: {:?}", result); + + match result { + TestInlineAdditionalPropertiesResponse::SuccessfulOperation + => "SuccessfulOperation\n".to_string() + , + } + } + Operation::TestJsonFormData { + param, + param2, + } => { + info!("Performing a TestJsonFormData request"); + + let result = client.test_json_form_data( + param, + param2, + ).await?; + debug!("Result: {:?}", result); + + match result { + TestJsonFormDataResponse::SuccessfulOperation + => "SuccessfulOperation\n".to_string() + , + } + } + Operation::HyphenParam { + hyphen_param, + } => { + info!("Performing a HyphenParam request on {:?}", ( + &hyphen_param + )); + + let result = client.hyphen_param( + hyphen_param, + ).await?; + debug!("Result: {:?}", result); + + match result { + HyphenParamResponse::Success + => "Success\n".to_string() + , + } + } + Operation::TestClassname { + body, + } => { + info!("Performing a TestClassname request"); + + let result = client.test_classname( + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + TestClassnameResponse::SuccessfulOperation + (body) + => "SuccessfulOperation\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::AddPet { + body, + } => { + info!("Performing a AddPet request"); + + let result = client.add_pet( + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + AddPetResponse::InvalidInput + => "InvalidInput\n".to_string() + , + } + } + Operation::FindPetsByStatus { + status, + } => { + info!("Performing a FindPetsByStatus request"); + + let result = client.find_pets_by_status( + status.as_ref(), + ).await?; + debug!("Result: {:?}", result); + + match result { + FindPetsByStatusResponse::SuccessfulOperation + (body) + => "SuccessfulOperation\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + FindPetsByStatusResponse::InvalidStatusValue + => "InvalidStatusValue\n".to_string() + , + } + } + Operation::FindPetsByTags { + tags, + } => { + info!("Performing a FindPetsByTags request"); + + let result = client.find_pets_by_tags( + tags.as_ref(), + ).await?; + debug!("Result: {:?}", result); + + match result { + FindPetsByTagsResponse::SuccessfulOperation + (body) + => "SuccessfulOperation\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + FindPetsByTagsResponse::InvalidTagValue + => "InvalidTagValue\n".to_string() + , + } + } + Operation::UpdatePet { + body, + } => { + info!("Performing a UpdatePet request"); + + let result = client.update_pet( + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + UpdatePetResponse::InvalidIDSupplied + => "InvalidIDSupplied\n".to_string() + , + UpdatePetResponse::PetNotFound + => "PetNotFound\n".to_string() + , + UpdatePetResponse::ValidationException + => "ValidationException\n".to_string() + , + } + } + Operation::DeletePet { + pet_id, + api_key, + } => { + prompt(args.force, "This will delete the given entry, are you sure?")?; + info!("Performing a DeletePet request on {:?}", ( + &pet_id + )); + + let result = client.delete_pet( + pet_id, + api_key, + ).await?; + debug!("Result: {:?}", result); + + match result { + DeletePetResponse::InvalidPetValue + => "InvalidPetValue\n".to_string() + , + } + } + Operation::GetPetById { + pet_id, + } => { + info!("Performing a GetPetById request on {:?}", ( + &pet_id + )); + + let result = client.get_pet_by_id( + pet_id, + ).await?; + debug!("Result: {:?}", result); + + match result { + GetPetByIdResponse::SuccessfulOperation + (body) + => "SuccessfulOperation\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + GetPetByIdResponse::InvalidIDSupplied + => "InvalidIDSupplied\n".to_string() + , + GetPetByIdResponse::PetNotFound + => "PetNotFound\n".to_string() + , + } + } + Operation::UpdatePetWithForm { + pet_id, + name, + status, + } => { + info!("Performing a UpdatePetWithForm request on {:?}", ( + &pet_id + )); + + let result = client.update_pet_with_form( + pet_id, + name, + status, + ).await?; + debug!("Result: {:?}", result); + + match result { + UpdatePetWithFormResponse::InvalidInput + => "InvalidInput\n".to_string() + , + } + } + Operation::UploadFile { + pet_id, + additional_metadata, + file, + } => { + info!("Performing a UploadFile request on {:?}", ( + &pet_id + )); + + let result = client.upload_file( + pet_id, + additional_metadata, + file, + ).await?; + debug!("Result: {:?}", result); + + match result { + UploadFileResponse::SuccessfulOperation + (body) + => "SuccessfulOperation\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::GetInventory { + } => { + info!("Performing a GetInventory request"); + + let result = client.get_inventory( + ).await?; + debug!("Result: {:?}", result); + + match result { + GetInventoryResponse::SuccessfulOperation + (body) + => "SuccessfulOperation\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::PlaceOrder { + body, + } => { + info!("Performing a PlaceOrder request"); + + let result = client.place_order( + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + PlaceOrderResponse::SuccessfulOperation + (body) + => "SuccessfulOperation\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + PlaceOrderResponse::InvalidOrder + => "InvalidOrder\n".to_string() + , + } + } + Operation::DeleteOrder { + order_id, + } => { + prompt(args.force, "This will delete the given entry, are you sure?")?; + info!("Performing a DeleteOrder request on {:?}", ( + &order_id + )); + + let result = client.delete_order( + order_id, + ).await?; + debug!("Result: {:?}", result); + + match result { + DeleteOrderResponse::InvalidIDSupplied + => "InvalidIDSupplied\n".to_string() + , + DeleteOrderResponse::OrderNotFound + => "OrderNotFound\n".to_string() + , + } + } + Operation::GetOrderById { + order_id, + } => { + info!("Performing a GetOrderById request on {:?}", ( + &order_id + )); + + let result = client.get_order_by_id( + order_id, + ).await?; + debug!("Result: {:?}", result); + + match result { + GetOrderByIdResponse::SuccessfulOperation + (body) + => "SuccessfulOperation\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + GetOrderByIdResponse::InvalidIDSupplied + => "InvalidIDSupplied\n".to_string() + , + GetOrderByIdResponse::OrderNotFound + => "OrderNotFound\n".to_string() + , + } + } + Operation::CreateUser { + body, + } => { + info!("Performing a CreateUser request"); + + let result = client.create_user( + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + CreateUserResponse::SuccessfulOperation + => "SuccessfulOperation\n".to_string() + , + } + } + Operation::CreateUsersWithArrayInput { + body, + } => { + info!("Performing a CreateUsersWithArrayInput request"); + + let result = client.create_users_with_array_input( + body.as_ref(), + ).await?; + debug!("Result: {:?}", result); + + match result { + CreateUsersWithArrayInputResponse::SuccessfulOperation + => "SuccessfulOperation\n".to_string() + , + } + } + Operation::CreateUsersWithListInput { + body, + } => { + info!("Performing a CreateUsersWithListInput request"); + + let result = client.create_users_with_list_input( + body.as_ref(), + ).await?; + debug!("Result: {:?}", result); + + match result { + CreateUsersWithListInputResponse::SuccessfulOperation + => "SuccessfulOperation\n".to_string() + , + } + } + Operation::LoginUser { + username, + password, + } => { + info!("Performing a LoginUser request"); + + let result = client.login_user( + username, + password, + ).await?; + debug!("Result: {:?}", result); + + match result { + LoginUserResponse::SuccessfulOperation + { + body, + x_rate_limit, + x_expires_after, + } + => "SuccessfulOperation\n".to_string() + + + &format!("body: {}\n", serde_json::to_string_pretty(&body)?) + + &format!( + "x_rate_limit: {}\n", + serde_json::to_string_pretty(&x_rate_limit)? + ) + + &format!( + "x_expires_after: {}\n", + serde_json::to_string_pretty(&x_expires_after)? + ), + LoginUserResponse::InvalidUsername + => "InvalidUsername\n".to_string() + , + } + } + Operation::LogoutUser { + } => { + info!("Performing a LogoutUser request"); + + let result = client.logout_user( + ).await?; + debug!("Result: {:?}", result); + + match result { + LogoutUserResponse::SuccessfulOperation + => "SuccessfulOperation\n".to_string() + , + } + } + Operation::DeleteUser { + username, + } => { + prompt(args.force, "This will delete the given entry, are you sure?")?; + info!("Performing a DeleteUser request on {:?}", ( + &username + )); + + let result = client.delete_user( + username, + ).await?; + debug!("Result: {:?}", result); + + match result { + DeleteUserResponse::InvalidUsernameSupplied + => "InvalidUsernameSupplied\n".to_string() + , + DeleteUserResponse::UserNotFound + => "UserNotFound\n".to_string() + , + } + } + Operation::GetUserByName { + username, + } => { + info!("Performing a GetUserByName request on {:?}", ( + &username + )); + + let result = client.get_user_by_name( + username, + ).await?; + debug!("Result: {:?}", result); + + match result { + GetUserByNameResponse::SuccessfulOperation + (body) + => "SuccessfulOperation\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + GetUserByNameResponse::InvalidUsernameSupplied + => "InvalidUsernameSupplied\n".to_string() + , + GetUserByNameResponse::UserNotFound + => "UserNotFound\n".to_string() + , + } + } + Operation::UpdateUser { + username, + body, + } => { + info!("Performing a UpdateUser request on {:?}", ( + &username + )); + + let result = client.update_user( + username, + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + UpdateUserResponse::InvalidUserSupplied + => "InvalidUserSupplied\n".to_string() + , + UpdateUserResponse::UserNotFound + => "UserNotFound\n".to_string() + , + } + } + }; + + if let Some(output_file) = args.output_file { + std::fs::write(output_file, result)? + } else { + println!("{}", result); + } + Ok(()) +} + +fn prompt(force: bool, text: &str) -> Result<()> { + if force || Confirm::new().with_prompt(text).interact()? { + Ok(()) + } else { + Err(anyhow!("Aborting")) + } +} + +// May be unused if all inputs are primitive types +#[allow(dead_code)] +fn parse_json(json_string: &str) -> Result { + serde_json::from_str(json_string).map_err(|err| anyhow!("Error parsing input: {}", err)) +} diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/ArrayTest.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/ArrayTest.md index cfa79518c0a4..b563bd578c86 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/ArrayTest.md +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/ArrayTest.md @@ -6,7 +6,7 @@ Name | Type | Description | Notes **array_of_string** | **Vec** | | [optional] [default to None] **array_array_of_integer** | [**Vec>**](array.md) | | [optional] [default to None] **array_array_of_model** | [**Vec>**](array.md) | | [optional] [default to None] -**array_of_enum** | **Vec** | | [optional] [default to None] +**array_of_enum** | [**Vec**](MapTest_map_map_of_enum_value_value.md) | | [optional] [default to None] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/DollarSpecialLeftSquareBracketModelNameRightSquareBracket.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/DollarSpecialLeftSquareBracketModelNameRightSquareBracket.md new file mode 100644 index 000000000000..6719abdbbfd6 --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/DollarSpecialLeftSquareBracketModelNameRightSquareBracket.md @@ -0,0 +1,10 @@ +# DollarSpecialLeftSquareBracketModelNameRightSquareBracket + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- +**dollar_special_left_square_bracket_property_name_right_square_bracket** | **i64** | | [optional] [default to None] + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArrays.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArrays.md index 5e5f3548ebb6..f829bdd18ce1 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArrays.md +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArrays.md @@ -3,9 +3,9 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**just_symbol** | **String** | | [optional] [default to None] -**array_enum** | **Vec** | | [optional] [default to None] -**array_array_enum** | [**Vec>**](array.md) | | [optional] [default to None] +**just_symbol** | [***models::EnumArraysJustSymbol**](EnumArrays_just_symbol.md) | | [optional] [default to None] +**array_enum** | [**Vec**](EnumArrays_array_enum_inner.md) | | [optional] [default to None] +**array_array_enum** | [**Vec>**](array.md) | | [optional] [default to None] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArraysArrayArrayEnumInnerInner.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArraysArrayArrayEnumInnerInner.md new file mode 100644 index 000000000000..e811ef49a7b2 --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArraysArrayArrayEnumInnerInner.md @@ -0,0 +1,9 @@ +# EnumArraysArrayArrayEnumInnerInner + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArraysArrayEnumInner.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArraysArrayEnumInner.md new file mode 100644 index 000000000000..c976bdf93495 --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArraysArrayEnumInner.md @@ -0,0 +1,9 @@ +# EnumArraysArrayEnumInner + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArraysJustSymbol.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArraysJustSymbol.md new file mode 100644 index 000000000000..ebdd890812bd --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumArraysJustSymbol.md @@ -0,0 +1,9 @@ +# EnumArraysJustSymbol + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumTest.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumTest.md index 89b555dd5de1..cf89b12718d7 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumTest.md +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumTest.md @@ -3,10 +3,10 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**enum_string** | **String** | | [optional] [default to None] -**enum_string_required** | **String** | | -**enum_integer** | **i32** | | [optional] [default to None] -**enum_number** | **f64** | | [optional] [default to None] +**enum_string** | [***models::EnumTestEnumString**](Enum_Test_enum_string.md) | | [optional] [default to None] +**enum_string_required** | [***models::EnumTestEnumString**](Enum_Test_enum_string.md) | | +**enum_integer** | [***models::EnumTestEnumInteger**](Enum_Test_enum_integer.md) | | [optional] [default to None] +**enum_number** | [***models::TestEnumParametersEnumQueryDoubleParameter**](testEnumParameters_enum_query_double_parameter.md) | | [optional] [default to None] **outer_enum** | [***models::OuterEnum**](OuterEnum.md) | | [optional] [default to None] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumTestEnumInteger.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumTestEnumInteger.md new file mode 100644 index 000000000000..888dc92561e9 --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumTestEnumInteger.md @@ -0,0 +1,9 @@ +# EnumTestEnumInteger + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumTestEnumString.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumTestEnumString.md new file mode 100644 index 000000000000..9c8ada5e8f52 --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/EnumTestEnumString.md @@ -0,0 +1,9 @@ +# EnumTestEnumString + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/FindPetsByStatusStatusParameterInner.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/FindPetsByStatusStatusParameterInner.md new file mode 100644 index 000000000000..eb650a9da349 --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/FindPetsByStatusStatusParameterInner.md @@ -0,0 +1,9 @@ +# FindPetsByStatusStatusParameterInner + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/MapTest.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/MapTest.md index d3bdfd717a9d..590eae909b98 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/MapTest.md +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/MapTest.md @@ -4,8 +4,8 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **map_map_of_string** | [**std::collections::HashMap>**](map.md) | | [optional] [default to None] -**map_map_of_enum** | [**std::collections::HashMap>**](map.md) | | [optional] [default to None] -**map_of_enum_string** | **std::collections::HashMap** | | [optional] [default to None] +**map_map_of_enum** | [**std::collections::HashMap>**](map.md) | | [optional] [default to None] +**map_of_enum_string** | [**std::collections::HashMap**](MapTest_map_map_of_enum_value_value.md) | | [optional] [default to None] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/MapTestMapMapOfEnumValueValue.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/MapTestMapMapOfEnumValueValue.md new file mode 100644 index 000000000000..98f437d887b9 --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/MapTestMapMapOfEnumValueValue.md @@ -0,0 +1,9 @@ +# MapTestMapMapOfEnumValueValue + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/Order.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/Order.md index f94865fdaa85..ab8ebad2cefc 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/Order.md +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/Order.md @@ -7,7 +7,7 @@ Name | Type | Description | Notes **pet_id** | **i64** | | [optional] [default to None] **quantity** | **i32** | | [optional] [default to None] **ship_date** | [**chrono::DateTime::**](DateTime.md) | | [optional] [default to None] -**status** | **String** | Order Status | [optional] [default to None] +**status** | [***models::OrderStatus**](Order_status.md) | | [optional] [default to None] **complete** | **bool** | | [optional] [default to Some(false)] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/OrderStatus.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/OrderStatus.md new file mode 100644 index 000000000000..bf3cc64b90e6 --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/OrderStatus.md @@ -0,0 +1,9 @@ +# OrderStatus + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/Pet.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/Pet.md index 25930379f201..b82e37a480ed 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/Pet.md +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/Pet.md @@ -8,7 +8,7 @@ Name | Type | Description | Notes **name** | **String** | | **photo_urls** | **Vec** | | **tags** | [**Vec**](Tag.md) | | [optional] [default to None] -**status** | **String** | pet status in the store | [optional] [default to None] +**status** | [***models::PetStatus**](Pet_status.md) | | [optional] [default to None] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/PetStatus.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/PetStatus.md new file mode 100644 index 000000000000..a052000ba751 --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/PetStatus.md @@ -0,0 +1,9 @@ +# PetStatus + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumHeaderStringArrayParameterInner.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumHeaderStringArrayParameterInner.md new file mode 100644 index 000000000000..0035e028ccaf --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumHeaderStringArrayParameterInner.md @@ -0,0 +1,9 @@ +# TestEnumParametersEnumHeaderStringArrayParameterInner + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumHeaderStringParameter.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumHeaderStringParameter.md new file mode 100644 index 000000000000..2fae5705bd58 --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumHeaderStringParameter.md @@ -0,0 +1,9 @@ +# TestEnumParametersEnumHeaderStringParameter + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumQueryDoubleParameter.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumQueryDoubleParameter.md new file mode 100644 index 000000000000..2945c91e223c --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumQueryDoubleParameter.md @@ -0,0 +1,9 @@ +# TestEnumParametersEnumQueryDoubleParameter + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumQueryIntegerParameter.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumQueryIntegerParameter.md new file mode 100644 index 000000000000..95ad64f68da6 --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersEnumQueryIntegerParameter.md @@ -0,0 +1,9 @@ +# TestEnumParametersEnumQueryIntegerParameter + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersRequestEnumFormString.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersRequestEnumFormString.md new file mode 100644 index 000000000000..63a0cf68d6a9 --- /dev/null +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/TestEnumParametersRequestEnumFormString.md @@ -0,0 +1,9 @@ +# TestEnumParametersRequestEnumFormString + +## Properties +Name | Type | Description | Notes +------------ | ------------- | ------------- | ------------- + +[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) + + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/fake_api.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/fake_api.md index ddc0786bbe06..9b690e7b1ff3 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/fake_api.md +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/fake_api.md @@ -10,13 +10,13 @@ Method | HTTP request | Description **fakeOuterNumberSerialize**](fake_api.md#fakeOuterNumberSerialize) | **POST** /fake/outer/number | **fakeOuterStringSerialize**](fake_api.md#fakeOuterStringSerialize) | **POST** /fake/outer/string | **fake_response_with_numerical_description**](fake_api.md#fake_response_with_numerical_description) | **GET** /fake/response-with-numerical-description | -**hyphenParam**](fake_api.md#hyphenParam) | **GET** /fake/hyphenParam/{hyphen-param} | **testBodyWithQueryParams**](fake_api.md#testBodyWithQueryParams) | **PUT** /fake/body-with-query-params | **testClientModel**](fake_api.md#testClientModel) | **PATCH** /fake | To test \"client\" model **testEndpointParameters**](fake_api.md#testEndpointParameters) | **POST** /fake | Fake endpoint for testing various parameters 假端點 偽のエンドポイント 가짜 엔드 포인트 **testEnumParameters**](fake_api.md#testEnumParameters) | **GET** /fake | To test enum parameters **testInlineAdditionalProperties**](fake_api.md#testInlineAdditionalProperties) | **POST** /fake/inline-additionalProperties | test inline additionalProperties **testJsonFormData**](fake_api.md#testJsonFormData) | **GET** /fake/jsonFormData | test json serialization of form data +**hyphenParam**](fake_api.md#hyphenParam) | **GET** /fake/hyphenParam/{hyphen-param} | # **123example** @@ -199,33 +199,6 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **hyphenParam** -> hyphenParam(hyphen_param) - - -To test hyphen in path parameter name - -### Required Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **hyphen_param** | **String**| Parameter with hyphen in name | - -### Return type - - (empty response body) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: Not defined - -[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) - # **testBodyWithQueryParams** > testBodyWithQueryParams(query, body) @@ -305,8 +278,8 @@ Name | Type | Description | Notes **double** | **f64**| None | **pattern_without_delimiter** | **String**| None | **byte** | **swagger::ByteArray**| None | - **integer** | **i32**| None | - **int32** | **i32**| None | + **integer** | **u32**| None | + **int32** | **u32**| None | **int64** | **i64**| None | **float** | **f32**| None | **string** | **String**| None | @@ -348,13 +321,13 @@ Optional parameters are passed through a map[string]interface{}. Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **enum_header_string_array** | [**String**](String.md)| Header parameter enum test (string array) | - **enum_header_string** | **String**| Header parameter enum test (string) | [default to "-efg".to_string()] - **enum_query_string_array** | [**String**](String.md)| Query parameter enum test (string array) | - **enum_query_string** | **String**| Query parameter enum test (string) | [default to "-efg".to_string()] - **enum_query_integer** | **i32**| Query parameter enum test (double) | - **enum_query_double** | **f64**| Query parameter enum test (double) | - **enum_form_string** | **String**| Form parameter enum test (string) | [default to "-efg".to_string()] + **enum_header_string_array** | [**models::TestEnumParametersEnumHeaderStringArrayParameterInner**](models::TestEnumParametersEnumHeaderStringArrayParameterInner.md)| Header parameter enum test (string array) | + **enum_header_string** | [****](.md)| Header parameter enum test (string) | + **enum_query_string_array** | [**models::TestEnumParametersEnumHeaderStringArrayParameterInner**](models::TestEnumParametersEnumHeaderStringArrayParameterInner.md)| Query parameter enum test (string array) | + **enum_query_string** | [****](.md)| Query parameter enum test (string) | + **enum_query_integer** | [****](.md)| Query parameter enum test (double) | + **enum_query_double** | [****](.md)| Query parameter enum test (double) | + **enum_form_string** | [**testEnumParameters_request_enum_form_string**](testEnumParameters_request_enum_form_string.md)| | ### Return type @@ -422,3 +395,30 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **hyphenParam** +> hyphenParam(hyphen_param) + + +To test hyphen in path parameter name + +### Required Parameters + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **hyphen_param** | **String**| Parameter with hyphen in name | + +### Return type + + (empty response body) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: Not defined + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/pet_api.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/pet_api.md index 48dc1d0aefa0..26e6a98d32f4 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/pet_api.md +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/pet_api.md @@ -5,11 +5,11 @@ All URIs are relative to *http://petstore.swagger.io:80/v2* Method | HTTP request | Description ------------- | ------------- | ------------- **addPet**](pet_api.md#addPet) | **POST** /pet | Add a new pet to the store -**deletePet**](pet_api.md#deletePet) | **DELETE** /pet/{petId} | Deletes a pet **findPetsByStatus**](pet_api.md#findPetsByStatus) | **GET** /pet/findByStatus | Finds Pets by status **findPetsByTags**](pet_api.md#findPetsByTags) | **GET** /pet/findByTags | Finds Pets by tags -**getPetById**](pet_api.md#getPetById) | **GET** /pet/{petId} | Find pet by ID **updatePet**](pet_api.md#updatePet) | **PUT** /pet | Update an existing pet +**deletePet**](pet_api.md#deletePet) | **DELETE** /pet/{petId} | Deletes a pet +**getPetById**](pet_api.md#getPetById) | **GET** /pet/{petId} | Find pet by ID **updatePetWithForm**](pet_api.md#updatePetWithForm) | **POST** /pet/{petId} | Updates a pet in the store with form data **uploadFile**](pet_api.md#uploadFile) | **POST** /pet/{petId}/uploadImage | uploads an image @@ -40,29 +40,22 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **deletePet** -> deletePet(ctx, pet_id, optional) -Deletes a pet +# **findPetsByStatus** +> Vec findPetsByStatus(ctx, status) +Finds Pets by status + +Multiple status values can be provided with comma separated strings ### Required Parameters Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context containing the authentication | nil if no authentication - **pet_id** | **i64**| Pet id to delete | - **optional** | **map[string]interface{}** | optional parameters | nil if no parameters - -### Optional Parameters -Optional parameters are passed through a map[string]interface{}. - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **pet_id** | **i64**| Pet id to delete | - **api_key** | **String**| | + **status** | [**models::FindPetsByStatusStatusParameterInner**](models::FindPetsByStatusStatusParameterInner.md)| Status values that need to be considered for filter | ### Return type - (empty response body) +[**Vec**](Pet.md) ### Authorization @@ -71,22 +64,22 @@ Name | Type | Description | Notes ### HTTP request headers - **Content-Type**: Not defined - - **Accept**: Not defined + - **Accept**: application/json, application/xml [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **findPetsByStatus** -> Vec findPetsByStatus(ctx, status) -Finds Pets by status +# **findPetsByTags** +> Vec findPetsByTags(ctx, tags) +Finds Pets by tags -Multiple status values can be provided with comma separated strings +Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. ### Required Parameters Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context containing the authentication | nil if no authentication - **status** | [**String**](String.md)| Status values that need to be considered for filter | + **tags** | [**String**](String.md)| Tags to filter by | ### Return type @@ -103,22 +96,20 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **findPetsByTags** -> Vec findPetsByTags(ctx, tags) -Finds Pets by tags - -Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. +# **updatePet** +> updatePet(ctx, body) +Update an existing pet ### Required Parameters Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context containing the authentication | nil if no authentication - **tags** | [**String**](String.md)| Tags to filter by | + **body** | [**Pet**](Pet.md)| Pet object that needs to be added to the store | ### Return type -[**Vec**](Pet.md) + (empty response body) ### Authorization @@ -126,62 +117,71 @@ Name | Type | Description | Notes ### HTTP request headers - - **Content-Type**: Not defined - - **Accept**: application/json, application/xml + - **Content-Type**: application/json, application/xml + - **Accept**: Not defined [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **getPetById** -> models::Pet getPetById(ctx, pet_id) -Find pet by ID - -Returns a single pet +# **deletePet** +> deletePet(ctx, pet_id, optional) +Deletes a pet ### Required Parameters Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context containing the authentication | nil if no authentication - **pet_id** | **i64**| ID of pet to return | + **pet_id** | **i64**| Pet id to delete | + **optional** | **map[string]interface{}** | optional parameters | nil if no parameters + +### Optional Parameters +Optional parameters are passed through a map[string]interface{}. + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **pet_id** | **i64**| Pet id to delete | + **api_key** | **String**| | ### Return type -[**models::Pet**](Pet.md) + (empty response body) ### Authorization -[api_key](../README.md#api_key) +[petstore_auth](../README.md#petstore_auth) ### HTTP request headers - **Content-Type**: Not defined - - **Accept**: application/json, application/xml + - **Accept**: Not defined [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **updatePet** -> updatePet(ctx, body) -Update an existing pet +# **getPetById** +> models::Pet getPetById(ctx, pet_id) +Find pet by ID + +Returns a single pet ### Required Parameters Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- **ctx** | **context.Context** | context containing the authentication | nil if no authentication - **body** | [**Pet**](Pet.md)| Pet object that needs to be added to the store | + **pet_id** | **i64**| ID of pet to return | ### Return type - (empty response body) +[**models::Pet**](Pet.md) ### Authorization -[petstore_auth](../README.md#petstore_auth) +[api_key](../README.md#api_key) ### HTTP request headers - - **Content-Type**: application/json, application/xml - - **Accept**: Not defined + - **Content-Type**: Not defined + - **Accept**: application/json, application/xml [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/store_api.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/store_api.md index 9c8c27bcc365..2e92b2ee355a 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/store_api.md +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/store_api.md @@ -4,78 +4,76 @@ All URIs are relative to *http://petstore.swagger.io:80/v2* Method | HTTP request | Description ------------- | ------------- | ------------- -**deleteOrder**](store_api.md#deleteOrder) | **DELETE** /store/order/{order_id} | Delete purchase order by ID **getInventory**](store_api.md#getInventory) | **GET** /store/inventory | Returns pet inventories by status -**getOrderById**](store_api.md#getOrderById) | **GET** /store/order/{order_id} | Find purchase order by ID **placeOrder**](store_api.md#placeOrder) | **POST** /store/order | Place an order for a pet +**deleteOrder**](store_api.md#deleteOrder) | **DELETE** /store/order/{order_id} | Delete purchase order by ID +**getOrderById**](store_api.md#getOrderById) | **GET** /store/order/{order_id} | Find purchase order by ID -# **deleteOrder** -> deleteOrder(order_id) -Delete purchase order by ID +# **getInventory** +> std::collections::HashMap getInventory(ctx, ) +Returns pet inventories by status -For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors +Returns a map of status codes to quantities ### Required Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **order_id** | **String**| ID of the order that needs to be deleted | +This endpoint does not need any parameter. ### Return type - (empty response body) +[**std::collections::HashMap**](integer.md) ### Authorization -No authorization required +[api_key](../README.md#api_key) ### HTTP request headers - **Content-Type**: Not defined - - **Accept**: Not defined + - **Accept**: application/json [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **getInventory** -> std::collections::HashMap getInventory(ctx, ) -Returns pet inventories by status - -Returns a map of status codes to quantities +# **placeOrder** +> models::Order placeOrder(body) +Place an order for a pet ### Required Parameters -This endpoint does not need any parameter. + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **body** | [**Order**](Order.md)| order placed for purchasing the pet | ### Return type -[**std::collections::HashMap**](integer.md) +[**models::Order**](Order.md) ### Authorization -[api_key](../README.md#api_key) +No authorization required ### HTTP request headers - **Content-Type**: Not defined - - **Accept**: application/json + - **Accept**: application/json, application/xml [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **getOrderById** -> models::Order getOrderById(order_id) -Find purchase order by ID +# **deleteOrder** +> deleteOrder(order_id) +Delete purchase order by ID -For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions +For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors ### Required Parameters Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **order_id** | **i64**| ID of pet that needs to be fetched | + **order_id** | **String**| ID of the order that needs to be deleted | ### Return type -[**models::Order**](Order.md) + (empty response body) ### Authorization @@ -84,19 +82,21 @@ No authorization required ### HTTP request headers - **Content-Type**: Not defined - - **Accept**: application/json, application/xml + - **Accept**: Not defined [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **placeOrder** -> models::Order placeOrder(body) -Place an order for a pet +# **getOrderById** +> models::Order getOrderById(order_id) +Find purchase order by ID + +For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions ### Required Parameters Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **body** | [**Order**](Order.md)| order placed for purchasing the pet | + **order_id** | **u64**| ID of pet that needs to be fetched | ### Return type diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/user_api.md b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/user_api.md index 7e3c1b2ca1f6..9518a5d031c5 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/user_api.md +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/docs/user_api.md @@ -7,10 +7,10 @@ Method | HTTP request | Description **createUser**](user_api.md#createUser) | **POST** /user | Create user **createUsersWithArrayInput**](user_api.md#createUsersWithArrayInput) | **POST** /user/createWithArray | Creates list of users with given input array **createUsersWithListInput**](user_api.md#createUsersWithListInput) | **POST** /user/createWithList | Creates list of users with given input array -**deleteUser**](user_api.md#deleteUser) | **DELETE** /user/{username} | Delete user -**getUserByName**](user_api.md#getUserByName) | **GET** /user/{username} | Get user by user name **loginUser**](user_api.md#loginUser) | **GET** /user/login | Logs user into the system **logoutUser**](user_api.md#logoutUser) | **GET** /user/logout | Logs out current logged in user session +**deleteUser**](user_api.md#deleteUser) | **DELETE** /user/{username} | Delete user +**getUserByName**](user_api.md#getUserByName) | **GET** /user/{username} | Get user by user name **updateUser**](user_api.md#updateUser) | **PUT** /user/{username} | Updated user @@ -91,21 +91,20 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **deleteUser** -> deleteUser(username) -Delete user - -This can only be done by the logged in user. +# **loginUser** +> String loginUser(username, password) +Logs user into the system ### Required Parameters Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **username** | **String**| The name that needs to be deleted | + **username** | **String**| The user name for login | + **password** | **String**| The password for login in clear text | ### Return type - (empty response body) +[**String**](string.md) ### Authorization @@ -114,23 +113,20 @@ No authorization required ### HTTP request headers - **Content-Type**: Not defined - - **Accept**: Not defined + - **Accept**: application/json, application/xml [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **getUserByName** -> models::User getUserByName(username) -Get user by user name +# **logoutUser** +> logoutUser() +Logs out current logged in user session ### Required Parameters - -Name | Type | Description | Notes -------------- | ------------- | ------------- | ------------- - **username** | **String**| The name that needs to be fetched. Use user1 for testing. | +This endpoint does not need any parameter. ### Return type -[**models::User**](User.md) + (empty response body) ### Authorization @@ -139,24 +135,25 @@ No authorization required ### HTTP request headers - **Content-Type**: Not defined - - **Accept**: application/json, application/xml + - **Accept**: Not defined [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **loginUser** -> String loginUser(username, password) -Logs user into the system +# **deleteUser** +> deleteUser(username) +Delete user + +This can only be done by the logged in user. ### Required Parameters Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- - **username** | **String**| The user name for login | - **password** | **String**| The password for login in clear text | + **username** | **String**| The name that needs to be deleted | ### Return type -[**String**](string.md) + (empty response body) ### Authorization @@ -165,20 +162,23 @@ No authorization required ### HTTP request headers - **Content-Type**: Not defined - - **Accept**: application/json, application/xml + - **Accept**: Not defined [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) -# **logoutUser** -> logoutUser() -Logs out current logged in user session +# **getUserByName** +> models::User getUserByName(username) +Get user by user name ### Required Parameters -This endpoint does not need any parameter. + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **username** | **String**| The name that needs to be fetched. Use user1 for testing. | ### Return type - (empty response body) +[**models::User**](User.md) ### Authorization @@ -187,7 +187,7 @@ No authorization required ### HTTP request headers - **Content-Type**: Not defined - - **Accept**: Not defined + - **Accept**: application/json, application/xml [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/client/main.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/client/main.rs index b3cd7d27e032..41ce2cfaee50 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/client/main.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/client/main.rs @@ -12,36 +12,36 @@ use petstore_with_fake_endpoints_models_for_testing::{Api, ApiNoContext, Claims, FakeOuterNumberSerializeResponse, FakeOuterStringSerializeResponse, FakeResponseWithNumericalDescriptionResponse, - HyphenParamResponse, TestBodyWithQueryParamsResponse, TestClientModelResponse, TestEndpointParametersResponse, TestEnumParametersResponse, TestInlineAdditionalPropertiesResponse, TestJsonFormDataResponse, + HyphenParamResponse, TestClassnameResponse, AddPetResponse, - DeletePetResponse, FindPetsByStatusResponse, FindPetsByTagsResponse, - GetPetByIdResponse, UpdatePetResponse, + DeletePetResponse, + GetPetByIdResponse, UpdatePetWithFormResponse, UploadFileResponse, - DeleteOrderResponse, GetInventoryResponse, - GetOrderByIdResponse, PlaceOrderResponse, + DeleteOrderResponse, + GetOrderByIdResponse, CreateUserResponse, CreateUsersWithArrayInputResponse, CreateUsersWithListInputResponse, - DeleteUserResponse, - GetUserByNameResponse, LoginUserResponse, LogoutUserResponse, + DeleteUserResponse, + GetUserByNameResponse, UpdateUserResponse, }; -use clap::{App, Arg}; +use clap::{Command, Arg}; // NOTE: Set environment variable RUST_LOG to the name of the executable (or "cargo run") to activate console logging for all loglevels. // See https://docs.rs/env_logger/latest/env_logger/ for more details @@ -64,49 +64,42 @@ use client_auth::build_token; fn main() { env_logger::init(); - let matches = App::new("client") - .arg(Arg::with_name("operation") + let matches = Command::new("client") + .arg(Arg::new("operation") .help("Sets the operation to run") - .possible_values(&[ - "Call123example", - "FakeOuterBooleanSerialize", - "FakeOuterCompositeSerialize", - "FakeOuterNumberSerialize", - "FakeOuterStringSerialize", - "FakeResponseWithNumericalDescription", - "HyphenParam", - "TestEndpointParameters", - "TestEnumParameters", - "TestJsonFormData", - "DeletePet", - "FindPetsByStatus", - "FindPetsByTags", - "GetPetById", - "UpdatePetWithForm", - "UploadFile", - "DeleteOrder", - "GetInventory", - "GetOrderById", - "CreateUsersWithArrayInput", - "CreateUsersWithListInput", - "DeleteUser", - "GetUserByName", - "LoginUser", - "LogoutUser", - ]) + .value_parser(Vec::<&str>::from([ + "Call123example", + "FakeOuterBooleanSerialize", + "FakeOuterCompositeSerialize", + "FakeOuterNumberSerialize", + "FakeOuterStringSerialize", + "FakeResponseWithNumericalDescription", + "TestEndpointParameters", + "TestEnumParameters", + "TestJsonFormData", + "FindPetsByStatus", + "FindPetsByTags", + "DeletePet", + "GetPetById", + "UpdatePetWithForm", + "UploadFile", + "GetInventory", + "GetOrderById", + "CreateUsersWithArrayInput", + "CreateUsersWithListInput", + "LogoutUser", + ])) .required(true) .index(1)) - .arg(Arg::with_name("https") + .arg(Arg::new("https") .long("https") .help("Whether to use HTTPS or not")) - .arg(Arg::with_name("host") + .arg(Arg::new("host") .long("host") - .takes_value(true) .default_value("petstore.swagger.io") .help("Hostname to contact")) - .arg(Arg::with_name("port") + .arg(Arg::new("port") .long("port") - .takes_value(true) .default_value("80") .help("Port to contact")) .get_matches(); @@ -115,55 +108,71 @@ fn main() { // In a real (production) system this Bearer token should be obtained via an external Identity/Authentication-server // Ensure that you set the correct algorithm and encodingkey that matches what is used on the server side. // See https://github.com/Keats/jsonwebtoken for more information - let auth_token = build_token( Claims { - sub: "tester@acme.com".to_owned(), + sub: "tester@acme.com".to_owned(), company: "ACME".to_owned(), iss: "my_identity_provider".to_owned(), // added a very long expiry time aud: "org.acme.Resource_Server".to_string(), exp: 10000000000, // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ + scopes: + [ "write:pets", "read:pets", - ].join(", ") - }, + ].join::<&str>(", ") + }, b"secret").unwrap(); let auth_data = if !auth_token.is_empty() { - Some(AuthData::Bearer(swagger::auth::Bearer { token: auth_token})) + Some(AuthData::Bearer(auth_token)) } else { // No Bearer-token available, so return None None }; - let is_https = matches.is_present("https"); + let is_https = matches.contains_id("https"); let base_url = format!("{}://{}:{}", if is_https { "https" } else { "http" }, - matches.value_of("host").unwrap(), - matches.value_of("port").unwrap()); + matches.get_one::("host").unwrap(), + matches.get_one::("port").unwrap()); let context: ClientContext = swagger::make_context!(ContextBuilder, EmptyContext, auth_data, XSpanIdString::default()); - let mut client : Box> = if matches.is_present("https") { - // Using Simple HTTPS - let client = Box::new(Client::try_new_https(&base_url) - .expect("Failed to create HTTPS client")); - Box::new(client.with_context(context)) - } else { - // Using HTTP - let client = Box::new(Client::try_new_http( - &base_url) - .expect("Failed to create HTTP client")); - Box::new(client.with_context(context)) + let mut client : Box> = { + #[cfg(feature = "client-tls")] + { + if is_https { + // Using HTTPS with native-tls + let client = Box::new(Client::try_new_https(&base_url) + .expect("Failed to create HTTPS client")); + Box::new(client.with_context(context)) + } else { + // Using HTTP + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } + } + + #[cfg(not(feature = "client-tls"))] + { + if is_https { + panic!("HTTPS requested but TLS support not enabled. \ + Enable the 'client-tls' feature to use HTTPS."); + } + // Using HTTP only + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } }; let mut rt = tokio::runtime::Runtime::new().unwrap(); - match matches.value_of("operation") { + match matches.get_one::("operation").map(String::as_str) { /* Disabled because there's no example. Some("TestSpecialTags") => { let result = rt.block_on(client.test_special_tags( @@ -206,16 +215,10 @@ fn main() { )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, - Some("HyphenParam") => { - let result = rt.block_on(client.hyphen_param( - "hyphen_param_example".to_string() - )); - info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); - }, /* Disabled because there's no example. Some("TestBodyWithQueryParams") => { let result = rt.block_on(client.test_body_with_query_params( - "query_example".to_string(), + ???, ??? )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); @@ -251,12 +254,12 @@ fn main() { Some("TestEnumParameters") => { let result = rt.block_on(client.test_enum_parameters( Some(&Vec::new()), - Some("enum_header_string_example".to_string()), + Some(models::TestEnumParametersEnumHeaderStringParameter::Abc), Some(&Vec::new()), - Some("enum_query_string_example".to_string()), - Some(56), - Some(1.2), - Some("enum_form_string_example".to_string()) + Some(models::TestEnumParametersEnumHeaderStringParameter::Abc), + Some(models::TestEnumParametersEnumQueryIntegerParameter::Variant1), + Some(models::TestEnumParametersEnumQueryDoubleParameter::Variant11), + Some(models::TestEnumParametersRequestEnumFormString::Abc) )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, @@ -276,6 +279,14 @@ fn main() { info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, /* Disabled because there's no example. + Some("HyphenParam") => { + let result = rt.block_on(client.hyphen_param( + ??? + )); + info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); + }, + */ + /* Disabled because there's no example. Some("TestClassname") => { let result = rt.block_on(client.test_classname( ??? @@ -291,13 +302,6 @@ fn main() { info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, */ - Some("DeletePet") => { - let result = rt.block_on(client.delete_pet( - 789, - Some("api_key_example".to_string()) - )); - info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); - }, Some("FindPetsByStatus") => { let result = rt.block_on(client.find_pets_by_status( &Vec::new() @@ -310,12 +314,6 @@ fn main() { )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, - Some("GetPetById") => { - let result = rt.block_on(client.get_pet_by_id( - 789 - )); - info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); - }, /* Disabled because there's no example. Some("UpdatePet") => { let result = rt.block_on(client.update_pet( @@ -324,9 +322,22 @@ fn main() { info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, */ + Some("DeletePet") => { + let result = rt.block_on(client.delete_pet( + 0, + None + )); + info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); + }, + Some("GetPetById") => { + let result = rt.block_on(client.get_pet_by_id( + 0 + )); + info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); + }, Some("UpdatePetWithForm") => { let result = rt.block_on(client.update_pet_with_form( - 789, + 0, Some("name_example".to_string()), Some("status_example".to_string()) )); @@ -334,37 +345,39 @@ fn main() { }, Some("UploadFile") => { let result = rt.block_on(client.upload_file( - 789, + 0, Some("additional_metadata_example".to_string()), Some(swagger::ByteArray(Vec::from("BINARY_DATA_HERE"))) )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, - Some("DeleteOrder") => { - let result = rt.block_on(client.delete_order( - "order_id_example".to_string() - )); - info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); - }, Some("GetInventory") => { let result = rt.block_on(client.get_inventory( )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, - Some("GetOrderById") => { - let result = rt.block_on(client.get_order_by_id( - 789 + /* Disabled because there's no example. + Some("PlaceOrder") => { + let result = rt.block_on(client.place_order( + ??? )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, + */ /* Disabled because there's no example. - Some("PlaceOrder") => { - let result = rt.block_on(client.place_order( + Some("DeleteOrder") => { + let result = rt.block_on(client.delete_order( ??? )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, */ + Some("GetOrderById") => { + let result = rt.block_on(client.get_order_by_id( + 0 + )); + info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); + }, /* Disabled because there's no example. Some("CreateUser") => { let result = rt.block_on(client.create_user( @@ -385,34 +398,40 @@ fn main() { )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, - Some("DeleteUser") => { - let result = rt.block_on(client.delete_user( - "username_example".to_string() + /* Disabled because there's no example. + Some("LoginUser") => { + let result = rt.block_on(client.login_user( + ???, + ??? )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, - Some("GetUserByName") => { - let result = rt.block_on(client.get_user_by_name( - "username_example".to_string() + */ + Some("LogoutUser") => { + let result = rt.block_on(client.logout_user( )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, - Some("LoginUser") => { - let result = rt.block_on(client.login_user( - "username_example".to_string(), - "password_example".to_string() + /* Disabled because there's no example. + Some("DeleteUser") => { + let result = rt.block_on(client.delete_user( + ??? )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, - Some("LogoutUser") => { - let result = rt.block_on(client.logout_user( + */ + /* Disabled because there's no example. + Some("GetUserByName") => { + let result = rt.block_on(client.get_user_by_name( + ??? )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); }, + */ /* Disabled because there's no example. Some("UpdateUser") => { let result = rt.block_on(client.update_user( - "username_example".to_string(), + ???, ??? )); info!("{:?} (X-Span-ID: {:?})", result, (client.context() as &dyn Has).get().clone()); diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server/main.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server/main.rs index 63e175c3dc90..2b3cd2612d79 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server/main.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server/main.rs @@ -3,26 +3,26 @@ #![allow(missing_docs)] - -use clap::{App, Arg}; +use clap::{Arg, Command}; mod server; mod server_auth; - /// Create custom server, wire it to the autogenerated router, /// and pass it to the web server. #[tokio::main] async fn main() { env_logger::init(); - let matches = App::new("server") - .arg(Arg::with_name("https") - .long("https") - .help("Whether to use HTTPS or not")) + let matches = Command::new("server") + .arg( + Arg::new("https") + .long("https") + .help("Whether to use HTTPS or not"), + ) .get_matches(); - let addr = "127.0.0.1:80"; + let addr = "127.0.0.1:8080"; - server::create(addr, matches.is_present("https")).await; + server::create(addr, matches.contains_id("https")).await; } diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server/server.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server/server.rs index 38904f6f5680..98ed4ce9894a 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server/server.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server/server.rs @@ -4,8 +4,9 @@ use async_trait::async_trait; use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt}; -use hyper::server::conn::Http; -use hyper::service::Service; +use hyper::server::conn::http1; +use hyper_util::rt::TokioIo; +use hyper::service::{service_fn, Service}; use log::info; use std::future::Future; use std::marker::PhantomData; @@ -24,15 +25,13 @@ use petstore_with_fake_endpoints_models_for_testing::models; /// Builds an SSL implementation for Simple HTTPS from some hard-coded file names pub async fn create(addr: &str, https: bool) { - let addr = addr.parse().expect("Failed to parse bind address"); + let addr: SocketAddr = addr.parse().expect("Failed to parse bind address"); + let listener = TcpListener::bind(&addr).await.unwrap(); let server = Server::new(); let service = MakeService::new(server); - - // This pushes a fourth layer of the middleware-stack even though Swagger assumes only three levels. - // This fourth layer creates an accept-all policy, hower the example-code already acchieves the same via a Bearer-token with full permissions, so next line is not needed (anymore). - // let service = MakeAllowAllAuthenticator::new(service, "cosmo"); + let service = MakeAllowAllAuthenticator::new(service, "cosmo"); #[allow(unused_mut)] let mut service = @@ -56,21 +55,19 @@ pub async fn create(addr: &str, https: bool) { ssl.check_private_key().expect("Failed to check private key"); let tls_acceptor = ssl.build(); - let tcp_listener = TcpListener::bind(&addr).await.unwrap(); info!("Starting a server (with https)"); loop { - if let Ok((tcp, _)) = tcp_listener.accept().await { + if let Ok((tcp, addr)) = listener.accept().await { let ssl = Ssl::new(tls_acceptor.context()).unwrap(); - let addr = tcp.peer_addr().expect("Unable to get remote address"); let service = service.call(addr); tokio::spawn(async move { let tls = tokio_openssl::SslStream::new(ssl, tcp).map_err(|_| ())?; let service = service.await.map_err(|_| ())?; - Http::new() - .serve_connection(tls, service) + http1::Builder::new() + .serve_connection(TokioIo::new(tls), service) .await .map_err(|_| ()) }); @@ -79,12 +76,40 @@ pub async fn create(addr: &str, https: bool) { } } else { info!("Starting a server (over http, so no TLS)"); - // Using HTTP - hyper::server::Server::bind(&addr).serve(service).await.unwrap() + println!("Listening on http://{}", addr); + + loop { + // When an incoming TCP connection is received grab a TCP stream for + // client<->server communication. + // + // Note, this is a .await point, this loop will loop forever but is not a busy loop. The + // .await point allows the Tokio runtime to pull the task off of the thread until the task + // has work to do. In this case, a connection arrives on the port we are listening on and + // the task is woken up, at which point the task is then put back on a thread, and is + // driven forward by the runtime, eventually yielding a TCP stream. + let (tcp_stream, addr) = listener.accept().await.expect("Failed to accept connection"); + + let service = service.call(addr).await.unwrap(); + let io = TokioIo::new(tcp_stream); + // Spin up a new task in Tokio so we can continue to listen for new TCP connection on the + // current task without waiting for the processing of the HTTP1 connection we just received + // to finish + tokio::task::spawn(async move { + // Handle the connection from the client using HTTP1 and pass any + // HTTP requests received on that connection to the `hello` function + let result = http1::Builder::new() + .serve_connection(io, service) + .await; + if let Err(err) = result + { + println!("Error serving connection: {err:?}"); + } + }); + } } } -#[derive(Copy, Clone)] +#[derive(Copy)] pub struct Server { marker: PhantomData, } @@ -95,6 +120,14 @@ impl Server { } } +impl Clone for Server { + fn clone(&self) -> Self { + Self { + marker: PhantomData, + } + } +} + use jsonwebtoken::{decode, encode, errors::Error as JwtError, Algorithm, DecodingKey, EncodingKey, Header, TokenData, Validation}; use serde::{Deserialize, Serialize}; @@ -111,33 +144,33 @@ use petstore_with_fake_endpoints_models_for_testing::{ FakeOuterNumberSerializeResponse, FakeOuterStringSerializeResponse, FakeResponseWithNumericalDescriptionResponse, - HyphenParamResponse, TestBodyWithQueryParamsResponse, TestClientModelResponse, TestEndpointParametersResponse, TestEnumParametersResponse, TestInlineAdditionalPropertiesResponse, TestJsonFormDataResponse, + HyphenParamResponse, TestClassnameResponse, AddPetResponse, - DeletePetResponse, FindPetsByStatusResponse, FindPetsByTagsResponse, - GetPetByIdResponse, UpdatePetResponse, + DeletePetResponse, + GetPetByIdResponse, UpdatePetWithFormResponse, UploadFileResponse, - DeleteOrderResponse, GetInventoryResponse, - GetOrderByIdResponse, PlaceOrderResponse, + DeleteOrderResponse, + GetOrderByIdResponse, CreateUserResponse, CreateUsersWithArrayInputResponse, CreateUsersWithListInputResponse, - DeleteUserResponse, - GetUserByNameResponse, LoginUserResponse, LogoutUserResponse, + DeleteUserResponse, + GetUserByNameResponse, UpdateUserResponse, }; use petstore_with_fake_endpoints_models_for_testing::server::MakeService; @@ -209,15 +242,6 @@ impl Api for Server where C: Has + Send + Sync Err(ApiError("Api-Error: Operation is NOT implemented".into())) } - async fn hyphen_param( - &self, - hyphen_param: String, - context: &C) -> Result - { - info!("hyphen_param(\"{}\") - X-Span-ID: {:?}", hyphen_param, context.get().0.clone()); - Err(ApiError("Api-Error: Operation is NOT implemented".into())) - } - async fn test_body_with_query_params( &self, query: String, @@ -245,8 +269,8 @@ impl Api for Server where C: Has + Send + Sync double: f64, pattern_without_delimiter: String, byte: swagger::ByteArray, - integer: Option, - int32: Option, + integer: Option, + int32: Option, int64: Option, float: Option, string: Option, @@ -262,15 +286,15 @@ impl Api for Server where C: Has + Send + Sync } /// To test enum parameters - async fn test_enum_parameters( - &self, - enum_header_string_array: Option<&Vec>, - enum_header_string: Option, - enum_query_string_array: Option<&Vec>, - enum_query_string: Option, - enum_query_integer: Option, - enum_query_double: Option, - enum_form_string: Option, + async fn test_enum_parameters<'a>( + &self, + enum_header_string_array: Option<&'a Vec>, + enum_header_string: Option, + enum_query_string_array: Option<&'a Vec>, + enum_query_string: Option, + enum_query_integer: Option, + enum_query_double: Option, + enum_form_string: Option, context: &C) -> Result { info!("test_enum_parameters({:?}, {:?}, {:?}, {:?}, {:?}, {:?}, {:?}) - X-Span-ID: {:?}", enum_header_string_array, enum_header_string, enum_query_string_array, enum_query_string, enum_query_integer, enum_query_double, enum_form_string, context.get().0.clone()); @@ -298,6 +322,15 @@ impl Api for Server where C: Has + Send + Sync Err(ApiError("Api-Error: Operation is NOT implemented".into())) } + async fn hyphen_param( + &self, + hyphen_param: String, + context: &C) -> Result + { + info!("hyphen_param(\"{}\") - X-Span-ID: {:?}", hyphen_param, context.get().0.clone()); + Err(ApiError("Api-Error: Operation is NOT implemented".into())) + } + /// To test class name in snake case async fn test_classname( &self, @@ -318,21 +351,10 @@ impl Api for Server where C: Has + Send + Sync Err(ApiError("Api-Error: Operation is NOT implemented".into())) } - /// Deletes a pet - async fn delete_pet( - &self, - pet_id: i64, - api_key: Option, - context: &C) -> Result - { - info!("delete_pet({}, {:?}) - X-Span-ID: {:?}", pet_id, api_key, context.get().0.clone()); - Err(ApiError("Api-Error: Operation is NOT implemented".into())) - } - /// Finds Pets by status - async fn find_pets_by_status( + async fn find_pets_by_status<'a>( &self, - status: &Vec, + status: &'a Vec, context: &C) -> Result { info!("find_pets_by_status({:?}) - X-Span-ID: {:?}", status, context.get().0.clone()); @@ -340,32 +362,43 @@ impl Api for Server where C: Has + Send + Sync } /// Finds Pets by tags - async fn find_pets_by_tags( + async fn find_pets_by_tags<'a>( &self, - tags: &Vec, + tags: &'a Vec, context: &C) -> Result { info!("find_pets_by_tags({:?}) - X-Span-ID: {:?}", tags, context.get().0.clone()); Err(ApiError("Api-Error: Operation is NOT implemented".into())) } - /// Find pet by ID - async fn get_pet_by_id( + /// Update an existing pet + async fn update_pet( + &self, + body: models::Pet, + context: &C) -> Result + { + info!("update_pet({:?}) - X-Span-ID: {:?}", body, context.get().0.clone()); + Err(ApiError("Api-Error: Operation is NOT implemented".into())) + } + + /// Deletes a pet + async fn delete_pet( &self, pet_id: i64, - context: &C) -> Result + api_key: Option, + context: &C) -> Result { - info!("get_pet_by_id({}) - X-Span-ID: {:?}", pet_id, context.get().0.clone()); + info!("delete_pet({}, {:?}) - X-Span-ID: {:?}", pet_id, api_key, context.get().0.clone()); Err(ApiError("Api-Error: Operation is NOT implemented".into())) } - /// Update an existing pet - async fn update_pet( + /// Find pet by ID + async fn get_pet_by_id( &self, - body: models::Pet, - context: &C) -> Result + pet_id: i64, + context: &C) -> Result { - info!("update_pet({:?}) - X-Span-ID: {:?}", body, context.get().0.clone()); + info!("get_pet_by_id({}) - X-Span-ID: {:?}", pet_id, context.get().0.clone()); Err(ApiError("Api-Error: Operation is NOT implemented".into())) } @@ -393,42 +426,42 @@ impl Api for Server where C: Has + Send + Sync Err(ApiError("Api-Error: Operation is NOT implemented".into())) } - /// Delete purchase order by ID - async fn delete_order( + /// Returns pet inventories by status + async fn get_inventory( &self, - order_id: String, - context: &C) -> Result + context: &C) -> Result { - info!("delete_order(\"{}\") - X-Span-ID: {:?}", order_id, context.get().0.clone()); + info!("get_inventory() - X-Span-ID: {:?}", context.get().0.clone()); Err(ApiError("Api-Error: Operation is NOT implemented".into())) } - /// Returns pet inventories by status - async fn get_inventory( + /// Place an order for a pet + async fn place_order( &self, - context: &C) -> Result + body: models::Order, + context: &C) -> Result { - info!("get_inventory() - X-Span-ID: {:?}", context.get().0.clone()); + info!("place_order({:?}) - X-Span-ID: {:?}", body, context.get().0.clone()); Err(ApiError("Api-Error: Operation is NOT implemented".into())) } - /// Find purchase order by ID - async fn get_order_by_id( + /// Delete purchase order by ID + async fn delete_order( &self, - order_id: i64, - context: &C) -> Result + order_id: String, + context: &C) -> Result { - info!("get_order_by_id({}) - X-Span-ID: {:?}", order_id, context.get().0.clone()); + info!("delete_order(\"{}\") - X-Span-ID: {:?}", order_id, context.get().0.clone()); Err(ApiError("Api-Error: Operation is NOT implemented".into())) } - /// Place an order for a pet - async fn place_order( + /// Find purchase order by ID + async fn get_order_by_id( &self, - body: models::Order, - context: &C) -> Result + order_id: u64, + context: &C) -> Result { - info!("place_order({:?}) - X-Span-ID: {:?}", body, context.get().0.clone()); + info!("get_order_by_id({}) - X-Span-ID: {:?}", order_id, context.get().0.clone()); Err(ApiError("Api-Error: Operation is NOT implemented".into())) } @@ -443,9 +476,9 @@ impl Api for Server where C: Has + Send + Sync } /// Creates list of users with given input array - async fn create_users_with_array_input( + async fn create_users_with_array_input<'a>( &self, - body: &Vec, + body: &'a Vec, context: &C) -> Result { info!("create_users_with_array_input({:?}) - X-Span-ID: {:?}", body, context.get().0.clone()); @@ -453,52 +486,52 @@ impl Api for Server where C: Has + Send + Sync } /// Creates list of users with given input array - async fn create_users_with_list_input( + async fn create_users_with_list_input<'a>( &self, - body: &Vec, + body: &'a Vec, context: &C) -> Result { info!("create_users_with_list_input({:?}) - X-Span-ID: {:?}", body, context.get().0.clone()); Err(ApiError("Api-Error: Operation is NOT implemented".into())) } - /// Delete user - async fn delete_user( + /// Logs user into the system + async fn login_user( &self, username: String, - context: &C) -> Result + password: String, + context: &C) -> Result { - info!("delete_user(\"{}\") - X-Span-ID: {:?}", username, context.get().0.clone()); + info!("login_user(\"{}\", \"{}\") - X-Span-ID: {:?}", username, password, context.get().0.clone()); Err(ApiError("Api-Error: Operation is NOT implemented".into())) } - /// Get user by user name - async fn get_user_by_name( + /// Logs out current logged in user session + async fn logout_user( &self, - username: String, - context: &C) -> Result + context: &C) -> Result { - info!("get_user_by_name(\"{}\") - X-Span-ID: {:?}", username, context.get().0.clone()); + info!("logout_user() - X-Span-ID: {:?}", context.get().0.clone()); Err(ApiError("Api-Error: Operation is NOT implemented".into())) } - /// Logs user into the system - async fn login_user( + /// Delete user + async fn delete_user( &self, username: String, - password: String, - context: &C) -> Result + context: &C) -> Result { - info!("login_user(\"{}\", \"{}\") - X-Span-ID: {:?}", username, password, context.get().0.clone()); + info!("delete_user(\"{}\") - X-Span-ID: {:?}", username, context.get().0.clone()); Err(ApiError("Api-Error: Operation is NOT implemented".into())) } - /// Logs out current logged in user session - async fn logout_user( + /// Get user by user name + async fn get_user_by_name( &self, - context: &C) -> Result + username: String, + context: &C) -> Result { - info!("logout_user() - X-Span-ID: {:?}", context.get().0.clone()); + info!("get_user_by_name(\"{}\") - X-Span-ID: {:?}", username, context.get().0.clone()); Err(ApiError("Api-Error: Operation is NOT implemented".into())) } diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server/server_auth.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server/server_auth.rs index f5133036d31a..ec3b16b195d6 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server/server_auth.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/examples/server/server_auth.rs @@ -1,8 +1,8 @@ use swagger::{ ApiError, - auth::{Basic, Bearer}, - Has, + Has, XSpanIdString}; +use headers::authorization::{Basic, Bearer}; use petstore_with_fake_endpoints_models_for_testing::{AuthenticationApi, Claims}; use crate::server::Server; use jsonwebtoken::{decode, errors as JwtError, decode_header, DecodingKey, TokenData, Validation}; @@ -15,26 +15,27 @@ use log::{error, debug}; /// Get a dummy claim with full permissions (all scopes) for testing purposes fn full_permission_claim() -> Claims { - Claims { - sub: "tester@acme.com".to_owned(), - company: "ACME".to_owned(), - iss: "mini-bank-IDP".to_owned(), - aud: "org.acme.Resource_Server".to_string(), - // added a very long expiry time - exp: 10000000000, - // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ - "write:pets", - "read:pets", - ].join(", ") - } + // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. + Claims { + sub: "tester@acme.com".to_owned(), + company: "ACME".to_owned(), + iss: "mini-bank-IDP".to_owned(), + aud: "org.acme.Resource_Server".to_string(), + // added a very long expiry time + exp: 10000000000, + scopes: + [ + "write:pets", + "read:pets", + ].join::<&str>(", ") + } } -/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. +/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. fn extract_token_data(token: &str, key: &[u8]) -> Result, JwtError::Error> { - + // Ensure that you set the correct algorithm and correct key. // See https://github.com/Keats/jsonwebtoken for more information. let header = decode_header(token)?; @@ -65,8 +66,8 @@ fn build_authorization(claims: Claims) -> Authorization { let scopes = swagger::auth::Scopes::Some(scopes); Authorization{ - subject: claims.sub, - scopes, + subject: claims.sub, + scopes, issuer: Some(claims.iss)} } @@ -89,7 +90,7 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn bearer_authorization(&self, bearer: &Bearer) -> Result { debug!("\tAuthorizationApi: Received Bearer-token, {bearer:#?}"); - match extract_token_data(&bearer.token, b"secret") { + match extract_token_data(&bearer.token(), b"secret") { Ok(auth_data) => { debug!("\tUnpack auth_data as: {auth_data:#?}"); let authorization = build_authorization(auth_data.claims); @@ -107,23 +108,22 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn apikey_authorization(&self, api_key: &str) -> Result { debug!("\tAuthorizationApi: Received api-key, {api_key:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } - + /// Implementation of the method to map a basic authentication (username and password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result { debug!("\tAuthorizationApi: Received Basic-token, {basic:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } -} - +} diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/auth.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/auth.rs index cbaba3dca7c6..a6a39f79450f 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/auth.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/auth.rs @@ -1,8 +1,7 @@ use std::collections::BTreeSet; -use crate::server::Authorization; use serde::{Deserialize, Serialize}; -use swagger::{ApiError, auth::{Basic, Bearer}}; - +use swagger::{ApiError, auth::Authorization}; +use headers::authorization::{Basic, Bearer}; #[derive(Debug, Serialize, Deserialize)] pub struct Claims { pub sub: String, @@ -24,7 +23,7 @@ pub trait AuthenticationApi { /// Method should be implemented (see example-code) to map Basic (Username:password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result; -} +} // Implement it for AllowAllAuthenticator (dummy is needed, but should not used as we have Bearer authorization) use swagger::auth::{AllowAllAuthenticator, RcBound, Scopes}; @@ -34,7 +33,7 @@ fn dummy_authorization() -> Authorization { // However, if you want to use it anyway this can not be unimplemented, so dummy implementation added. // unimplemented!() Authorization{ - subject: "Dummmy".to_owned(), + subject: "Dummy".to_owned(), scopes: Scopes::Some(BTreeSet::new()), // create an empty scope, as this should not be used issuer: None } diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/client/mod.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/client/mod.rs index 625e7aea9fa3..10886d73eed7 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/client/mod.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/client/mod.rs @@ -1,10 +1,12 @@ use async_trait::async_trait; +use bytes::Bytes; use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt}; +use http_body_util::{combinators::BoxBody, Full}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; -use hyper::{Body, Request, Response, service::Service, Uri}; +use hyper::{body::{Body, Incoming}, Request, Response, service::Service, Uri}; use percent_encoding::{utf8_percent_encode, AsciiSet}; use std::borrow::Cow; -use std::convert::TryInto; +use std::convert::{TryInto, Infallible}; use std::io::{ErrorKind, Read}; use std::error::Error; use std::future::Future; @@ -18,6 +20,7 @@ use std::string::ToString; use std::task::{Context, Poll}; use swagger::{ApiError, AuthData, BodyExt, Connector, DropContextService, Has, XSpanIdString}; use url::form_urlencoded; +use tower_service::Service as _; use mime::Mime; use std::io::Cursor; @@ -46,33 +49,33 @@ use crate::{Api, FakeOuterNumberSerializeResponse, FakeOuterStringSerializeResponse, FakeResponseWithNumericalDescriptionResponse, - HyphenParamResponse, TestBodyWithQueryParamsResponse, TestClientModelResponse, TestEndpointParametersResponse, TestEnumParametersResponse, TestInlineAdditionalPropertiesResponse, TestJsonFormDataResponse, + HyphenParamResponse, TestClassnameResponse, AddPetResponse, - DeletePetResponse, FindPetsByStatusResponse, FindPetsByTagsResponse, - GetPetByIdResponse, UpdatePetResponse, + DeletePetResponse, + GetPetByIdResponse, UpdatePetWithFormResponse, UploadFileResponse, - DeleteOrderResponse, GetInventoryResponse, - GetOrderByIdResponse, PlaceOrderResponse, + DeleteOrderResponse, + GetOrderByIdResponse, CreateUserResponse, CreateUsersWithArrayInputResponse, CreateUsersWithListInputResponse, - DeleteUserResponse, - GetUserByNameResponse, LoginUserResponse, LogoutUserResponse, + DeleteUserResponse, + GetUserByNameResponse, UpdateUserResponse }; @@ -91,15 +94,14 @@ fn into_base_path(input: impl TryInto, } let host = uri.host().ok_or(ClientInitError::MissingHost)?; - let port = uri.port_u16().map(|x| format!(":{}", x)).unwrap_or_default(); - Ok(format!("{}://{}{}{}", scheme, host, port, uri.path().trim_end_matches('/'))) + let port = uri.port_u16().map(|x| format!(":{x}")).unwrap_or_default(); + Ok(format!("{scheme}://{host}{port}{}", uri.path().trim_end_matches('/'))) } /// A client that implements the API by making HTTP calls out to a server. pub struct Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -116,8 +118,7 @@ pub struct Client where impl fmt::Debug for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -129,8 +130,7 @@ impl fmt::Debug for Client where impl Clone for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -144,8 +144,19 @@ impl Clone for Client where } } -impl Client, C>, C> where - Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static, +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + Connector, + BoxBody + > + >, + C + >, + C +> where + Connector: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static, C: Clone + Send + Sync + 'static, { /// Create a client with a custom implementation of hyper::client::Connect. @@ -159,7 +170,7 @@ impl Client" /// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")` /// * `connector` - Implementation of `hyper::client::Connect` to use for the client pub fn try_new_with_connector( @@ -168,8 +179,8 @@ impl Client Result { - let client_service = hyper::client::Client::builder().build(connector); - let client_service = DropContextService::new(client_service); + let client_service = hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector); + let client_service = DropContextService::new(hyper_util::service::TowerToHyperService::new(client_service)); Ok(Self { client_service, @@ -179,28 +190,29 @@ impl Client; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HyperHttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + #[derive(Debug, Clone)] pub enum HyperClient { - Http(hyper::client::Client), - Https(hyper::client::Client), + Http(hyper_util::client::legacy::Client>), + #[cfg(feature = "client-tls")] + Https(hyper_util::client::legacy::Client>), } -impl Service> for HyperClient { - type Response = Response; - type Error = hyper::Error; - type Future = hyper::client::ResponseFuture; - - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - match self { - HyperClient::Http(client) => client.poll_ready(cx), - HyperClient::Https(client) => client.poll_ready(cx), - } - } +impl Service>> for HyperClient { + type Response = Response; + type Error = hyper_util::client::legacy::Error; + type Future = hyper_util::client::legacy::ResponseFuture; - fn call(&mut self, req: Request) -> Self::Future { + fn call(&self, req: Request>) -> Self::Future { match self { - HyperClient::Http(client) => client.call(req), - HyperClient::Https(client) => client.call(req) + HyperClient::Http(client) => client.request(req), + #[cfg(feature = "client-tls")] + HyperClient::Https(client) => client.request(req), } } } @@ -211,7 +223,7 @@ impl Client, C> where /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new( base_path: &str, ) -> Result { @@ -224,13 +236,19 @@ impl Client, C> where let client_service = match scheme.as_str() { "http" => { - HyperClient::Http(hyper::client::Client::builder().build(connector.build())) + HyperClient::Http(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector.build())) + }, + #[cfg(feature = "client-tls")] + "https" => { + let https_connector = connector + .https() + .build() + .map_err(ClientInitError::SslError)?; + HyperClient::Https(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(https_connector)) }, + #[cfg(not(feature = "client-tls"))] "https" => { - let connector = connector.https() - .build() - .map_err(ClientInitError::SslError)?; - HyperClient::Https(hyper::client::Client::builder().build(connector)) + return Err(ClientInitError::TlsNotEnabled); }, _ => { return Err(ClientInitError::InvalidScheme); @@ -247,13 +265,24 @@ impl Client, C> where } } -impl Client, C>, C> where +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + hyper_util::client::legacy::connect::HttpConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new_http( base_path: &str, ) -> Result { @@ -263,19 +292,46 @@ impl Client; - -#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] -type HttpsConnector = hyper_openssl::HttpsConnector; - -impl Client, C>, C> where +#[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] +type HttpsConnector = hyper_tls::HttpsConnector; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + +#[cfg(feature = "client-tls")] +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + HttpsConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { - /// Create a client with a TLS connection to the server + /// Create a client with a TLS connection to the server. + /// + /// # Arguments + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + pub fn try_new_https(base_path: &str) -> Result + { + let https_connector = Connector::builder() + .https() + .build() + .map_err(ClientInitError::SslError)?; + Self::try_new_with_connector(base_path, Some("https"), https_connector) + } + + /// Create a client with a TLS connection to the server using OpenSSL via swagger. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn try_new_https(base_path: &str) -> Result { let https_connector = Connector::builder() @@ -285,10 +341,10 @@ impl Client, C Self::try_new_with_connector(base_path, Some("https"), https_connector) } - /// Create a client with a TLS connection to the server using a pinned certificate + /// Create a client with a TLS connection to the server using a pinned certificate. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn try_new_https_pinned( @@ -309,7 +365,7 @@ impl Client, C /// Create a client with a mutually authenticated TLS connection to the server. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server /// * `client_key` - Path to the client private key /// * `client_certificate` - Path to the client's public certificate associated with the private key @@ -337,8 +393,7 @@ impl Client, C impl Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -372,12 +427,15 @@ pub enum ClientInitError { /// Missing Hostname MissingHost, + /// HTTPS requested but TLS features not enabled + TlsNotEnabled, + /// SSL Connection Error - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + #[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] SslError(native_tls::Error), /// SSL Connection Error - #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] SslError(openssl::error::ErrorStack), } @@ -400,29 +458,32 @@ impl Error for ClientInitError { } } +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + #[async_trait] -impl Api for Client where +impl Api for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C), + Response=Response> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Has + Has> + Clone + Send + Sync + 'static, + B: hyper::body::Body + Send + 'static + Unpin, + B::Data: Send, + B::Error: Into>, { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - match self.client_service.clone().poll_ready(cx) { - Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())), - Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)), - Poll::Pending => Poll::Pending, - } - } + #[allow(clippy::vec_init_then_push)] async fn test_special_tags( &self, param_body: models::Client, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/another-fake/dummy", self.base_path @@ -440,77 +501,77 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("PATCH") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body // Body parameter let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(TestSpecialTagsResponse::SuccessfulOperation (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn call123example( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/fake/operation-with-numeric-id", self.base_path @@ -528,25 +589,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -556,30 +617,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn fake_outer_boolean_serialize( &self, param_body: Option, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/fake/outer/boolean", self.base_path @@ -597,79 +658,80 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let body = param_body.map(|ref body| { - serde_json::to_string(body).expect("impossible to fail to serialize") - }); - if let Some(body) = body { - *request.body_mut() = Body::from(body); + // Consumes basic body + // Body parameter + if let Some(param_body) = param_body { + let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); + *request.body_mut() = body_from_string(body); } let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(FakeOuterBooleanSerializeResponse::OutputBoolean (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn fake_outer_composite_serialize( &self, param_body: Option, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/fake/outer/composite", self.base_path @@ -687,79 +749,80 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let body = param_body.map(|ref body| { - serde_json::to_string(body).expect("impossible to fail to serialize") - }); - if let Some(body) = body { - *request.body_mut() = Body::from(body); + // Consumes basic body + // Body parameter + if let Some(param_body) = param_body { + let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); + *request.body_mut() = body_from_string(body); } let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(FakeOuterCompositeSerializeResponse::OutputComposite (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn fake_outer_number_serialize( &self, param_body: Option, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/fake/outer/number", self.base_path @@ -777,79 +840,80 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let body = param_body.map(|ref body| { - serde_json::to_string(body).expect("impossible to fail to serialize") - }); - if let Some(body) = body { - *request.body_mut() = Body::from(body); + // Consumes basic body + // Body parameter + if let Some(param_body) = param_body { + let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); + *request.body_mut() = body_from_string(body); } let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(FakeOuterNumberSerializeResponse::OutputNumber (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn fake_outer_string_serialize( &self, param_body: Option, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/fake/outer/string", self.base_path @@ -867,78 +931,79 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let body = param_body.map(|ref body| { - serde_json::to_string(body).expect("impossible to fail to serialize") - }); - if let Some(body) = body { - *request.body_mut() = Body::from(body); + // Consumes basic body + // Body parameter + if let Some(param_body) = param_body { + let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); + *request.body_mut() = body_from_string(body); } let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(FakeOuterStringSerializeResponse::OutputString (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn fake_response_with_numerical_description( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/fake/response-with-numerical-description", self.base_path @@ -956,25 +1021,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -984,94 +1049,23 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, - match body { - Ok(body) => match String::from_utf8(body) { - Ok(body) => body, - Err(e) => format!("", e), - }, - Err(e) => format!("", e), - } - ))) - } - } - } - - async fn hyphen_param( - &self, - param_hyphen_param: String, - context: &C) -> Result - { - let mut client_service = self.client_service.clone(); - let mut uri = format!( - "{}/v2/fake/hyphenParam/{hyphen_param}", - self.base_path - ,hyphen_param=utf8_percent_encode(¶m_hyphen_param.to_string(), ID_ENCODE_SET) - ); - - // Query parameters - let query_string = { - let mut query_string = form_urlencoded::Serializer::new("".to_owned()); - query_string.finish() - }; - if !query_string.is_empty() { - uri += "?"; - uri += &query_string; - } - - let uri = match Uri::from_str(&uri) { - Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), - }; - - let mut request = match Request::builder() - .method("GET") - .uri(uri) - .body(Body::empty()) { - Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) - }; - - let header = HeaderValue::from_str(Has::::get(context).0.as_str()); - request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) - }); - - let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; - - match response.status().as_u16() { - 200 => { - Ok( - HyphenParamResponse::Success - ) - } - code => { - let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn test_body_with_query_params( &self, param_query: String, @@ -1079,6 +1073,7 @@ impl Api for Client where context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/fake/body-with-query-params", self.base_path @@ -1098,33 +1093,33 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("PUT") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body + // Body parameter let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1134,30 +1129,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn test_client_model( &self, param_body: models::Client, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/fake", self.base_path @@ -1175,77 +1170,79 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("PATCH") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body + // Body parameter let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(TestClientModelResponse::SuccessfulOperation (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn test_endpoint_parameters( &self, param_number: f64, param_double: f64, param_pattern_without_delimiter: String, param_byte: swagger::ByteArray, - param_integer: Option, - param_int32: Option, + param_integer: Option, + param_int32: Option, param_int64: Option, param_float: Option, param_string: Option, @@ -1257,6 +1254,7 @@ impl Api for Client where context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/fake", self.base_path @@ -1274,68 +1272,126 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) - }; - - let params = &[ - ("integer", param_integer.map(|param| format!("{:?}", param))), - ("int32", param_int32.map(|param| format!("{:?}", param))), - ("int64", param_int64.map(|param| format!("{:?}", param))), - ("number", Some(format!("{:?}", param_number))), - ("float", param_float.map(|param| format!("{:?}", param))), - ("double", Some(format!("{:?}", param_double))), - ("string", param_string), - ("pattern_without_delimiter", Some(param_pattern_without_delimiter)), - ("byte", Some(format!("{:?}", param_byte))), - ("binary", param_binary.map(|param| format!("{:?}", param))), - ("date", param_date.map(|param| format!("{:?}", param))), - ("dateTime", param_date_time.map(|param| format!("{:?}", param))), - ("password", param_password), - ("callback", param_callback), - ]; + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) + }; + + // Consumes form body + let mut params = vec![]; + if let Some(param_integer) = param_integer { + #[allow(clippy::uninlined_format_args)] + params.push(("integer", + format!("{:?}", param_integer) + )); + } + if let Some(param_int32) = param_int32 { + #[allow(clippy::uninlined_format_args)] + params.push(("int32", + format!("{:?}", param_int32) + )); + } + if let Some(param_int64) = param_int64 { + #[allow(clippy::uninlined_format_args)] + params.push(("int64", + format!("{:?}", param_int64) + )); + } + #[allow(clippy::uninlined_format_args)] + params.push(("number", + format!("{}", param_number) + )); + if let Some(param_float) = param_float { + #[allow(clippy::uninlined_format_args)] + params.push(("float", + format!("{:?}", param_float) + )); + } + #[allow(clippy::uninlined_format_args)] + params.push(("double", + format!("{}", param_double) + )); + if let Some(param_string) = param_string { + #[allow(clippy::uninlined_format_args)] + params.push(("string", + param_string + )); + } + #[allow(clippy::uninlined_format_args)] + params.push(("pattern_without_delimiter", + param_pattern_without_delimiter + )); + #[allow(clippy::uninlined_format_args)] + params.push(("byte", + format!("{:?}", param_byte) + )); + if let Some(param_binary) = param_binary { + #[allow(clippy::uninlined_format_args)] + params.push(("binary", + format!("{:?}", param_binary) + )); + } + if let Some(param_date) = param_date { + #[allow(clippy::uninlined_format_args)] + params.push(("date", + format!("{:?}", param_date) + )); + } + if let Some(param_date_time) = param_date_time { + #[allow(clippy::uninlined_format_args)] + params.push(("dateTime", + format!("{:?}", param_date_time) + )); + } + if let Some(param_password) = param_password { + #[allow(clippy::uninlined_format_args)] + params.push(("password", + param_password + )); + } + if let Some(param_callback) = param_callback { + #[allow(clippy::uninlined_format_args)] + params.push(("callback", + param_callback + )); + } + let body = serde_urlencoded::to_string(params).expect("impossible to fail to serialize"); + *request.body_mut() = body_from_string(body); + let header = "application/x-www-form-urlencoded"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); - *request.body_mut() = Body::from(body.into_bytes()); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); #[allow(clippy::collapsible_match)] if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported + use headers::authorization::Credentials; #[allow(clippy::single_match, clippy::match_single_binding)] match auth_data { - AuthData::Basic(basic_header) => { - let auth = swagger::auth::Header(basic_header.clone()); - let header = match HeaderValue::from_str(&format!("{}", auth)) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e))) - }; + AuthData::Basic(ref basic_user, ref basic_password) => { + let auth = headers::Authorization::basic(basic_user.as_str(), basic_password.as_str()); request.headers_mut().insert( hyper::header::AUTHORIZATION, - header); + auth.0.encode()); }, _ => {} } } let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 400 => { @@ -1350,36 +1406,36 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn test_enum_parameters( + #[allow(clippy::vec_init_then_push)] + async fn test_enum_parameters<'a>( &self, - param_enum_header_string_array: Option<&Vec>, - param_enum_header_string: Option, - param_enum_query_string_array: Option<&Vec>, - param_enum_query_string: Option, - param_enum_query_integer: Option, - param_enum_query_double: Option, - param_enum_form_string: Option, + param_enum_header_string_array: Option<&'a Vec>, + param_enum_header_string: Option, + param_enum_query_string_array: Option<&'a Vec>, + param_enum_query_string: Option, + param_enum_query_integer: Option, + param_enum_query_double: Option, + param_enum_form_string: Option, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/fake", self.base_path @@ -1394,7 +1450,7 @@ impl Api for Client where } if let Some(param_enum_query_string) = param_enum_query_string { query_string.append_pair("enum_query_string", - ¶m_enum_query_string); + ¶m_enum_query_string.to_string()); } if let Some(param_enum_query_integer) = param_enum_query_integer { query_string.append_pair("enum_query_integer", @@ -1413,32 +1469,37 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let params = &[ - ("enum_form_string", param_enum_form_string), - ]; + // Consumes form body + let mut params = vec![]; + if let Some(param_enum_form_string) = param_enum_form_string { + #[allow(clippy::uninlined_format_args)] + params.push(("enum_form_string", + format!("{:?}", param_enum_form_string) + )); + } + let body = serde_urlencoded::to_string(params).expect("impossible to fail to serialize"); + *request.body_mut() = body_from_string(body); + let header = "application/x-www-form-urlencoded"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); - *request.body_mut() = Body::from(body.into_bytes()); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); // Header parameters @@ -1447,12 +1508,12 @@ impl Api for Client where Some(param_enum_header_string_array) => { request.headers_mut().append( HeaderName::from_static("enum_header_string_array"), - #[allow(clippy::redundant_clone)] + #[allow(clippy::redundant_clone, clippy::clone_on_copy)] match header::IntoHeaderValue(param_enum_header_string_array.clone()).try_into() { Ok(header) => header, Err(e) => { return Err(ApiError(format!( - "Invalid header enum_header_string_array - {}", e))); + "Invalid header enum_header_string_array - {e}"))); }, }); }, @@ -1464,12 +1525,12 @@ impl Api for Client where Some(param_enum_header_string) => { request.headers_mut().append( HeaderName::from_static("enum_header_string"), - #[allow(clippy::redundant_clone)] + #[allow(clippy::redundant_clone, clippy::clone_on_copy)] match header::IntoHeaderValue(param_enum_header_string.clone()).try_into() { Ok(header) => header, Err(e) => { return Err(ApiError(format!( - "Invalid header enum_header_string - {}", e))); + "Invalid header enum_header_string - {e}"))); }, }); }, @@ -1477,7 +1538,7 @@ impl Api for Client where } let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 400 => { @@ -1492,30 +1553,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn test_inline_additional_properties( &self, param_param: std::collections::HashMap, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/fake/inline-additionalProperties", self.base_path @@ -1533,33 +1594,33 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body + // Body parameter let body = serde_json::to_string(¶m_param).expect("impossible to fail to serialize"); - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -1569,24 +1630,23 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn test_json_form_data( &self, param_param: String, @@ -1594,6 +1654,7 @@ impl Api for Client where context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/fake/jsonFormData", self.base_path @@ -1611,70 +1672,146 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let params = &[ - ("param", Some(param_param)), - ("param2", Some(param_param2)), - ]; + // Consumes form body + let mut params = vec![]; + #[allow(clippy::uninlined_format_args)] + params.push(("param", + param_param + )); + #[allow(clippy::uninlined_format_args)] + params.push(("param2", + param_param2 + )); + let body = serde_urlencoded::to_string(params).expect("impossible to fail to serialize"); + *request.body_mut() = body_from_string(body); + let header = "application/x-www-form-urlencoded"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); + request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); - *request.body_mut() = Body::from(body.into_bytes()); + + let response = client_service.call((request, context.clone())) + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; + + match response.status().as_u16() { + 200 => { + Ok( + TestJsonFormDataResponse::SuccessfulOperation + ) + } + code => { + let headers = response.headers().clone(); + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", + match body { + Ok(body) => match String::from_utf8(body) { + Ok(body) => body, + Err(e) => format!(""), + }, + Err(e) => format!("", Into::::into(e)), + } + ))) + } + } + } + + #[allow(clippy::vec_init_then_push)] + async fn hyphen_param( + &self, + param_hyphen_param: String, + context: &C) -> Result + { + let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] + let mut uri = format!( + "{}/v2/fake/hyphenParam/{hyphen_param}", + self.base_path + ,hyphen_param=utf8_percent_encode(¶m_hyphen_param.to_string(), ID_ENCODE_SET) + ); + + // Query parameters + let query_string = { + let mut query_string = form_urlencoded::Serializer::new("".to_owned()); + query_string.finish() + }; + if !query_string.is_empty() { + uri += "?"; + uri += &query_string; + } + + let uri = match Uri::from_str(&uri) { + Ok(uri) => uri, + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), + }; + + let mut request = match Request::builder() + .method("GET") + .uri(uri) + .body(BoxBody::new(http_body_util::Empty::new())) { + Ok(req) => req, + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) + }; + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { Ok( - TestJsonFormDataResponse::SuccessfulOperation + HyphenParamResponse::Success ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn test_classname( &self, param_body: models::Client, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/fake_classname_test", self.base_path @@ -1695,37 +1832,34 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("PATCH") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body // Body parameter let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); #[allow(clippy::collapsible_match)] if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported + use headers::authorization::Credentials; #[allow(clippy::single_match, clippy::match_single_binding)] match auth_data { _ => {} @@ -1733,49 +1867,52 @@ impl Api for Client where } let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(TestClassnameResponse::SuccessfulOperation (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn add_pet( &self, param_body: models::Pet, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/pet", self.base_path @@ -1793,53 +1930,51 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body // Body parameter let body = param_body.as_xml(); - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); #[allow(clippy::collapsible_match)] if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported + use headers::authorization::Credentials; #[allow(clippy::single_match, clippy::match_single_binding)] match auth_data { - AuthData::Bearer(bearer_header) => { - let auth = swagger::auth::Header(bearer_header.clone()); - let header = match HeaderValue::from_str(&format!("{}", auth)) { + AuthData::Bearer(ref bearer_header) => { + let header = match headers::Authorization::bearer(&bearer_header.to_string()) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {e}"))) }; request.headers_mut().insert( hyper::header::AUTHORIZATION, - header); + header.0.encode()); }, _ => {} } } let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 405 => { @@ -1849,40 +1984,40 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn delete_pet( + #[allow(clippy::vec_init_then_push)] + async fn find_pets_by_status<'a>( &self, - param_pet_id: i64, - param_api_key: Option, - context: &C) -> Result + param_status: &'a Vec, + context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( - "{}/v2/pet/{pet_id}", + "{}/v2/pet/findByStatus", self.base_path - ,pet_id=utf8_percent_encode(¶m_pet_id.to_string(), ID_ENCODE_SET) ); // Query parameters let query_string = { let mut query_string = form_urlencoded::Serializer::new("".to_owned()); + query_string.append_pair("status", + ¶m_status.iter().map(ToString::to_string).collect::>().join(",")); query_string.finish() }; if !query_string.is_empty() { @@ -1892,105 +2027,105 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() - .method("DELETE") + .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); #[allow(clippy::collapsible_match)] if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported + use headers::authorization::Credentials; #[allow(clippy::single_match, clippy::match_single_binding)] match auth_data { - AuthData::Bearer(bearer_header) => { - let auth = swagger::auth::Header(bearer_header.clone()); - let header = match HeaderValue::from_str(&format!("{}", auth)) { + AuthData::Bearer(ref bearer_header) => { + let header = match headers::Authorization::bearer(&bearer_header.to_string()) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {e}"))) }; request.headers_mut().insert( hyper::header::AUTHORIZATION, - header); + header.0.encode()); }, _ => {} } } - // Header parameters - #[allow(clippy::single_match)] - match param_api_key { - Some(param_api_key) => { - request.headers_mut().append( - HeaderName::from_static("api_key"), - #[allow(clippy::redundant_clone)] - match header::IntoHeaderValue(param_api_key.clone()).try_into() { - Ok(header) => header, - Err(e) => { - return Err(ApiError(format!( - "Invalid header api_key - {}", e))); - }, - }); - }, - None => {} - } - let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { + 200 => { + let body = response.into_body(); + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + + let body = str::from_utf8(&body) + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + // ToDo: this will move to swagger-rs and become a standard From conversion trait + // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream + let body = serde_xml_rs::from_str::>(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + + Ok(FindPetsByStatusResponse::SuccessfulOperation + (body) + ) + } 400 => { Ok( - DeletePetResponse::InvalidPetValue + FindPetsByStatusResponse::InvalidStatusValue ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn find_pets_by_status( + #[allow(clippy::vec_init_then_push)] + async fn find_pets_by_tags<'a>( &self, - param_status: &Vec, - context: &C) -> Result + param_tags: &'a Vec, + context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( - "{}/v2/pet/findByStatus", + "{}/v2/pet/findByTags", self.base_path ); // Query parameters let query_string = { let mut query_string = form_urlencoded::Serializer::new("".to_owned()); - query_string.append_pair("status", - ¶m_status.iter().map(ToString::to_string).collect::>().join(",")); + query_string.append_pair("tags", + ¶m_tags.iter().map(ToString::to_string).collect::>().join(",")); query_string.finish() }; if !query_string.is_empty() { @@ -2000,102 +2135,103 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); #[allow(clippy::collapsible_match)] if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported + use headers::authorization::Credentials; #[allow(clippy::single_match, clippy::match_single_binding)] match auth_data { - AuthData::Bearer(bearer_header) => { - let auth = swagger::auth::Header(bearer_header.clone()); - let header = match HeaderValue::from_str(&format!("{}", auth)) { + AuthData::Bearer(ref bearer_header) => { + let header = match headers::Authorization::bearer(&bearer_header.to_string()) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {e}"))) }; request.headers_mut().insert( hyper::header::AUTHORIZATION, - header); + header.0.encode()); }, _ => {} } } let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; // ToDo: this will move to swagger-rs and become a standard From conversion trait // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream let body = serde_xml_rs::from_str::>(body) - .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?; - Ok(FindPetsByStatusResponse::SuccessfulOperation + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + + Ok(FindPetsByTagsResponse::SuccessfulOperation (body) ) } 400 => { Ok( - FindPetsByStatusResponse::InvalidStatusValue + FindPetsByTagsResponse::InvalidTagValue ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn find_pets_by_tags( + #[allow(clippy::vec_init_then_push)] + async fn update_pet( &self, - param_tags: &Vec, - context: &C) -> Result + param_body: models::Pet, + context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( - "{}/v2/pet/findByTags", + "{}/v2/pet", self.base_path ); // Query parameters let query_string = { let mut query_string = form_urlencoded::Serializer::new("".to_owned()); - query_string.append_pair("tags", - ¶m_tags.iter().map(ToString::to_string).collect::>().join(",")); query_string.finish() }; if !query_string.is_empty() { @@ -2105,92 +2241,95 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() - .method("GET") + .method("PUT") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body + // Body parameter + let body = param_body.as_xml(); + *request.body_mut() = body_from_string(body); + + let header = "application/json"; + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); #[allow(clippy::collapsible_match)] if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported + use headers::authorization::Credentials; #[allow(clippy::single_match, clippy::match_single_binding)] match auth_data { - AuthData::Bearer(bearer_header) => { - let auth = swagger::auth::Header(bearer_header.clone()); - let header = match HeaderValue::from_str(&format!("{}", auth)) { + AuthData::Bearer(ref bearer_header) => { + let header = match headers::Authorization::bearer(&bearer_header.to_string()) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {e}"))) }; request.headers_mut().insert( hyper::header::AUTHORIZATION, - header); + header.0.encode()); }, _ => {} } } let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { - 200 => { - let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; - let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - // ToDo: this will move to swagger-rs and become a standard From conversion trait - // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream - let body = serde_xml_rs::from_str::>(body) - .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?; - Ok(FindPetsByTagsResponse::SuccessfulOperation - (body) + 400 => { + Ok( + UpdatePetResponse::InvalidIDSupplied ) } - 400 => { + 404 => { Ok( - FindPetsByTagsResponse::InvalidTagValue + UpdatePetResponse::PetNotFound + ) + } + 405 => { + Ok( + UpdatePetResponse::ValidationException ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn get_pet_by_id( + #[allow(clippy::vec_init_then_push)] + async fn delete_pet( &self, param_pet_id: i64, - context: &C) -> Result + param_api_key: Option, + context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/pet/{pet_id}", self.base_path @@ -2209,90 +2348,98 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() - .method("GET") + .method("DELETE") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); #[allow(clippy::collapsible_match)] if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported + use headers::authorization::Credentials; #[allow(clippy::single_match, clippy::match_single_binding)] match auth_data { + AuthData::Bearer(ref bearer_header) => { + let header = match headers::Authorization::bearer(&bearer_header.to_string()) { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {e}"))) + }; + request.headers_mut().insert( + hyper::header::AUTHORIZATION, + header.0.encode()); + }, _ => {} } } + // Header parameters + #[allow(clippy::single_match)] + match param_api_key { + Some(param_api_key) => { + request.headers_mut().append( + HeaderName::from_static("api_key"), + #[allow(clippy::redundant_clone, clippy::clone_on_copy)] + match header::IntoHeaderValue(param_api_key.clone()).try_into() { + Ok(header) => header, + Err(e) => { + return Err(ApiError(format!( + "Invalid header api_key - {e}"))); + }, + }); + }, + None => {} + } + let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { - 200 => { - let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; - let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - // ToDo: this will move to swagger-rs and become a standard From conversion trait - // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream - let body = serde_xml_rs::from_str::(body) - .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?; - Ok(GetPetByIdResponse::SuccessfulOperation - (body) - ) - } 400 => { Ok( - GetPetByIdResponse::InvalidIDSupplied - ) - } - 404 => { - Ok( - GetPetByIdResponse::PetNotFound + DeletePetResponse::InvalidPetValue ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn update_pet( + #[allow(clippy::vec_init_then_push)] + async fn get_pet_by_id( &self, - param_body: models::Pet, - context: &C) -> Result + param_pet_id: i64, + context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( - "{}/v2/pet", + "{}/v2/pet/{pet_id}", self.base_path + ,pet_id=utf8_percent_encode(¶m_pet_id.to_string(), ID_ENCODE_SET) ); // Query parameters @@ -2307,44 +2454,35 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() - .method("PUT") + .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let body = param_body.as_xml(); - *request.body_mut() = Body::from(body); - - let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); #[allow(clippy::collapsible_match)] if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported + use headers::authorization::Credentials; #[allow(clippy::single_match, clippy::match_single_binding)] match auth_data { - AuthData::Bearer(bearer_header) => { - let auth = swagger::auth::Header(bearer_header.clone()); - let header = match HeaderValue::from_str(&format!("{}", auth)) { + AuthData::ApiKey(ref api_key) => { + let header = match HeaderValue::from_str(api_key.as_str()) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create header: {e}"))) }; request.headers_mut().insert( - hyper::header::AUTHORIZATION, + HeaderName::from_static("api_key"), header); }, _ => {} @@ -2352,44 +2490,57 @@ impl Api for Client where } let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { - 400 => { - Ok( - UpdatePetResponse::InvalidIDSupplied + 200 => { + let body = response.into_body(); + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + + let body = str::from_utf8(&body) + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + // ToDo: this will move to swagger-rs and become a standard From conversion trait + // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream + let body = serde_xml_rs::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + + Ok(GetPetByIdResponse::SuccessfulOperation + (body) ) } - 404 => { + 400 => { Ok( - UpdatePetResponse::PetNotFound + GetPetByIdResponse::InvalidIDSupplied ) } - 405 => { + 404 => { Ok( - UpdatePetResponse::ValidationException + GetPetByIdResponse::PetNotFound ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn update_pet_with_form( &self, param_pet_id: i64, @@ -2398,6 +2549,7 @@ impl Api for Client where context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/pet/{pet_id}", self.base_path @@ -2416,56 +2568,65 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let params = &[ - ("name", param_name), - ("status", param_status), - ]; + // Consumes form body + let mut params = vec![]; + if let Some(param_name) = param_name { + #[allow(clippy::uninlined_format_args)] + params.push(("name", + param_name + )); + } + if let Some(param_status) = param_status { + #[allow(clippy::uninlined_format_args)] + params.push(("status", + param_status + )); + } + let body = serde_urlencoded::to_string(params).expect("impossible to fail to serialize"); + *request.body_mut() = body_from_string(body); + let header = "application/x-www-form-urlencoded"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); - *request.body_mut() = Body::from(body.into_bytes()); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); #[allow(clippy::collapsible_match)] if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported + use headers::authorization::Credentials; #[allow(clippy::single_match, clippy::match_single_binding)] match auth_data { - AuthData::Bearer(bearer_header) => { - let auth = swagger::auth::Header(bearer_header.clone()); - let header = match HeaderValue::from_str(&format!("{}", auth)) { + AuthData::Bearer(ref bearer_header) => { + let header = match headers::Authorization::bearer(&bearer_header.to_string()) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {e}"))) }; request.headers_mut().insert( hyper::header::AUTHORIZATION, - header); + header.0.encode()); }, _ => {} } } let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 405 => { @@ -2475,24 +2636,23 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn upload_file( &self, param_pet_id: i64, @@ -2501,6 +2661,7 @@ impl Api for Client where context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/pet/{pet_id}/uploadImage", self.base_path @@ -2519,29 +2680,30 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let (body_string, multipart_header) = { + // Consumes multipart/form body + let (body_bytes, multipart_header) = { let mut multipart = Multipart::new(); // For each parameter, encode as appropriate and add to the multipart body as a stream. let additional_metadata_str = match serde_json::to_string(¶m_additional_metadata) { Ok(str) => str, - Err(e) => return Err(ApiError(format!("Unable to serialize additional_metadata to string: {}", e))), + Err(e) => return Err(ApiError(format!("Unable to serialize additional_metadata to string: {e}"))), }; let additional_metadata_vec = additional_metadata_str.as_bytes().to_vec(); - let additional_metadata_mime = mime_0_2::Mime::from_str("application/json").expect("impossible to fail to parse"); + let additional_metadata_mime = mime::Mime::from_str("application/json").expect("impossible to fail to parse"); let additional_metadata_cursor = Cursor::new(additional_metadata_vec); multipart.add_stream("additional_metadata", additional_metadata_cursor, None as Option<&str>, Some(additional_metadata_mime)); @@ -2549,11 +2711,11 @@ impl Api for Client where let file_str = match serde_json::to_string(¶m_file) { Ok(str) => str, - Err(e) => return Err(ApiError(format!("Unable to serialize file to string: {}", e))), + Err(e) => return Err(ApiError(format!("Unable to serialize file to string: {e}"))), }; let file_vec = file_str.as_bytes().to_vec(); - let file_mime = mime_0_2::Mime::from_str("application/json").expect("impossible to fail to parse"); + let file_mime = mime::Mime::from_str("application/json").expect("impossible to fail to parse"); let file_cursor = Cursor::new(file_vec); multipart.add_stream("file", file_cursor, None as Option<&str>, Some(file_mime)); @@ -2561,103 +2723,104 @@ impl Api for Client where let mut fields = match multipart.prepare() { Ok(fields) => fields, - Err(err) => return Err(ApiError(format!("Unable to build request: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build request: {err}"))), }; - let mut body_string = String::new(); + let mut body_bytes = Vec::new(); - match fields.read_to_string(&mut body_string) { + match fields.read_to_end(&mut body_bytes) { Ok(_) => (), - Err(err) => return Err(ApiError(format!("Unable to build body: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build body: {err}"))), } let boundary = fields.boundary(); - let multipart_header = format!("multipart/form-data;boundary={}", boundary); + let multipart_header = format!("multipart/form-data;boundary={boundary}"); - (body_string, multipart_header) - }; + (body_bytes, multipart_header) + }; - *request.body_mut() = Body::from(body_string); + *request.body_mut() = BoxBody::new(Full::new(Bytes::from(body_bytes))); request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(&multipart_header) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", multipart_header, e))) + Err(e) => return Err(ApiError(format!("Unable to create header: {multipart_header} - {e}"))) }); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); #[allow(clippy::collapsible_match)] if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported + use headers::authorization::Credentials; #[allow(clippy::single_match, clippy::match_single_binding)] match auth_data { - AuthData::Bearer(bearer_header) => { - let auth = swagger::auth::Header(bearer_header.clone()); - let header = match HeaderValue::from_str(&format!("{}", auth)) { + AuthData::Bearer(ref bearer_header) => { + let header = match headers::Authorization::bearer(&bearer_header.to_string()) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {e}"))) }; request.headers_mut().insert( hyper::header::AUTHORIZATION, - header); + header.0.encode()); }, _ => {} } } let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(UploadFileResponse::SuccessfulOperation (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn delete_order( + #[allow(clippy::vec_init_then_push)] + async fn get_inventory( &self, - param_order_id: String, - context: &C) -> Result + context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( - "{}/v2/store/order/{order_id}", + "{}/v2/store/inventory", self.base_path - ,order_id=utf8_percent_encode(¶m_order_id.to_string(), ID_ENCODE_SET) ); // Query parameters @@ -2672,64 +2835,90 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() - .method("DELETE") + .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); + #[allow(clippy::collapsible_match)] + if let Some(auth_data) = Has::>::get(context).as_ref() { + use headers::authorization::Credentials; + #[allow(clippy::single_match, clippy::match_single_binding)] + match auth_data { + AuthData::ApiKey(ref api_key) => { + let header = match HeaderValue::from_str(api_key.as_str()) { + Ok(h) => h, + Err(e) => return Err(ApiError(format!("Unable to create header: {e}"))) + }; + request.headers_mut().insert( + HeaderName::from_static("api_key"), + header); + }, + _ => {} + } + } + let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { - 400 => { - Ok( - DeleteOrderResponse::InvalidIDSupplied - ) - } - 404 => { - Ok( - DeleteOrderResponse::OrderNotFound + 200 => { + let body = response.into_body(); + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + + let body = str::from_utf8(&body) + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::>(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + + Ok(GetInventoryResponse::SuccessfulOperation + (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn get_inventory( + #[allow(clippy::vec_init_then_push)] + async fn place_order( &self, - context: &C) -> Result + param_body: models::Order, + context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( - "{}/v2/store/inventory", + "{}/v2/store/order", self.base_path ); @@ -2745,76 +2934,85 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() - .method("GET") + .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body + // Body parameter + let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); + *request.body_mut() = body_from_string(body); + + let header = "application/json"; + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); - #[allow(clippy::collapsible_match)] - if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported - #[allow(clippy::single_match, clippy::match_single_binding)] - match auth_data { - _ => {} - } - } - let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::>(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; - Ok(GetInventoryResponse::SuccessfulOperation + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + // ToDo: this will move to swagger-rs and become a standard From conversion trait + // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream + let body = serde_xml_rs::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + + Ok(PlaceOrderResponse::SuccessfulOperation (body) ) } + 400 => { + Ok( + PlaceOrderResponse::InvalidOrder + ) + } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn get_order_by_id( + #[allow(clippy::vec_init_then_push)] + async fn delete_order( &self, - param_order_id: i64, - context: &C) -> Result + param_order_id: String, + context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/store/order/{order_id}", self.base_path @@ -2833,81 +3031,67 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() - .method("GET") + .method("DELETE") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { - 200 => { - let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; - let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - // ToDo: this will move to swagger-rs and become a standard From conversion trait - // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream - let body = serde_xml_rs::from_str::(body) - .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?; - Ok(GetOrderByIdResponse::SuccessfulOperation - (body) - ) - } 400 => { Ok( - GetOrderByIdResponse::InvalidIDSupplied + DeleteOrderResponse::InvalidIDSupplied ) } 404 => { Ok( - GetOrderByIdResponse::OrderNotFound + DeleteOrderResponse::OrderNotFound ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn place_order( + #[allow(clippy::vec_init_then_push)] + async fn get_order_by_id( &self, - param_body: models::Order, - context: &C) -> Result + param_order_id: u64, + context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( - "{}/v2/store/order", + "{}/v2/store/order/{order_id}", self.base_path + ,order_id=utf8_percent_encode(¶m_order_id.to_string(), ID_ENCODE_SET) ); // Query parameters @@ -2922,83 +3106,82 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() - .method("POST") + .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; - let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - - *request.body_mut() = Body::from(body); - - let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); - let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; // ToDo: this will move to swagger-rs and become a standard From conversion trait // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream let body = serde_xml_rs::from_str::(body) - .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?; - Ok(PlaceOrderResponse::SuccessfulOperation + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + + Ok(GetOrderByIdResponse::SuccessfulOperation (body) ) } 400 => { Ok( - PlaceOrderResponse::InvalidOrder + GetOrderByIdResponse::InvalidIDSupplied + ) + } + 404 => { + Ok( + GetOrderByIdResponse::OrderNotFound ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn create_user( &self, param_body: models::User, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/user", self.base_path @@ -3016,34 +3199,33 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body // Body parameter let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 0 => { @@ -3053,30 +3235,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn create_users_with_array_input( + #[allow(clippy::vec_init_then_push)] + async fn create_users_with_array_input<'a>( &self, - param_body: &Vec, + param_body: &'a Vec, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/user/createWithArray", self.base_path @@ -3094,33 +3276,33 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body + // Body parameter let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 0 => { @@ -3130,30 +3312,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn create_users_with_list_input( + #[allow(clippy::vec_init_then_push)] + async fn create_users_with_list_input<'a>( &self, - param_body: &Vec, + param_body: &'a Vec, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/user/createWithList", self.base_path @@ -3171,33 +3353,33 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body + // Body parameter let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 0 => { @@ -3207,39 +3389,43 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn delete_user( + #[allow(clippy::vec_init_then_push)] + async fn login_user( &self, param_username: String, - context: &C) -> Result + param_password: String, + context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( - "{}/v2/user/{username}", + "{}/v2/user/login", self.base_path - ,username=utf8_percent_encode(¶m_username.to_string(), ID_ENCODE_SET) ); // Query parameters let query_string = { let mut query_string = form_urlencoded::Serializer::new("".to_owned()); + query_string.append_pair("username", + ¶m_username); + query_string.append_pair("password", + ¶m_password); query_string.finish() }; if !query_string.is_empty() { @@ -3249,67 +3435,111 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() - .method("DELETE") + .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { - 400 => { - Ok( - DeleteUserResponse::InvalidUsernameSupplied + 200 => { + let response_x_rate_limit = match response.headers().get(HeaderName::from_static("x-rate-limit")) { + Some(response_x_rate_limit) => { + let response_x_rate_limit = response_x_rate_limit.clone(); + let response_x_rate_limit = match TryInto::>::try_into(response_x_rate_limit) { + Ok(value) => value, + Err(e) => { + return Err(ApiError(format!("Invalid response header X-Rate-Limit for response 200 - {e}"))); + }, + }; + Some(response_x_rate_limit.0) + }, + None => None, + }; + + let response_x_expires_after = match response.headers().get(HeaderName::from_static("x-expires-after")) { + Some(response_x_expires_after) => { + let response_x_expires_after = response_x_expires_after.clone(); + let response_x_expires_after = match TryInto::>>::try_into(response_x_expires_after) { + Ok(value) => value, + Err(e) => { + return Err(ApiError(format!("Invalid response header X-Expires-After for response 200 - {e}"))); + }, + }; + Some(response_x_expires_after.0) + }, + None => None, + }; + + let body = response.into_body(); + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + + let body = str::from_utf8(&body) + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + // ToDo: this will move to swagger-rs and become a standard From conversion trait + // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream + let body = serde_xml_rs::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + + Ok(LoginUserResponse::SuccessfulOperation + { + body, + x_rate_limit: response_x_rate_limit, + x_expires_after: response_x_expires_after, + } ) } - 404 => { + 400 => { Ok( - DeleteUserResponse::UserNotFound + LoginUserResponse::InvalidUsername ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn get_user_by_name( + #[allow(clippy::vec_init_then_push)] + async fn logout_user( &self, - param_username: String, - context: &C) -> Result + context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( - "{}/v2/user/{username}", + "{}/v2/user/logout", self.base_path - ,username=utf8_percent_encode(¶m_username.to_string(), ID_ENCODE_SET) ); // Query parameters @@ -3324,91 +3554,67 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { - 200 => { - let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; - let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - // ToDo: this will move to swagger-rs and become a standard From conversion trait - // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream - let body = serde_xml_rs::from_str::(body) - .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?; - Ok(GetUserByNameResponse::SuccessfulOperation - (body) - ) - } - 400 => { - Ok( - GetUserByNameResponse::InvalidUsernameSupplied - ) - } - 404 => { + 0 => { Ok( - GetUserByNameResponse::UserNotFound + LogoutUserResponse::SuccessfulOperation ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn login_user( + #[allow(clippy::vec_init_then_push)] + async fn delete_user( &self, param_username: String, - param_password: String, - context: &C) -> Result + context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( - "{}/v2/user/login", + "{}/v2/user/{username}", self.base_path + ,username=utf8_percent_encode(¶m_username.to_string(), ID_ENCODE_SET) ); // Query parameters let query_string = { let mut query_string = form_urlencoded::Serializer::new("".to_owned()); - query_string.append_pair("username", - ¶m_username); - query_string.append_pair("password", - ¶m_password); query_string.finish() }; if !query_string.is_empty() { @@ -3418,107 +3624,67 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() - .method("GET") + .method("DELETE") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { - 200 => { - let response_x_rate_limit = match response.headers().get(HeaderName::from_static("x-rate-limit")) { - Some(response_x_rate_limit) => { - let response_x_rate_limit = response_x_rate_limit.clone(); - let response_x_rate_limit = match TryInto::>::try_into(response_x_rate_limit) { - Ok(value) => value, - Err(e) => { - return Err(ApiError(format!("Invalid response header X-Rate-Limit for response 200 - {}", e))); - }, - }; - Some(response_x_rate_limit.0) - }, - None => None, - }; - - let response_x_expires_after = match response.headers().get(HeaderName::from_static("x-expires-after")) { - Some(response_x_expires_after) => { - let response_x_expires_after = response_x_expires_after.clone(); - let response_x_expires_after = match TryInto::>>::try_into(response_x_expires_after) { - Ok(value) => value, - Err(e) => { - return Err(ApiError(format!("Invalid response header X-Expires-After for response 200 - {}", e))); - }, - }; - Some(response_x_expires_after.0) - }, - None => None, - }; - - let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; - let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - // ToDo: this will move to swagger-rs and become a standard From conversion trait - // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream - let body = serde_xml_rs::from_str::(body) - .map_err(|e| ApiError(format!("Response body did not match the schema: {}", e)))?; - Ok(LoginUserResponse::SuccessfulOperation - { - body, - x_rate_limit: response_x_rate_limit, - x_expires_after: response_x_expires_after, - } + 400 => { + Ok( + DeleteUserResponse::InvalidUsernameSupplied ) } - 400 => { + 404 => { Ok( - LoginUserResponse::InvalidUsername + DeleteUserResponse::UserNotFound ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } - async fn logout_user( + #[allow(clippy::vec_init_then_push)] + async fn get_user_by_name( &self, - context: &C) -> Result + param_username: String, + context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( - "{}/v2/user/logout", + "{}/v2/user/{username}", self.base_path + ,username=utf8_percent_encode(¶m_username.to_string(), ID_ENCODE_SET) ); // Query parameters @@ -3533,52 +3699,75 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { - 0 => { + 200 => { + let body = response.into_body(); + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + + let body = str::from_utf8(&body) + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + // ToDo: this will move to swagger-rs and become a standard From conversion trait + // once https://github.com/RReverser/serde-xml-rs/pull/45 is accepted upstream + let body = serde_xml_rs::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + + Ok(GetUserByNameResponse::SuccessfulOperation + (body) + ) + } + 400 => { Ok( - LogoutUserResponse::SuccessfulOperation + GetUserByNameResponse::InvalidUsernameSupplied + ) + } + 404 => { + Ok( + GetUserByNameResponse::UserNotFound ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn update_user( &self, param_username: String, @@ -3586,6 +3775,7 @@ impl Api for Client where context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/v2/user/{username}", self.base_path @@ -3604,35 +3794,33 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("PUT") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body + // Body parameter let body = serde_json::to_string(¶m_body).expect("impossible to fail to serialize"); - - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 400 => { @@ -3647,18 +3835,16 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/context.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/context.rs index d821895b62ad..937ef9edc340 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/context.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/context.rs @@ -6,9 +6,9 @@ use std::default::Default; use std::io; use std::marker::PhantomData; use std::task::{Poll, Context}; -use swagger::auth::{AuthData, Authorization, Bearer, Scopes}; +use swagger::auth::{AuthData, Authorization, Scopes}; use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString}; -use crate::{Api, AuthenticationApi}; +use crate::Api; use log::error; pub struct MakeAddContext { @@ -16,11 +16,11 @@ pub struct MakeAddContext { marker: PhantomData, } -impl MakeAddContext +impl MakeAddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, + C: Send + 'static, { pub fn new(inner: T) -> MakeAddContext { MakeAddContext { @@ -30,27 +30,34 @@ where } } +impl Clone for MakeAddContext +where + T: Clone, +{ + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + // Make a service that adds context. -impl Service for +impl Service for MakeAddContext where Target: Send, A: Default + Push + Send, B: Push, Result = C>, - C: Push, Result = D>, - D: Send + 'static, + C: Send + 'static, T: Service + Send, T::Future: Send + 'static { type Error = T::Error; - type Response = AddContext; + type Response = AddContext; type Future = BoxFuture<'static, Result>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, target: Target) -> Self::Future { + fn call(&self, target: Target) -> Self::Future { let service = self.inner.call(target); Box::pin(async move { @@ -60,21 +67,17 @@ where } /// Middleware to add context data from the request -pub struct AddContext -where - A: Default + Push, - B: Push, Result = C>, - C: Push, Result = D> +#[derive(Debug, Clone)] +pub struct AddContext { inner: T, marker: PhantomData, } -impl AddContext +impl AddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, { pub fn new(inner: T) -> Self { AddContext { @@ -84,42 +87,26 @@ where } } -impl Service> for AddContext +impl Service> for AddContext where A: Default + Push, B: Push, Result=C>, - C: Push, Result=D>, - D: Send + 'static, - T: Service<(Request, D)> + AuthenticationApi + C: Send + 'static, + T: Service<(Request, C)> { type Error = T::Error; type Future = T::Future; type Response = T::Response; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - - fn call(&mut self, request: Request) -> Self::Future { + fn call(&self, request: Request) -> Self::Future { let context = A::default().push(XSpanIdString::get_or_generate(&request)); let headers = request.headers(); { - use swagger::auth::Bearer; + use headers::authorization::Bearer; use std::ops::Deref; - if let Some(bearer) = swagger::auth::from_headers::(headers) { - let authorization = self.inner.bearer_authorization(&bearer); - let auth_data = AuthData::Bearer(bearer); - - let context = context.push(Some(auth_data)); - let context = match authorization { - Ok(auth) => context.push(Some(auth)), - Err(err) => { - error!("Error during Authorization: {err:?}"); - context.push(None::) - } - }; + if let Some(bearer) = swagger::auth::from_headers(headers) { + let context = context.push(Some(bearer)); return self.inner.call((request, context)) } @@ -128,17 +115,8 @@ impl Service> for AddContext context.push(Some(auth)), - Err(err) => { - error!("Error during Authorization: {err:?}"); - context.push(None::) - } - }; return self.inner.call((request, context)) } @@ -149,43 +127,22 @@ impl Service> for AddContext context.push(Some(auth)), - Err(err) => { - error!("Error during Authorization: {err:?}"); - context.push(None::) - } - }; - return self.inner.call((request, context)) } } { - use swagger::auth::Basic; use std::ops::Deref; - if let Some(basic) = swagger::auth::from_headers::(headers) { - let authorization = self.inner.basic_authorization(&basic); - let auth_data = AuthData::Basic(basic); - - let context = context.push(Some(auth_data)); - let context = match authorization { - Ok(auth) => context.push(Some(auth)), - Err(err) => { - error!("Error during Authorization: {err:?}"); - context.push(None::) - } - }; + if let Some(auth) = swagger::auth::from_headers(headers) { + let context = context.push(Some(auth)); return self.inner.call((request, context)) } } let context = context.push(None::); - let context = context.push(None::); self.inner.call((request, context)) } diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/header.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/header.rs index 5bc6ebe929b9..823d2779b31f 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/header.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/header.rs @@ -31,11 +31,9 @@ macro_rules! ihv_generate { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse::<$t>() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse {} as a string: {}", - stringify!($t), e)), + Err(e) => Err(format!("Unable to parse {} as a string: {e}", stringify!($t))), }, - Err(e) => Err(format!("Unable to parse header {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header {hdr_value:?} as a string - {e}")), } } } @@ -76,8 +74,7 @@ impl TryFrom for IntoHeaderValue> { y => Some(y.to_string()), }) .collect())), - Err(e) => Err(format!("Unable to parse header: {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header: {hdr_value:?} as a string - {e}")), } } } @@ -88,8 +85,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(&hdr_value.0.join(", ")) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} into a header - {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} into a header - {e}")) } } } @@ -102,8 +98,7 @@ impl TryFrom for IntoHeaderValue { fn try_from(hdr_value: HeaderValue) -> Result { match hdr_value.to_str() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())), - Err(e) => Err(format!("Unable to convert header {:?} to {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to {e}")), } } } @@ -114,8 +109,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")) } } } @@ -128,11 +122,9 @@ impl TryFrom for IntoHeaderValue { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse bool from {} - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse bool from {hdr_value} - {e}")), }, - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")), } } } @@ -143,8 +135,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0.to_string()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert: {:?} into a header: {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert: {hdr_value:?} into a header: {e}")) } } } @@ -158,11 +149,9 @@ impl TryFrom for IntoHeaderValue> { match hdr_value.to_str() { Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) { Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))), - Err(e) => Err(format!("Unable to parse: {} as date - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse: {hdr_value} as date - {e}")), }, - Err(e) => Err(format!("Unable to convert header {:?} to string {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to string {e}")), } } } @@ -173,8 +162,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} to a header: {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} to a header: {e}")), } } } diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/lib.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/lib.rs index 1e80dc87bb74..3c409b899326 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/lib.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/lib.rs @@ -3,14 +3,15 @@ use async_trait::async_trait; use futures::Stream; +#[cfg(feature = "mock")] +use mockall::automock; use std::error::Error; use std::collections::BTreeSet; use std::task::{Poll, Context}; -use swagger::{ApiError, ContextWrapper}; +use swagger::{ApiError, ContextWrapper, auth::Authorization}; use serde::{Serialize, Deserialize}; -use crate::server::Authorization; - +#[cfg(any(feature = "client", feature = "server"))] type ServiceError = Box; pub const BASE_PATH: &str = "/v2"; @@ -67,12 +68,6 @@ pub enum FakeResponseWithNumericalDescriptionResponse { Status200 } -#[derive(Debug, PartialEq, Serialize, Deserialize)] -pub enum HyphenParamResponse { - /// Success - Success -} - #[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum TestBodyWithQueryParamsResponse { /// Success @@ -118,6 +113,12 @@ pub enum TestJsonFormDataResponse { SuccessfulOperation } +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub enum HyphenParamResponse { + /// Success + Success +} + #[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum TestClassnameResponse { /// successful operation @@ -131,12 +132,6 @@ pub enum AddPetResponse { InvalidInput } -#[derive(Debug, PartialEq, Serialize, Deserialize)] -pub enum DeletePetResponse { - /// Invalid pet value - InvalidPetValue -} - #[derive(Debug, PartialEq, Serialize, Deserialize)] #[must_use] pub enum FindPetsByStatusResponse { @@ -161,29 +156,35 @@ pub enum FindPetsByTagsResponse { #[derive(Debug, PartialEq, Serialize, Deserialize)] #[must_use] -pub enum GetPetByIdResponse { - /// successful operation - SuccessfulOperation - (models::Pet) - , +pub enum UpdatePetResponse { /// Invalid ID supplied InvalidIDSupplied , /// Pet not found PetNotFound + , + /// Validation exception + ValidationException +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub enum DeletePetResponse { + /// Invalid pet value + InvalidPetValue } #[derive(Debug, PartialEq, Serialize, Deserialize)] #[must_use] -pub enum UpdatePetResponse { +pub enum GetPetByIdResponse { + /// successful operation + SuccessfulOperation + (models::Pet) + , /// Invalid ID supplied InvalidIDSupplied , /// Pet not found PetNotFound - , - /// Validation exception - ValidationException } #[derive(Debug, PartialEq, Serialize, Deserialize)] @@ -199,16 +200,6 @@ pub enum UploadFileResponse { (models::ApiResponse) } -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[must_use] -pub enum DeleteOrderResponse { - /// Invalid ID supplied - InvalidIDSupplied - , - /// Order not found - OrderNotFound -} - #[derive(Debug, PartialEq, Serialize, Deserialize)] pub enum GetInventoryResponse { /// successful operation @@ -218,11 +209,18 @@ pub enum GetInventoryResponse { #[derive(Debug, PartialEq, Serialize, Deserialize)] #[must_use] -pub enum GetOrderByIdResponse { +pub enum PlaceOrderResponse { /// successful operation SuccessfulOperation (models::Order) , + /// Invalid Order + InvalidOrder +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[must_use] +pub enum DeleteOrderResponse { /// Invalid ID supplied InvalidIDSupplied , @@ -232,13 +230,16 @@ pub enum GetOrderByIdResponse { #[derive(Debug, PartialEq, Serialize, Deserialize)] #[must_use] -pub enum PlaceOrderResponse { +pub enum GetOrderByIdResponse { /// successful operation SuccessfulOperation (models::Order) , - /// Invalid Order - InvalidOrder + /// Invalid ID supplied + InvalidIDSupplied + , + /// Order not found + OrderNotFound } #[derive(Debug, PartialEq, Serialize, Deserialize)] @@ -259,30 +260,6 @@ pub enum CreateUsersWithListInputResponse { SuccessfulOperation } -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[must_use] -pub enum DeleteUserResponse { - /// Invalid username supplied - InvalidUsernameSupplied - , - /// User not found - UserNotFound -} - -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[must_use] -pub enum GetUserByNameResponse { - /// successful operation - SuccessfulOperation - (models::User) - , - /// Invalid username supplied - InvalidUsernameSupplied - , - /// User not found - UserNotFound -} - #[derive(Debug, PartialEq, Serialize, Deserialize)] #[must_use] pub enum LoginUserResponse { @@ -311,6 +288,30 @@ pub enum LogoutUserResponse { SuccessfulOperation } +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[must_use] +pub enum DeleteUserResponse { + /// Invalid username supplied + InvalidUsernameSupplied + , + /// User not found + UserNotFound +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[must_use] +pub enum GetUserByNameResponse { + /// successful operation + SuccessfulOperation + (models::User) + , + /// Invalid username supplied + InvalidUsernameSupplied + , + /// User not found + UserNotFound +} + #[derive(Debug, PartialEq, Serialize, Deserialize)] #[must_use] pub enum UpdateUserResponse { @@ -322,13 +323,10 @@ pub enum UpdateUserResponse { } /// API +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait Api { - fn poll_ready(&self, _cx: &mut Context) -> Poll>> { - Poll::Ready(Ok(())) - } - /// To test special tags async fn test_special_tags( &self, @@ -363,11 +361,6 @@ pub trait Api { &self, context: &C) -> Result; - async fn hyphen_param( - &self, - hyphen_param: String, - context: &C) -> Result; - async fn test_body_with_query_params( &self, query: String, @@ -387,8 +380,8 @@ pub trait Api { double: f64, pattern_without_delimiter: String, byte: swagger::ByteArray, - integer: Option, - int32: Option, + integer: Option, + int32: Option, int64: Option, float: Option, string: Option, @@ -400,15 +393,15 @@ pub trait Api { context: &C) -> Result; /// To test enum parameters - async fn test_enum_parameters( - &self, - enum_header_string_array: Option<&Vec>, - enum_header_string: Option, - enum_query_string_array: Option<&Vec>, - enum_query_string: Option, - enum_query_integer: Option, - enum_query_double: Option, - enum_form_string: Option, + async fn test_enum_parameters<'a>( + &self, + enum_header_string_array: Option<&'a Vec>, + enum_header_string: Option, + enum_query_string_array: Option<&'a Vec>, + enum_query_string: Option, + enum_query_integer: Option, + enum_query_double: Option, + enum_form_string: Option, context: &C) -> Result; /// test inline additionalProperties @@ -424,6 +417,11 @@ pub trait Api { param2: String, context: &C) -> Result; + async fn hyphen_param( + &self, + hyphen_param: String, + context: &C) -> Result; + /// To test class name in snake case async fn test_classname( &self, @@ -436,37 +434,37 @@ pub trait Api { body: models::Pet, context: &C) -> Result; - /// Deletes a pet - async fn delete_pet( - &self, - pet_id: i64, - api_key: Option, - context: &C) -> Result; - /// Finds Pets by status - async fn find_pets_by_status( + async fn find_pets_by_status<'a>( &self, - status: &Vec, + status: &'a Vec, context: &C) -> Result; /// Finds Pets by tags - async fn find_pets_by_tags( + async fn find_pets_by_tags<'a>( &self, - tags: &Vec, + tags: &'a Vec, context: &C) -> Result; - /// Find pet by ID - async fn get_pet_by_id( - &self, - pet_id: i64, - context: &C) -> Result; - /// Update an existing pet async fn update_pet( &self, body: models::Pet, context: &C) -> Result; + /// Deletes a pet + async fn delete_pet( + &self, + pet_id: i64, + api_key: Option, + context: &C) -> Result; + + /// Find pet by ID + async fn get_pet_by_id( + &self, + pet_id: i64, + context: &C) -> Result; + /// Updates a pet in the store with form data async fn update_pet_with_form( &self, @@ -483,29 +481,29 @@ pub trait Api { file: Option, context: &C) -> Result; - /// Delete purchase order by ID - async fn delete_order( - &self, - order_id: String, - context: &C) -> Result; - /// Returns pet inventories by status async fn get_inventory( &self, context: &C) -> Result; - /// Find purchase order by ID - async fn get_order_by_id( - &self, - order_id: i64, - context: &C) -> Result; - /// Place an order for a pet async fn place_order( &self, body: models::Order, context: &C) -> Result; + /// Delete purchase order by ID + async fn delete_order( + &self, + order_id: String, + context: &C) -> Result; + + /// Find purchase order by ID + async fn get_order_by_id( + &self, + order_id: u64, + context: &C) -> Result; + /// Create user async fn create_user( &self, @@ -513,29 +511,17 @@ pub trait Api { context: &C) -> Result; /// Creates list of users with given input array - async fn create_users_with_array_input( + async fn create_users_with_array_input<'a>( &self, - body: &Vec, + body: &'a Vec, context: &C) -> Result; /// Creates list of users with given input array - async fn create_users_with_list_input( + async fn create_users_with_list_input<'a>( &self, - body: &Vec, + body: &'a Vec, context: &C) -> Result; - /// Delete user - async fn delete_user( - &self, - username: String, - context: &C) -> Result; - - /// Get user by user name - async fn get_user_by_name( - &self, - username: String, - context: &C) -> Result; - /// Logs user into the system async fn login_user( &self, @@ -548,6 +534,18 @@ pub trait Api { &self, context: &C) -> Result; + /// Delete user + async fn delete_user( + &self, + username: String, + context: &C) -> Result; + + /// Get user by user name + async fn get_user_by_name( + &self, + username: String, + context: &C) -> Result; + /// Updated user async fn update_user( &self, @@ -558,11 +556,14 @@ pub trait Api { } /// API where `Context` isn't passed on every API call +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait ApiNoContext { - - fn poll_ready(&self, _cx: &mut Context) -> Poll>>; + // The std::task::Context struct houses a reference to std::task::Waker with the lifetime <'a>. + // Adding an anonymous lifetime `'a` to allow mockall to create a mock object with the right lifetimes. + // This is needed because the compiler is unable to determine the lifetimes on F's trait bound + // where F is the closure created by mockall. We use higher-rank trait bounds here to get around this. fn context(&self) -> &C; @@ -600,11 +601,6 @@ pub trait ApiNoContext { &self, ) -> Result; - async fn hyphen_param( - &self, - hyphen_param: String, - ) -> Result; - async fn test_body_with_query_params( &self, query: String, @@ -624,8 +620,8 @@ pub trait ApiNoContext { double: f64, pattern_without_delimiter: String, byte: swagger::ByteArray, - integer: Option, - int32: Option, + integer: Option, + int32: Option, int64: Option, float: Option, string: Option, @@ -637,15 +633,15 @@ pub trait ApiNoContext { ) -> Result; /// To test enum parameters - async fn test_enum_parameters( - &self, - enum_header_string_array: Option<&Vec>, - enum_header_string: Option, - enum_query_string_array: Option<&Vec>, - enum_query_string: Option, - enum_query_integer: Option, - enum_query_double: Option, - enum_form_string: Option, + async fn test_enum_parameters<'a>( + &self, + enum_header_string_array: Option<&'a Vec>, + enum_header_string: Option, + enum_query_string_array: Option<&'a Vec>, + enum_query_string: Option, + enum_query_integer: Option, + enum_query_double: Option, + enum_form_string: Option, ) -> Result; /// test inline additionalProperties @@ -661,6 +657,11 @@ pub trait ApiNoContext { param2: String, ) -> Result; + async fn hyphen_param( + &self, + hyphen_param: String, + ) -> Result; + /// To test class name in snake case async fn test_classname( &self, @@ -673,37 +674,37 @@ pub trait ApiNoContext { body: models::Pet, ) -> Result; - /// Deletes a pet - async fn delete_pet( - &self, - pet_id: i64, - api_key: Option, - ) -> Result; - /// Finds Pets by status - async fn find_pets_by_status( + async fn find_pets_by_status<'a>( &self, - status: &Vec, + status: &'a Vec, ) -> Result; /// Finds Pets by tags - async fn find_pets_by_tags( + async fn find_pets_by_tags<'a>( &self, - tags: &Vec, + tags: &'a Vec, ) -> Result; - /// Find pet by ID - async fn get_pet_by_id( - &self, - pet_id: i64, - ) -> Result; - /// Update an existing pet async fn update_pet( &self, body: models::Pet, ) -> Result; + /// Deletes a pet + async fn delete_pet( + &self, + pet_id: i64, + api_key: Option, + ) -> Result; + + /// Find pet by ID + async fn get_pet_by_id( + &self, + pet_id: i64, + ) -> Result; + /// Updates a pet in the store with form data async fn update_pet_with_form( &self, @@ -720,29 +721,29 @@ pub trait ApiNoContext { file: Option, ) -> Result; - /// Delete purchase order by ID - async fn delete_order( - &self, - order_id: String, - ) -> Result; - /// Returns pet inventories by status async fn get_inventory( &self, ) -> Result; - /// Find purchase order by ID - async fn get_order_by_id( - &self, - order_id: i64, - ) -> Result; - /// Place an order for a pet async fn place_order( &self, body: models::Order, ) -> Result; + /// Delete purchase order by ID + async fn delete_order( + &self, + order_id: String, + ) -> Result; + + /// Find purchase order by ID + async fn get_order_by_id( + &self, + order_id: u64, + ) -> Result; + /// Create user async fn create_user( &self, @@ -750,29 +751,17 @@ pub trait ApiNoContext { ) -> Result; /// Creates list of users with given input array - async fn create_users_with_array_input( + async fn create_users_with_array_input<'a>( &self, - body: &Vec, + body: &'a Vec, ) -> Result; /// Creates list of users with given input array - async fn create_users_with_list_input( + async fn create_users_with_list_input<'a>( &self, - body: &Vec, + body: &'a Vec, ) -> Result; - /// Delete user - async fn delete_user( - &self, - username: String, - ) -> Result; - - /// Get user by user name - async fn get_user_by_name( - &self, - username: String, - ) -> Result; - /// Logs user into the system async fn login_user( &self, @@ -785,6 +774,18 @@ pub trait ApiNoContext { &self, ) -> Result; + /// Delete user + async fn delete_user( + &self, + username: String, + ) -> Result; + + /// Get user by user name + async fn get_user_by_name( + &self, + username: String, + ) -> Result; + /// Updated user async fn update_user( &self, @@ -809,10 +810,6 @@ impl + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt for T #[async_trait] impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for ContextWrapper { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - self.api().poll_ready(cx) - } - fn context(&self) -> &C { ContextWrapper::context(self) } @@ -879,15 +876,6 @@ impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for Contex self.api().fake_response_with_numerical_description(&context).await } - async fn hyphen_param( - &self, - hyphen_param: String, - ) -> Result - { - let context = self.context().clone(); - self.api().hyphen_param(hyphen_param, &context).await - } - async fn test_body_with_query_params( &self, query: String, @@ -915,8 +903,8 @@ impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for Contex double: f64, pattern_without_delimiter: String, byte: swagger::ByteArray, - integer: Option, - int32: Option, + integer: Option, + int32: Option, int64: Option, float: Option, string: Option, @@ -932,15 +920,15 @@ impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for Contex } /// To test enum parameters - async fn test_enum_parameters( - &self, - enum_header_string_array: Option<&Vec>, - enum_header_string: Option, - enum_query_string_array: Option<&Vec>, - enum_query_string: Option, - enum_query_integer: Option, - enum_query_double: Option, - enum_form_string: Option, + async fn test_enum_parameters<'a>( + &self, + enum_header_string_array: Option<&'a Vec>, + enum_header_string: Option, + enum_query_string_array: Option<&'a Vec>, + enum_query_string: Option, + enum_query_integer: Option, + enum_query_double: Option, + enum_form_string: Option, ) -> Result { let context = self.context().clone(); @@ -968,6 +956,15 @@ impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for Contex self.api().test_json_form_data(param, param2, &context).await } + async fn hyphen_param( + &self, + hyphen_param: String, + ) -> Result + { + let context = self.context().clone(); + self.api().hyphen_param(hyphen_param, &context).await + } + /// To test class name in snake case async fn test_classname( &self, @@ -988,21 +985,10 @@ impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for Contex self.api().add_pet(body, &context).await } - /// Deletes a pet - async fn delete_pet( - &self, - pet_id: i64, - api_key: Option, - ) -> Result - { - let context = self.context().clone(); - self.api().delete_pet(pet_id, api_key, &context).await - } - /// Finds Pets by status - async fn find_pets_by_status( + async fn find_pets_by_status<'a>( &self, - status: &Vec, + status: &'a Vec, ) -> Result { let context = self.context().clone(); @@ -1010,33 +996,44 @@ impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for Contex } /// Finds Pets by tags - async fn find_pets_by_tags( + async fn find_pets_by_tags<'a>( &self, - tags: &Vec, + tags: &'a Vec, ) -> Result { let context = self.context().clone(); self.api().find_pets_by_tags(tags, &context).await } - /// Find pet by ID - async fn get_pet_by_id( + /// Update an existing pet + async fn update_pet( + &self, + body: models::Pet, + ) -> Result + { + let context = self.context().clone(); + self.api().update_pet(body, &context).await + } + + /// Deletes a pet + async fn delete_pet( &self, pet_id: i64, - ) -> Result + api_key: Option, + ) -> Result { let context = self.context().clone(); - self.api().get_pet_by_id(pet_id, &context).await + self.api().delete_pet(pet_id, api_key, &context).await } - /// Update an existing pet - async fn update_pet( + /// Find pet by ID + async fn get_pet_by_id( &self, - body: models::Pet, - ) -> Result + pet_id: i64, + ) -> Result { let context = self.context().clone(); - self.api().update_pet(body, &context).await + self.api().get_pet_by_id(pet_id, &context).await } /// Updates a pet in the store with form data @@ -1063,43 +1060,43 @@ impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for Contex self.api().upload_file(pet_id, additional_metadata, file, &context).await } - /// Delete purchase order by ID - async fn delete_order( + /// Returns pet inventories by status + async fn get_inventory( &self, - order_id: String, - ) -> Result + ) -> Result { let context = self.context().clone(); - self.api().delete_order(order_id, &context).await + self.api().get_inventory(&context).await } - /// Returns pet inventories by status - async fn get_inventory( + /// Place an order for a pet + async fn place_order( &self, - ) -> Result + body: models::Order, + ) -> Result { let context = self.context().clone(); - self.api().get_inventory(&context).await + self.api().place_order(body, &context).await } - /// Find purchase order by ID - async fn get_order_by_id( + /// Delete purchase order by ID + async fn delete_order( &self, - order_id: i64, - ) -> Result + order_id: String, + ) -> Result { let context = self.context().clone(); - self.api().get_order_by_id(order_id, &context).await + self.api().delete_order(order_id, &context).await } - /// Place an order for a pet - async fn place_order( + /// Find purchase order by ID + async fn get_order_by_id( &self, - body: models::Order, - ) -> Result + order_id: u64, + ) -> Result { let context = self.context().clone(); - self.api().place_order(body, &context).await + self.api().get_order_by_id(order_id, &context).await } /// Create user @@ -1113,9 +1110,9 @@ impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for Contex } /// Creates list of users with given input array - async fn create_users_with_array_input( + async fn create_users_with_array_input<'a>( &self, - body: &Vec, + body: &'a Vec, ) -> Result { let context = self.context().clone(); @@ -1123,53 +1120,53 @@ impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for Contex } /// Creates list of users with given input array - async fn create_users_with_list_input( + async fn create_users_with_list_input<'a>( &self, - body: &Vec, + body: &'a Vec, ) -> Result { let context = self.context().clone(); self.api().create_users_with_list_input(body, &context).await } - /// Delete user - async fn delete_user( + /// Logs user into the system + async fn login_user( &self, username: String, - ) -> Result + password: String, + ) -> Result { let context = self.context().clone(); - self.api().delete_user(username, &context).await + self.api().login_user(username, password, &context).await } - /// Get user by user name - async fn get_user_by_name( + /// Logs out current logged in user session + async fn logout_user( &self, - username: String, - ) -> Result + ) -> Result { let context = self.context().clone(); - self.api().get_user_by_name(username, &context).await + self.api().logout_user(&context).await } - /// Logs user into the system - async fn login_user( + /// Delete user + async fn delete_user( &self, username: String, - password: String, - ) -> Result + ) -> Result { let context = self.context().clone(); - self.api().login_user(username, password, &context).await + self.api().delete_user(username, &context).await } - /// Logs out current logged in user session - async fn logout_user( + /// Get user by user name + async fn get_user_by_name( &self, - ) -> Result + username: String, + ) -> Result { let context = self.context().clone(); - self.api().logout_user(&context).await + self.api().get_user_by_name(username, &context).await } /// Updated user diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/models.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/models.rs index c77a7acf8384..c724b2becd44 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/models.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/models.rs @@ -1,24 +1,48 @@ #![allow(unused_qualifications)] - +#[cfg(not(feature = "validate"))] use validator::Validate; use crate::models; #[cfg(any(feature = "client", feature = "server"))] use crate::header; +#[cfg(feature = "validate")] +use serde_valid::Validate; -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct AdditionalPropertiesClass { #[serde(rename = "map_property")] + #[serde(skip_serializing_if="Option::is_none")] pub map_property: Option>, #[serde(rename = "map_of_map_property")] + #[serde(skip_serializing_if="Option::is_none")] pub map_of_map_property: Option>>, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for AdditionalPropertiesClass { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for AdditionalPropertiesClass { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl AdditionalPropertiesClass { #[allow(clippy::new_without_default)] @@ -31,24 +55,21 @@ impl AdditionalPropertiesClass { } /// Converts the AdditionalPropertiesClass value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for AdditionalPropertiesClass { - fn to_string(&self) -> String { +impl std::fmt::Display for AdditionalPropertiesClass { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - // Skipping map_property in query parameter serialization - - // Skipping map_of_map_property in query parameter serialization - // Skipping map_of_map_property in query parameter serialization - + // Skipping map map_property in query parameter serialization + // Skipping map map_of_map_property in query parameter serialization ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a AdditionalPropertiesClass value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for AdditionalPropertiesClass { type Err = String; @@ -106,8 +127,7 @@ impl std::convert::TryFrom> f match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for AdditionalPropertiesClass - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for AdditionalPropertiesClass - value: {hdr_value} is invalid {e}")) } } } @@ -122,17 +142,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into AdditionalPropertiesClass - {}", - value, err)) + format!("Unable to convert header value '{value}' into AdditionalPropertiesClass - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into AdditionalPropertiesClass - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl AdditionalPropertiesClass { /// Helper function to allow us to convert this model to an XML string. @@ -143,18 +203,40 @@ impl AdditionalPropertiesClass { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct Animal { #[serde(rename = "className")] + pub class_name: String, #[serde(rename = "color")] + #[serde(skip_serializing_if="Option::is_none")] pub color: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for Animal { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for Animal { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl Animal { #[allow(clippy::new_without_default)] @@ -167,31 +249,27 @@ impl Animal { } /// Converts the Animal value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for Animal { - fn to_string(&self) -> String { +impl std::fmt::Display for Animal { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - Some("className".to_string()), Some(self.class_name.to_string()), - - self.color.as_ref().map(|color| { [ "color".to_string(), color.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a Animal value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for Animal { type Err = String; @@ -251,8 +329,7 @@ impl std::convert::TryFrom> for hyper::header::H match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for Animal - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for Animal - value: {hdr_value} is invalid {e}")) } } } @@ -267,17 +344,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into Animal - {}", - value, err)) + format!("Unable to convert header value '{value}' into Animal - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Animal - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl Animal { /// Helper function to allow us to convert this model to an XML string. @@ -289,6 +406,7 @@ impl Animal { } #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "validate", derive(Validate))] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct AnimalFarm( Vec @@ -353,16 +471,16 @@ impl std::ops::DerefMut for AnimalFarm { } /// Converts the AnimalFarm value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for AnimalFarm { - fn to_string(&self) -> String { - self.iter().map(|x| x.to_string()).collect::>().join(",") +impl std::fmt::Display for AnimalFarm { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.iter().map(|x| x.to_string()).collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a AnimalFarm value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for AnimalFarm { type Err = ::Err; @@ -389,8 +507,7 @@ impl std::convert::TryFrom> for hyper::heade match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for AnimalFarm - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for AnimalFarm - value: {hdr_value} is invalid {e}")) } } } @@ -405,17 +522,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into AnimalFarm - {}", - value, err)) + format!("Unable to convert header value '{value}' into AnimalFarm - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into AnimalFarm - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl AnimalFarm { /// Helper function to allow us to convert this model to an XML string. @@ -426,23 +583,46 @@ impl AnimalFarm { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct ApiResponse { #[serde(rename = "code")] + #[serde(skip_serializing_if="Option::is_none")] pub code: Option, #[serde(rename = "type")] + #[serde(skip_serializing_if="Option::is_none")] pub r#type: Option, #[serde(rename = "message")] + #[serde(skip_serializing_if="Option::is_none")] pub message: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for ApiResponse { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for ApiResponse { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl ApiResponse { #[allow(clippy::new_without_default)] @@ -456,43 +636,37 @@ impl ApiResponse { } /// Converts the ApiResponse value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for ApiResponse { - fn to_string(&self) -> String { +impl std::fmt::Display for ApiResponse { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.code.as_ref().map(|code| { [ "code".to_string(), code.to_string(), ].join(",") }), - - self.r#type.as_ref().map(|r#type| { [ "type".to_string(), r#type.to_string(), ].join(",") }), - - self.message.as_ref().map(|message| { [ "message".to_string(), message.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a ApiResponse value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for ApiResponse { type Err = String; @@ -556,8 +730,7 @@ impl std::convert::TryFrom> for hyper::head match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for ApiResponse - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for ApiResponse - value: {hdr_value} is invalid {e}")) } } } @@ -572,17 +745,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into ApiResponse - {}", - value, err)) + format!("Unable to convert header value '{value}' into ApiResponse - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ApiResponse - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl ApiResponse { /// Helper function to allow us to convert this model to an XML string. @@ -593,15 +806,36 @@ impl ApiResponse { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct ArrayOfArrayOfNumberOnly { #[serde(rename = "ArrayArrayNumber")] + #[serde(skip_serializing_if="Option::is_none")] pub array_array_number: Option>>, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for ArrayOfArrayOfNumberOnly { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for ArrayOfArrayOfNumberOnly { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl ArrayOfArrayOfNumberOnly { #[allow(clippy::new_without_default)] @@ -613,21 +847,20 @@ impl ArrayOfArrayOfNumberOnly { } /// Converts the ArrayOfArrayOfNumberOnly value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for ArrayOfArrayOfNumberOnly { - fn to_string(&self) -> String { +impl std::fmt::Display for ArrayOfArrayOfNumberOnly { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - // Skipping ArrayArrayNumber in query parameter serialization - + // Skipping non-primitive type ArrayArrayNumber in query parameter serialization ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a ArrayOfArrayOfNumberOnly value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for ArrayOfArrayOfNumberOnly { type Err = String; @@ -682,8 +915,7 @@ impl std::convert::TryFrom> fo match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for ArrayOfArrayOfNumberOnly - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for ArrayOfArrayOfNumberOnly - value: {hdr_value} is invalid {e}")) } } } @@ -698,17 +930,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into ArrayOfArrayOfNumberOnly - {}", - value, err)) + format!("Unable to convert header value '{value}' into ArrayOfArrayOfNumberOnly - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ArrayOfArrayOfNumberOnly - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl ArrayOfArrayOfNumberOnly { /// Helper function to allow us to convert this model to an XML string. @@ -719,15 +991,36 @@ impl ArrayOfArrayOfNumberOnly { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct ArrayOfNumberOnly { #[serde(rename = "ArrayNumber")] + #[serde(skip_serializing_if="Option::is_none")] pub array_number: Option>, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for ArrayOfNumberOnly { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for ArrayOfNumberOnly { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl ArrayOfNumberOnly { #[allow(clippy::new_without_default)] @@ -739,27 +1032,25 @@ impl ArrayOfNumberOnly { } /// Converts the ArrayOfNumberOnly value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for ArrayOfNumberOnly { - fn to_string(&self) -> String { +impl std::fmt::Display for ArrayOfNumberOnly { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.array_number.as_ref().map(|array_number| { [ "ArrayNumber".to_string(), array_number.iter().map(|x| x.to_string()).collect::>().join(","), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a ArrayOfNumberOnly value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for ArrayOfNumberOnly { type Err = String; @@ -814,8 +1105,7 @@ impl std::convert::TryFrom> for hyper match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for ArrayOfNumberOnly - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for ArrayOfNumberOnly - value: {hdr_value} is invalid {e}")) } } } @@ -830,17 +1120,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into ArrayOfNumberOnly - {}", - value, err)) + format!("Unable to convert header value '{value}' into ArrayOfNumberOnly - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ArrayOfNumberOnly - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl ArrayOfNumberOnly { /// Helper function to allow us to convert this model to an XML string. @@ -851,26 +1181,51 @@ impl ArrayOfNumberOnly { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct ArrayTest { #[serde(rename = "array_of_string")] + #[serde(skip_serializing_if="Option::is_none")] pub array_of_string: Option>, #[serde(rename = "array_array_of_integer")] + #[serde(skip_serializing_if="Option::is_none")] pub array_array_of_integer: Option>>, #[serde(rename = "array_array_of_model")] + + #[cfg_attr(feature = "validate", validate)] #[serde(skip_serializing_if="Option::is_none")] pub array_array_of_model: Option>>, - // Note: inline enums are not fully supported by openapi-generator #[serde(rename = "array_of_enum")] + + #[cfg_attr(feature = "validate", validate)] #[serde(skip_serializing_if="Option::is_none")] - pub array_of_enum: Option>, + pub array_of_enum: Option>, + +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for ArrayTest { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for ArrayTest { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } } @@ -887,39 +1242,28 @@ impl ArrayTest { } /// Converts the ArrayTest value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for ArrayTest { - fn to_string(&self) -> String { +impl std::fmt::Display for ArrayTest { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.array_of_string.as_ref().map(|array_of_string| { [ "array_of_string".to_string(), array_of_string.iter().map(|x| x.to_string()).collect::>().join(","), ].join(",") }), - - // Skipping array_array_of_integer in query parameter serialization - - // Skipping array_array_of_model in query parameter serialization - - - self.array_of_enum.as_ref().map(|array_of_enum| { - [ - "array_of_enum".to_string(), - array_of_enum.iter().map(|x| x.to_string()).collect::>().join(","), - ].join(",") - }), - + // Skipping non-primitive type array_array_of_integer in query parameter serialization + // Skipping non-primitive type array_array_of_model in query parameter serialization + // Skipping non-primitive type array_of_enum in query parameter serialization ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a ArrayTest value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for ArrayTest { type Err = String; @@ -932,7 +1276,7 @@ impl std::str::FromStr for ArrayTest { pub array_of_string: Vec>, pub array_array_of_integer: Vec>>, pub array_array_of_model: Vec>>, - pub array_of_enum: Vec>, + pub array_of_enum: Vec>, } let mut intermediate_rep = IntermediateRep::default(); @@ -983,8 +1327,7 @@ impl std::convert::TryFrom> for hyper::header match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for ArrayTest - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for ArrayTest - value: {hdr_value} is invalid {e}")) } } } @@ -999,17 +1342,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into ArrayTest - {}", - value, err)) + format!("Unable to convert header value '{value}' into ArrayTest - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ArrayTest - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl ArrayTest { /// Helper function to allow us to convert this model to an XML string. @@ -1020,36 +1403,62 @@ impl ArrayTest { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct Capitalization { #[serde(rename = "smallCamel")] + #[serde(skip_serializing_if="Option::is_none")] pub small_camel: Option, #[serde(rename = "CapitalCamel")] + #[serde(skip_serializing_if="Option::is_none")] pub capital_camel: Option, #[serde(rename = "small_Snake")] + #[serde(skip_serializing_if="Option::is_none")] pub small_snake: Option, #[serde(rename = "Capital_Snake")] + #[serde(skip_serializing_if="Option::is_none")] pub capital_snake: Option, #[serde(rename = "SCA_ETH_Flow_Points")] + #[serde(skip_serializing_if="Option::is_none")] pub sca_eth_flow_points: Option, /// Name of the pet #[serde(rename = "ATT_NAME")] + #[serde(skip_serializing_if="Option::is_none")] pub att_name: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for Capitalization { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for Capitalization { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl Capitalization { #[allow(clippy::new_without_default)] @@ -1066,67 +1475,55 @@ impl Capitalization { } /// Converts the Capitalization value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for Capitalization { - fn to_string(&self) -> String { +impl std::fmt::Display for Capitalization { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.small_camel.as_ref().map(|small_camel| { [ "smallCamel".to_string(), small_camel.to_string(), ].join(",") }), - - self.capital_camel.as_ref().map(|capital_camel| { [ "CapitalCamel".to_string(), capital_camel.to_string(), ].join(",") }), - - self.small_snake.as_ref().map(|small_snake| { [ "small_Snake".to_string(), small_snake.to_string(), ].join(",") }), - - self.capital_snake.as_ref().map(|capital_snake| { [ "Capital_Snake".to_string(), capital_snake.to_string(), ].join(",") }), - - self.sca_eth_flow_points.as_ref().map(|sca_eth_flow_points| { [ "SCA_ETH_Flow_Points".to_string(), sca_eth_flow_points.to_string(), ].join(",") }), - - self.att_name.as_ref().map(|att_name| { [ "ATT_NAME".to_string(), att_name.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a Capitalization value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for Capitalization { type Err = String; @@ -1202,8 +1599,7 @@ impl std::convert::TryFrom> for hyper::h match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for Capitalization - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for Capitalization - value: {hdr_value} is invalid {e}")) } } } @@ -1218,17 +1614,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into Capitalization - {}", - value, err)) + format!("Unable to convert header value '{value}' into Capitalization - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Capitalization - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl Capitalization { /// Helper function to allow us to convert this model to an XML string. @@ -1239,22 +1675,45 @@ impl Capitalization { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct Cat { #[serde(rename = "className")] + pub class_name: String, #[serde(rename = "color")] + #[serde(skip_serializing_if="Option::is_none")] pub color: Option, #[serde(rename = "declawed")] + #[serde(skip_serializing_if="Option::is_none")] pub declawed: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for Cat { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for Cat { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl Cat { #[allow(clippy::new_without_default)] @@ -1268,39 +1727,33 @@ impl Cat { } /// Converts the Cat value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for Cat { - fn to_string(&self) -> String { +impl std::fmt::Display for Cat { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - Some("className".to_string()), Some(self.class_name.to_string()), - - self.color.as_ref().map(|color| { [ "color".to_string(), color.to_string(), ].join(",") }), - - self.declawed.as_ref().map(|declawed| { [ "declawed".to_string(), declawed.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a Cat value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for Cat { type Err = String; @@ -1364,8 +1817,7 @@ impl std::convert::TryFrom> for hyper::header::Head match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for Cat - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for Cat - value: {hdr_value} is invalid {e}")) } } } @@ -1380,41 +1832,103 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into Cat - {}", - value, err)) + format!("Unable to convert header value '{value}' into Cat - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl Cat { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. - #[allow(dead_code)] - pub(crate) fn as_xml(&self) -> String { - serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] -#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -#[serde(rename = "Category")] -pub struct Category { - #[serde(rename = "id")] +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Cat - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl Cat { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +#[serde(rename = "Category")] +pub struct Category { + #[serde(rename = "id")] + #[serde(skip_serializing_if="Option::is_none")] pub id: Option, #[serde(rename = "name")] + #[serde(skip_serializing_if="Option::is_none")] pub name: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for Category { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for Category { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl Category { #[allow(clippy::new_without_default)] @@ -1427,35 +1941,31 @@ impl Category { } /// Converts the Category value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for Category { - fn to_string(&self) -> String { +impl std::fmt::Display for Category { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.id.as_ref().map(|id| { [ "id".to_string(), id.to_string(), ].join(",") }), - - self.name.as_ref().map(|name| { [ "name".to_string(), name.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a Category value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for Category { type Err = String; @@ -1515,8 +2025,7 @@ impl std::convert::TryFrom> for hyper::header: match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for Category - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for Category - value: {hdr_value} is invalid {e}")) } } } @@ -1531,17 +2040,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into Category - {}", - value, err)) + format!("Unable to convert header value '{value}' into Category - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Category - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl Category { /// Helper function to allow us to convert this model to an XML string. @@ -1553,15 +2102,36 @@ impl Category { } /// Model for testing model with \"_class\" property -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct ClassModel { #[serde(rename = "_class")] + #[serde(skip_serializing_if="Option::is_none")] pub _class: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for ClassModel { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for ClassModel { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl ClassModel { #[allow(clippy::new_without_default)] @@ -1573,27 +2143,25 @@ impl ClassModel { } /// Converts the ClassModel value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for ClassModel { - fn to_string(&self) -> String { +impl std::fmt::Display for ClassModel { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self._class.as_ref().map(|_class| { [ "_class".to_string(), _class.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a ClassModel value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for ClassModel { type Err = String; @@ -1649,8 +2217,7 @@ impl std::convert::TryFrom> for hyper::heade match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for ClassModel - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for ClassModel - value: {hdr_value} is invalid {e}")) } } } @@ -1665,17 +2232,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into ClassModel - {}", - value, err)) + format!("Unable to convert header value '{value}' into ClassModel - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ClassModel - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl ClassModel { /// Helper function to allow us to convert this model to an XML string. @@ -1686,15 +2293,36 @@ impl ClassModel { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct Client { #[serde(rename = "client")] + #[serde(skip_serializing_if="Option::is_none")] pub client: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for Client { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for Client { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl Client { #[allow(clippy::new_without_default)] @@ -1706,27 +2334,25 @@ impl Client { } /// Converts the Client value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for Client { - fn to_string(&self) -> String { +impl std::fmt::Display for Client { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.client.as_ref().map(|client| { [ "client".to_string(), client.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a Client value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for Client { type Err = String; @@ -1782,8 +2408,7 @@ impl std::convert::TryFrom> for hyper::header::H match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for Client - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for Client - value: {hdr_value} is invalid {e}")) } } } @@ -1798,17 +2423,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into Client - {}", - value, err)) + format!("Unable to convert header value '{value}' into Client - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Client - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl Client { /// Helper function to allow us to convert this model to an XML string. @@ -1819,22 +2484,45 @@ impl Client { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct Dog { #[serde(rename = "className")] + pub class_name: String, #[serde(rename = "color")] + #[serde(skip_serializing_if="Option::is_none")] pub color: Option, #[serde(rename = "breed")] + #[serde(skip_serializing_if="Option::is_none")] pub breed: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for Dog { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for Dog { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl Dog { #[allow(clippy::new_without_default)] @@ -1848,39 +2536,33 @@ impl Dog { } /// Converts the Dog value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for Dog { - fn to_string(&self) -> String { +impl std::fmt::Display for Dog { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - Some("className".to_string()), Some(self.class_name.to_string()), - - self.color.as_ref().map(|color| { [ "color".to_string(), color.to_string(), ].join(",") }), - - self.breed.as_ref().map(|breed| { [ "breed".to_string(), breed.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a Dog value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for Dog { type Err = String; @@ -1944,8 +2626,7 @@ impl std::convert::TryFrom> for hyper::header::Head match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for Dog - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for Dog - value: {hdr_value} is invalid {e}")) } } } @@ -1960,17 +2641,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into Dog - {}", - value, err)) + format!("Unable to convert header value '{value}' into Dog - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Dog - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl Dog { /// Helper function to allow us to convert this model to an XML string. @@ -1981,50 +2702,69 @@ impl Dog { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] #[serde(rename = "$special[model.name]")] -pub struct DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket { +pub struct DollarSpecialLeftSquareBracketModelNameRightSquareBracket { #[serde(rename = "$special[property.name]")] + #[serde(skip_serializing_if="Option::is_none")] - pub dollar_special_left_square_bracket_property_period_name_right_square_bracket: Option, + pub dollar_special_left_square_bracket_property_name_right_square_bracket: Option, + +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for DollarSpecialLeftSquareBracketModelNameRightSquareBracket { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for DollarSpecialLeftSquareBracketModelNameRightSquareBracket { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } } -impl DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket { +impl DollarSpecialLeftSquareBracketModelNameRightSquareBracket { #[allow(clippy::new_without_default)] - pub fn new() -> DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket { - DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket { - dollar_special_left_square_bracket_property_period_name_right_square_bracket: None, + pub fn new() -> DollarSpecialLeftSquareBracketModelNameRightSquareBracket { + DollarSpecialLeftSquareBracketModelNameRightSquareBracket { + dollar_special_left_square_bracket_property_name_right_square_bracket: None, } } } -/// Converts the DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// Converts the DollarSpecialLeftSquareBracketModelNameRightSquareBracket value to the Query Parameters representation (style=form, explode=false) +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket { - fn to_string(&self) -> String { +impl std::fmt::Display for DollarSpecialLeftSquareBracketModelNameRightSquareBracket { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - - self.dollar_special_left_square_bracket_property_period_name_right_square_bracket.as_ref().map(|dollar_special_left_square_bracket_property_period_name_right_square_bracket| { + self.dollar_special_left_square_bracket_property_name_right_square_bracket.as_ref().map(|dollar_special_left_square_bracket_property_name_right_square_bracket| { [ "$special[property.name]".to_string(), - dollar_special_left_square_bracket_property_period_name_right_square_bracket.to_string(), + dollar_special_left_square_bracket_property_name_right_square_bracket.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } -/// Converts Query Parameters representation (style=form, explode=false) to a DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// Converts Query Parameters representation (style=form, explode=false) to a DollarSpecialLeftSquareBracketModelNameRightSquareBracket value +/// as specified in /// Should be implemented in a serde deserializer -impl std::str::FromStr for DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket { +impl std::str::FromStr for DollarSpecialLeftSquareBracketModelNameRightSquareBracket { type Err = String; fn from_str(s: &str) -> std::result::Result { @@ -2032,7 +2772,7 @@ impl std::str::FromStr for DollarSpecialLeftSquareBracketModelPeriodNameRightSqu #[derive(Default)] #[allow(dead_code)] struct IntermediateRep { - pub dollar_special_left_square_bracket_property_period_name_right_square_bracket: Vec, + pub dollar_special_left_square_bracket_property_name_right_square_bracket: Vec, } let mut intermediate_rep = IntermediateRep::default(); @@ -2044,15 +2784,15 @@ impl std::str::FromStr for DollarSpecialLeftSquareBracketModelPeriodNameRightSqu while key_result.is_some() { let val = match string_iter.next() { Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket".to_string()) + None => return std::result::Result::Err("Missing value while parsing DollarSpecialLeftSquareBracketModelNameRightSquareBracket".to_string()) }; if let Some(key) = key_result { #[allow(clippy::match_single_binding)] match key { #[allow(clippy::redundant_clone)] - "$special[property.name]" => intermediate_rep.dollar_special_left_square_bracket_property_period_name_right_square_bracket.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket".to_string()) + "$special[property.name]" => intermediate_rep.dollar_special_left_square_bracket_property_name_right_square_bracket.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing DollarSpecialLeftSquareBracketModelNameRightSquareBracket".to_string()) } } @@ -2061,52 +2801,91 @@ impl std::str::FromStr for DollarSpecialLeftSquareBracketModelPeriodNameRightSqu } // Use the intermediate representation to return the struct - std::result::Result::Ok(DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket { - dollar_special_left_square_bracket_property_period_name_right_square_bracket: intermediate_rep.dollar_special_left_square_bracket_property_period_name_right_square_bracket.into_iter().next(), + std::result::Result::Ok(DollarSpecialLeftSquareBracketModelNameRightSquareBracket { + dollar_special_left_square_bracket_property_name_right_square_bracket: intermediate_rep.dollar_special_left_square_bracket_property_name_right_square_bracket.into_iter().next(), }) } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for DollarSpecialLeftSquareBracketModelNameRightSquareBracket - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket - {}", - value, err)) + format!("Unable to convert header value '{value}' into DollarSpecialLeftSquareBracketModelNameRightSquareBracket - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into DollarSpecialLeftSquareBracketModelNameRightSquareBracket - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} -impl DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket { +impl DollarSpecialLeftSquareBracketModelNameRightSquareBracket { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -2115,24 +2894,47 @@ impl DollarSpecialLeftSquareBracketModelPeriodNameRightSquareBracket { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct EnumArrays { - // Note: inline enums are not fully supported by openapi-generator #[serde(rename = "just_symbol")] + + #[cfg_attr(feature = "validate", validate)] #[serde(skip_serializing_if="Option::is_none")] - pub just_symbol: Option, + pub just_symbol: Option, - // Note: inline enums are not fully supported by openapi-generator #[serde(rename = "array_enum")] + + #[cfg_attr(feature = "validate", validate)] #[serde(skip_serializing_if="Option::is_none")] - pub array_enum: Option>, + pub array_enum: Option>, - // Note: inline enums are not fully supported by openapi-generator #[serde(rename = "array_array_enum")] + + #[cfg_attr(feature = "validate", validate)] #[serde(skip_serializing_if="Option::is_none")] - pub array_array_enum: Option>>, + pub array_array_enum: Option>>, + +} +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for EnumArrays { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for EnumArrays { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } } @@ -2148,37 +2950,22 @@ impl EnumArrays { } /// Converts the EnumArrays value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for EnumArrays { - fn to_string(&self) -> String { +impl std::fmt::Display for EnumArrays { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - - self.just_symbol.as_ref().map(|just_symbol| { - [ - "just_symbol".to_string(), - just_symbol.to_string(), - ].join(",") - }), - - - self.array_enum.as_ref().map(|array_enum| { - [ - "array_enum".to_string(), - array_enum.iter().map(|x| x.to_string()).collect::>().join(","), - ].join(",") - }), - - // Skipping array_array_enum in query parameter serialization - + // Skipping non-primitive type just_symbol in query parameter serialization + // Skipping non-primitive type array_enum in query parameter serialization + // Skipping non-primitive type array_array_enum in query parameter serialization ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a EnumArrays value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for EnumArrays { type Err = String; @@ -2188,9 +2975,9 @@ impl std::str::FromStr for EnumArrays { #[derive(Default)] #[allow(dead_code)] struct IntermediateRep { - pub just_symbol: Vec, - pub array_enum: Vec>, - pub array_array_enum: Vec>>, + pub just_symbol: Vec, + pub array_enum: Vec>, + pub array_array_enum: Vec>>, } let mut intermediate_rep = IntermediateRep::default(); @@ -2209,7 +2996,7 @@ impl std::str::FromStr for EnumArrays { #[allow(clippy::match_single_binding)] match key { #[allow(clippy::redundant_clone)] - "just_symbol" => intermediate_rep.just_symbol.push(::from_str(val).map_err(|x| x.to_string())?), + "just_symbol" => intermediate_rep.just_symbol.push(::from_str(val).map_err(|x| x.to_string())?), "array_enum" => return std::result::Result::Err("Parsing a container in this style is not supported in EnumArrays".to_string()), "array_array_enum" => return std::result::Result::Err("Parsing a container in this style is not supported in EnumArrays".to_string()), _ => return std::result::Result::Err("Unexpected key while parsing EnumArrays".to_string()) @@ -2240,8 +3027,7 @@ impl std::convert::TryFrom> for hyper::heade match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for EnumArrays - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for EnumArrays - value: {hdr_value} is invalid {e}")) } } } @@ -2256,17 +3042,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into EnumArrays - {}", - value, err)) + format!("Unable to convert header value '{value}' into EnumArrays - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into EnumArrays - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl EnumArrays { /// Helper function to allow us to convert this model to an XML string. @@ -2282,82 +3108,556 @@ impl EnumArrays { /// which helps with FFI. #[allow(non_camel_case_types)] #[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] #[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] -pub enum EnumClass { - #[serde(rename = "_abc")] - Abc, - #[serde(rename = "-efg")] - Efg, - #[serde(rename = "(xyz)")] - LeftParenthesisXyzRightParenthesis, +pub enum EnumArraysArrayArrayEnumInnerInner { + #[serde(rename = "Cat")] + Cat, + #[serde(rename = "Dog")] + Dog, } -impl std::fmt::Display for EnumClass { +impl std::fmt::Display for EnumArraysArrayArrayEnumInnerInner { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match *self { - EnumClass::Abc => write!(f, "_abc"), - EnumClass::Efg => write!(f, "-efg"), - EnumClass::LeftParenthesisXyzRightParenthesis => write!(f, "(xyz)"), + EnumArraysArrayArrayEnumInnerInner::Cat => write!(f, "Cat"), + EnumArraysArrayArrayEnumInnerInner::Dog => write!(f, "Dog"), } } } -impl std::str::FromStr for EnumClass { +impl std::str::FromStr for EnumArraysArrayArrayEnumInnerInner { type Err = String; fn from_str(s: &str) -> std::result::Result { match s { - "_abc" => std::result::Result::Ok(EnumClass::Abc), - "-efg" => std::result::Result::Ok(EnumClass::Efg), - "(xyz)" => std::result::Result::Ok(EnumClass::LeftParenthesisXyzRightParenthesis), - _ => std::result::Result::Err(format!("Value not valid: {}", s)), + "Cat" => std::result::Result::Ok(EnumArraysArrayArrayEnumInnerInner::Cat), + "Dog" => std::result::Result::Ok(EnumArraysArrayArrayEnumInnerInner::Dog), + _ => std::result::Result::Err(format!("Value not valid: {s}")), } } } -impl EnumClass { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. - #[allow(dead_code)] - pub(crate) fn as_xml(&self) -> String { - serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for EnumArraysArrayArrayEnumInnerInner - value: {hdr_value} is invalid {e}")) + } } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] -#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct EnumTest { - // Note: inline enums are not fully supported by openapi-generator - #[serde(rename = "enum_string")] - #[serde(skip_serializing_if="Option::is_none")] - pub enum_string: Option, - - // Note: inline enums are not fully supported by openapi-generator - #[serde(rename = "enum_string_required")] - pub enum_string_required: String, +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; - // Note: inline enums are not fully supported by openapi-generator - #[serde(rename = "enum_integer")] - #[serde(skip_serializing_if="Option::is_none")] - pub enum_integer: Option, + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into EnumArraysArrayArrayEnumInnerInner - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} - // Note: inline enums are not fully supported by openapi-generator - #[serde(rename = "enum_number")] - #[serde(skip_serializing_if="Option::is_none")] - pub enum_number: Option, +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; - #[serde(rename = "outerEnum")] - #[serde(skip_serializing_if="Option::is_none")] - pub outer_enum: Option, + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; -impl EnumTest { - #[allow(clippy::new_without_default)] - pub fn new(enum_string_required: String, ) -> EnumTest { - EnumTest { + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into EnumArraysArrayArrayEnumInnerInner - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl EnumArraysArrayArrayEnumInnerInner { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum EnumArraysArrayEnumInner { + #[serde(rename = "fish")] + Fish, + #[serde(rename = "crab")] + Crab, +} + +impl std::fmt::Display for EnumArraysArrayEnumInner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + EnumArraysArrayEnumInner::Fish => write!(f, "fish"), + EnumArraysArrayEnumInner::Crab => write!(f, "crab"), + } + } +} + +impl std::str::FromStr for EnumArraysArrayEnumInner { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match s { + "fish" => std::result::Result::Ok(EnumArraysArrayEnumInner::Fish), + "crab" => std::result::Result::Ok(EnumArraysArrayEnumInner::Crab), + _ => std::result::Result::Err(format!("Value not valid: {s}")), + } + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for EnumArraysArrayEnumInner - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into EnumArraysArrayEnumInner - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into EnumArraysArrayEnumInner - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl EnumArraysArrayEnumInner { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum EnumArraysJustSymbol { + #[serde(rename = ">=")] + GreaterThanEqual, + #[serde(rename = "$")] + Dollar, +} + +impl std::fmt::Display for EnumArraysJustSymbol { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + EnumArraysJustSymbol::GreaterThanEqual => write!(f, ">="), + EnumArraysJustSymbol::Dollar => write!(f, "$"), + } + } +} + +impl std::str::FromStr for EnumArraysJustSymbol { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match s { + ">=" => std::result::Result::Ok(EnumArraysJustSymbol::GreaterThanEqual), + "$" => std::result::Result::Ok(EnumArraysJustSymbol::Dollar), + _ => std::result::Result::Err(format!("Value not valid: {s}")), + } + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for EnumArraysJustSymbol - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into EnumArraysJustSymbol - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into EnumArraysJustSymbol - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl EnumArraysJustSymbol { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum EnumClass { + #[serde(rename = "_abc")] + Abc, + #[serde(rename = "-efg")] + Efg, + #[serde(rename = "(xyz)")] + LeftParenthesisXyzRightParenthesis, +} + +impl std::fmt::Display for EnumClass { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + EnumClass::Abc => write!(f, "_abc"), + EnumClass::Efg => write!(f, "-efg"), + EnumClass::LeftParenthesisXyzRightParenthesis => write!(f, "(xyz)"), + } + } +} + +impl std::str::FromStr for EnumClass { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match s { + "_abc" => std::result::Result::Ok(EnumClass::Abc), + "-efg" => std::result::Result::Ok(EnumClass::Efg), + "(xyz)" => std::result::Result::Ok(EnumClass::LeftParenthesisXyzRightParenthesis), + _ => std::result::Result::Err(format!("Value not valid: {s}")), + } + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for EnumClass - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into EnumClass - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into EnumClass - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl EnumClass { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct EnumTest { + #[serde(rename = "enum_string")] + + #[cfg_attr(feature = "validate", validate)] + #[serde(skip_serializing_if="Option::is_none")] + pub enum_string: Option, + + #[serde(rename = "enum_string_required")] + + #[cfg_attr(feature = "validate", validate)] + pub enum_string_required: models::EnumTestEnumString, + + #[serde(rename = "enum_integer")] + + #[cfg_attr(feature = "validate", validate)] + #[serde(skip_serializing_if="Option::is_none")] + pub enum_integer: Option, + + #[serde(rename = "enum_number")] + + #[cfg_attr(feature = "validate", validate)] + #[serde(skip_serializing_if="Option::is_none")] + pub enum_number: Option, + + #[serde(rename = "outerEnum")] + + #[cfg_attr(feature = "validate", validate)] + #[serde(skip_serializing_if="Option::is_none")] + pub outer_enum: Option, + +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for EnumTest { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for EnumTest { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + + +impl EnumTest { + #[allow(clippy::new_without_default)] + pub fn new(enum_string_required: models::EnumTestEnumString, ) -> EnumTest { + EnumTest { enum_string: None, enum_string_required, enum_integer: None, @@ -2367,150 +3667,2850 @@ impl EnumTest { } } -/// Converts the EnumTest value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// Converts the EnumTest value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for EnumTest { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let params: Vec> = vec![ + // Skipping non-primitive type enum_string in query parameter serialization + // Skipping non-primitive type enum_string_required in query parameter serialization + // Skipping non-primitive type enum_integer in query parameter serialization + // Skipping non-primitive type enum_number in query parameter serialization + // Skipping non-primitive type outerEnum in query parameter serialization + ]; + + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a EnumTest value +/// as specified in +/// Should be implemented in a serde deserializer +impl std::str::FromStr for EnumTest { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + /// An intermediate representation of the struct to use for parsing. + #[derive(Default)] + #[allow(dead_code)] + struct IntermediateRep { + pub enum_string: Vec, + pub enum_string_required: Vec, + pub enum_integer: Vec, + pub enum_number: Vec, + pub outer_enum: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(','); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing EnumTest".to_string()) + }; + + if let Some(key) = key_result { + #[allow(clippy::match_single_binding)] + match key { + #[allow(clippy::redundant_clone)] + "enum_string" => intermediate_rep.enum_string.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "enum_string_required" => intermediate_rep.enum_string_required.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "enum_integer" => intermediate_rep.enum_integer.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "enum_number" => intermediate_rep.enum_number.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "outerEnum" => intermediate_rep.outer_enum.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing EnumTest".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(EnumTest { + enum_string: intermediate_rep.enum_string.into_iter().next(), + enum_string_required: intermediate_rep.enum_string_required.into_iter().next().ok_or_else(|| "enum_string_required missing in EnumTest".to_string())?, + enum_integer: intermediate_rep.enum_integer.into_iter().next(), + enum_number: intermediate_rep.enum_number.into_iter().next(), + outer_enum: intermediate_rep.outer_enum.into_iter().next(), + }) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for EnumTest - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into EnumTest - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into EnumTest - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl EnumTest { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(i32)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde_repr::Serialize_repr, serde_repr::Deserialize_repr, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum EnumTestEnumInteger { + Variant1 = 1, + Variant12 = -1, +} + +impl std::fmt::Display for EnumTestEnumInteger { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", *self as i32) + } +} + +impl std::str::FromStr for EnumTestEnumInteger { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match s.parse::() { + std::result::Result::Ok(1) => std::result::Result::Ok(EnumTestEnumInteger::Variant1), + std::result::Result::Ok(-1) => std::result::Result::Ok(EnumTestEnumInteger::Variant12), + _ => std::result::Result::Err(format!("Value not valid: {s}")), + } + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for EnumTestEnumInteger - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into EnumTestEnumInteger - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into EnumTestEnumInteger - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl EnumTestEnumInteger { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum EnumTestEnumString { + #[serde(rename = "UPPER")] + Upper, + #[serde(rename = "lower")] + Lower, + #[serde(rename = "")] + Empty, +} + +impl std::fmt::Display for EnumTestEnumString { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + EnumTestEnumString::Upper => write!(f, "UPPER"), + EnumTestEnumString::Lower => write!(f, "lower"), + EnumTestEnumString::Empty => write!(f, ""), + } + } +} + +impl std::str::FromStr for EnumTestEnumString { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match s { + "UPPER" => std::result::Result::Ok(EnumTestEnumString::Upper), + "lower" => std::result::Result::Ok(EnumTestEnumString::Lower), + "" => std::result::Result::Ok(EnumTestEnumString::Empty), + _ => std::result::Result::Err(format!("Value not valid: {s}")), + } + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for EnumTestEnumString - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into EnumTestEnumString - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into EnumTestEnumString - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl EnumTestEnumString { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum FindPetsByStatusStatusParameterInner { + #[serde(rename = "available")] + Available, + #[serde(rename = "pending")] + Pending, + #[serde(rename = "sold")] + Sold, +} + +impl std::fmt::Display for FindPetsByStatusStatusParameterInner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + FindPetsByStatusStatusParameterInner::Available => write!(f, "available"), + FindPetsByStatusStatusParameterInner::Pending => write!(f, "pending"), + FindPetsByStatusStatusParameterInner::Sold => write!(f, "sold"), + } + } +} + +impl std::str::FromStr for FindPetsByStatusStatusParameterInner { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match s { + "available" => std::result::Result::Ok(FindPetsByStatusStatusParameterInner::Available), + "pending" => std::result::Result::Ok(FindPetsByStatusStatusParameterInner::Pending), + "sold" => std::result::Result::Ok(FindPetsByStatusStatusParameterInner::Sold), + _ => std::result::Result::Err(format!("Value not valid: {s}")), + } + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for FindPetsByStatusStatusParameterInner - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into FindPetsByStatusStatusParameterInner - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into FindPetsByStatusStatusParameterInner - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl FindPetsByStatusStatusParameterInner { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct FormatTest { + #[serde(rename = "integer")] + #[cfg_attr(not(feature = "validate"), validate( + range(min = 10u8, max = 100u8), + ))] + #[cfg_attr(feature = "validate", validate(minimum = 10u8))] + #[cfg_attr(feature = "validate", validate(maximum = 100u8))] + + #[serde(skip_serializing_if="Option::is_none")] + pub integer: Option, + + #[serde(rename = "int32")] + #[cfg_attr(not(feature = "validate"), validate( + range(min = 20u32, max = 200u32), + ))] + #[cfg_attr(feature = "validate", validate(minimum = 20u32))] + #[cfg_attr(feature = "validate", validate(maximum = 200u32))] + + #[serde(skip_serializing_if="Option::is_none")] + pub int32: Option, + + #[serde(rename = "int64")] + + #[serde(skip_serializing_if="Option::is_none")] + pub int64: Option, + + #[serde(rename = "number")] + #[cfg_attr(not(feature = "validate"), validate( + range(min = 32.1f64, max = 543.2f64), + ))] + #[cfg_attr(feature = "validate", validate(minimum = 32.1f64))] + #[cfg_attr(feature = "validate", validate(maximum = 543.2f64))] + + pub number: f64, + + #[serde(rename = "float")] + #[cfg_attr(not(feature = "validate"), validate( + range(min = 54.3f32, max = 987.6f32), + ))] + #[cfg_attr(feature = "validate", validate(minimum = 54.3f32))] + #[cfg_attr(feature = "validate", validate(maximum = 987.6f32))] + + #[serde(skip_serializing_if="Option::is_none")] + pub float: Option, + + #[serde(rename = "double")] + #[cfg_attr(not(feature = "validate"), validate( + range(min = 67.8f64, max = 123.4f64), + ))] + #[cfg_attr(feature = "validate", validate(minimum = 67.8f64))] + #[cfg_attr(feature = "validate", validate(maximum = 123.4f64))] + + #[serde(skip_serializing_if="Option::is_none")] + pub double: Option, + + #[serde(rename = "string")] + #[cfg_attr(not(feature = "validate"), validate( + regex(path = *RE_FORMATTEST_STRING), + ))] + #[cfg_attr(feature = "validate", validate(pattern = r"/[a-z]/i"))] + + #[serde(skip_serializing_if="Option::is_none")] + pub string: Option, + + #[serde(rename = "byte")] + #[cfg_attr(not(feature = "validate"), validate( + custom(function = "validate_byte_formattest_byte") + ))] + + pub byte: swagger::ByteArray, + + #[serde(rename = "binary")] + + #[serde(skip_serializing_if="Option::is_none")] + pub binary: Option, + + #[serde(rename = "date")] + + pub date: chrono::naive::NaiveDate, + + #[serde(rename = "dateTime")] + + #[serde(skip_serializing_if="Option::is_none")] + pub date_time: Option>, + + #[serde(rename = "uuid")] + + #[serde(skip_serializing_if="Option::is_none")] + pub uuid: Option, + + #[serde(rename = "password")] + #[cfg_attr(not(feature = "validate"), validate( + length(min = 10, max = 64), + ))] + #[cfg_attr(feature = "validate", validate(min_length = 10))] + #[cfg_attr(feature = "validate", validate(max_length = 64))] + + pub password: String, + +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for FormatTest { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for FormatTest { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +lazy_static::lazy_static! { + static ref RE_FORMATTEST_STRING: regex::Regex = regex::Regex::new(r"/[a-z]/i").unwrap(); +} +lazy_static::lazy_static! { + static ref RE_FORMATTEST_BYTE: regex::bytes::Regex = regex::bytes::Regex::new(r"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$").unwrap(); +} +#[cfg(not(feature = "validate"))] +fn validate_byte_formattest_byte( + b: &swagger::ByteArray +) -> Result<(), validator::ValidationError> { + if !RE_FORMATTEST_BYTE.is_match(b) { + return Err(validator::ValidationError::new("Character not allowed")); + } + Ok(()) +} + +impl FormatTest { + #[allow(clippy::new_without_default)] + pub fn new(number: f64, byte: swagger::ByteArray, date: chrono::naive::NaiveDate, password: String, ) -> FormatTest { + FormatTest { + integer: None, + int32: None, + int64: None, + number, + float: None, + double: None, + string: None, + byte, + binary: None, + date, + date_time: None, + uuid: None, + password, + } + } +} + +/// Converts the FormatTest value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for FormatTest { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let params: Vec> = vec![ + self.integer.as_ref().map(|integer| { + [ + "integer".to_string(), + integer.to_string(), + ].join(",") + }), + self.int32.as_ref().map(|int32| { + [ + "int32".to_string(), + int32.to_string(), + ].join(",") + }), + self.int64.as_ref().map(|int64| { + [ + "int64".to_string(), + int64.to_string(), + ].join(",") + }), + Some("number".to_string()), + Some(self.number.to_string()), + self.float.as_ref().map(|float| { + [ + "float".to_string(), + float.to_string(), + ].join(",") + }), + self.double.as_ref().map(|double| { + [ + "double".to_string(), + double.to_string(), + ].join(",") + }), + self.string.as_ref().map(|string| { + [ + "string".to_string(), + string.to_string(), + ].join(",") + }), + // Skipping byte array byte in query parameter serialization + // Skipping binary data binary in query parameter serialization + // Skipping non-primitive type date in query parameter serialization + // Skipping non-primitive type dateTime in query parameter serialization + // Skipping non-primitive type uuid in query parameter serialization + Some("password".to_string()), + Some(self.password.to_string()), + ]; + + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a FormatTest value +/// as specified in +/// Should be implemented in a serde deserializer +impl std::str::FromStr for FormatTest { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + /// An intermediate representation of the struct to use for parsing. + #[derive(Default)] + #[allow(dead_code)] + struct IntermediateRep { + pub integer: Vec, + pub int32: Vec, + pub int64: Vec, + pub number: Vec, + pub float: Vec, + pub double: Vec, + pub string: Vec, + pub byte: Vec, + pub binary: Vec, + pub date: Vec, + pub date_time: Vec>, + pub uuid: Vec, + pub password: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(','); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing FormatTest".to_string()) + }; + + if let Some(key) = key_result { + #[allow(clippy::match_single_binding)] + match key { + #[allow(clippy::redundant_clone)] + "integer" => intermediate_rep.integer.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "int32" => intermediate_rep.int32.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "int64" => intermediate_rep.int64.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "number" => intermediate_rep.number.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "float" => intermediate_rep.float.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "double" => intermediate_rep.double.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "string" => intermediate_rep.string.push(::from_str(val).map_err(|x| x.to_string())?), + "byte" => return std::result::Result::Err("Parsing binary data in this style is not supported in FormatTest".to_string()), + "binary" => return std::result::Result::Err("Parsing binary data in this style is not supported in FormatTest".to_string()), + #[allow(clippy::redundant_clone)] + "date" => intermediate_rep.date.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "dateTime" => intermediate_rep.date_time.push( as std::str::FromStr>::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "uuid" => intermediate_rep.uuid.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "password" => intermediate_rep.password.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing FormatTest".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(FormatTest { + integer: intermediate_rep.integer.into_iter().next(), + int32: intermediate_rep.int32.into_iter().next(), + int64: intermediate_rep.int64.into_iter().next(), + number: intermediate_rep.number.into_iter().next().ok_or_else(|| "number missing in FormatTest".to_string())?, + float: intermediate_rep.float.into_iter().next(), + double: intermediate_rep.double.into_iter().next(), + string: intermediate_rep.string.into_iter().next(), + byte: intermediate_rep.byte.into_iter().next().ok_or_else(|| "byte missing in FormatTest".to_string())?, + binary: intermediate_rep.binary.into_iter().next(), + date: intermediate_rep.date.into_iter().next().ok_or_else(|| "date missing in FormatTest".to_string())?, + date_time: intermediate_rep.date_time.into_iter().next(), + uuid: intermediate_rep.uuid.into_iter().next(), + password: intermediate_rep.password.into_iter().next().ok_or_else(|| "password missing in FormatTest".to_string())?, + }) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for FormatTest - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into FormatTest - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into FormatTest - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl FormatTest { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct HasOnlyReadOnly { + #[serde(rename = "bar")] + + #[serde(skip_serializing_if="Option::is_none")] + pub bar: Option, + + #[serde(rename = "foo")] + + #[serde(skip_serializing_if="Option::is_none")] + pub foo: Option, + +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for HasOnlyReadOnly { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for HasOnlyReadOnly { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + + +impl HasOnlyReadOnly { + #[allow(clippy::new_without_default)] + pub fn new() -> HasOnlyReadOnly { + HasOnlyReadOnly { + bar: None, + foo: None, + } + } +} + +/// Converts the HasOnlyReadOnly value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for HasOnlyReadOnly { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let params: Vec> = vec![ + self.bar.as_ref().map(|bar| { + [ + "bar".to_string(), + bar.to_string(), + ].join(",") + }), + self.foo.as_ref().map(|foo| { + [ + "foo".to_string(), + foo.to_string(), + ].join(",") + }), + ]; + + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a HasOnlyReadOnly value +/// as specified in +/// Should be implemented in a serde deserializer +impl std::str::FromStr for HasOnlyReadOnly { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + /// An intermediate representation of the struct to use for parsing. + #[derive(Default)] + #[allow(dead_code)] + struct IntermediateRep { + pub bar: Vec, + pub foo: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(','); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing HasOnlyReadOnly".to_string()) + }; + + if let Some(key) = key_result { + #[allow(clippy::match_single_binding)] + match key { + #[allow(clippy::redundant_clone)] + "bar" => intermediate_rep.bar.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "foo" => intermediate_rep.foo.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing HasOnlyReadOnly".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(HasOnlyReadOnly { + bar: intermediate_rep.bar.into_iter().next(), + foo: intermediate_rep.foo.into_iter().next(), + }) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for HasOnlyReadOnly - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into HasOnlyReadOnly - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into HasOnlyReadOnly - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl HasOnlyReadOnly { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct List { + #[serde(rename = "123-list")] + + #[serde(skip_serializing_if="Option::is_none")] + pub param_123_list: Option, + +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for List { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for List { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + + +impl List { + #[allow(clippy::new_without_default)] + pub fn new() -> List { + List { + param_123_list: None, + } + } +} + +/// Converts the List value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for List { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let params: Vec> = vec![ + self.param_123_list.as_ref().map(|param_123_list| { + [ + "123-list".to_string(), + param_123_list.to_string(), + ].join(",") + }), + ]; + + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a List value +/// as specified in +/// Should be implemented in a serde deserializer +impl std::str::FromStr for List { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + /// An intermediate representation of the struct to use for parsing. + #[derive(Default)] + #[allow(dead_code)] + struct IntermediateRep { + pub param_123_list: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(','); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing List".to_string()) + }; + + if let Some(key) = key_result { + #[allow(clippy::match_single_binding)] + match key { + #[allow(clippy::redundant_clone)] + "123-list" => intermediate_rep.param_123_list.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing List".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(List { + param_123_list: intermediate_rep.param_123_list.into_iter().next(), + }) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for List - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into List - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into List - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl List { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct MapTest { + #[serde(rename = "map_map_of_string")] + + #[serde(skip_serializing_if="Option::is_none")] + pub map_map_of_string: Option>>, + + #[serde(rename = "map_map_of_enum")] + + #[cfg_attr(feature = "validate", validate)] + #[serde(skip_serializing_if="Option::is_none")] + pub map_map_of_enum: Option>>, + + #[serde(rename = "map_of_enum_string")] + + #[cfg_attr(feature = "validate", validate)] + #[serde(skip_serializing_if="Option::is_none")] + pub map_of_enum_string: Option>, + +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for MapTest { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for MapTest { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + + +impl MapTest { + #[allow(clippy::new_without_default)] + pub fn new() -> MapTest { + MapTest { + map_map_of_string: None, + map_map_of_enum: None, + map_of_enum_string: None, + } + } +} + +/// Converts the MapTest value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for MapTest { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let params: Vec> = vec![ + // Skipping map map_map_of_string in query parameter serialization + // Skipping map map_map_of_enum in query parameter serialization + // Skipping map map_of_enum_string in query parameter serialization + ]; + + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a MapTest value +/// as specified in +/// Should be implemented in a serde deserializer +impl std::str::FromStr for MapTest { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + /// An intermediate representation of the struct to use for parsing. + #[derive(Default)] + #[allow(dead_code)] + struct IntermediateRep { + pub map_map_of_string: Vec>>, + pub map_map_of_enum: Vec>>, + pub map_of_enum_string: Vec>, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(','); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing MapTest".to_string()) + }; + + if let Some(key) = key_result { + #[allow(clippy::match_single_binding)] + match key { + "map_map_of_string" => return std::result::Result::Err("Parsing a container in this style is not supported in MapTest".to_string()), + "map_map_of_enum" => return std::result::Result::Err("Parsing a container in this style is not supported in MapTest".to_string()), + "map_of_enum_string" => return std::result::Result::Err("Parsing a container in this style is not supported in MapTest".to_string()), + _ => return std::result::Result::Err("Unexpected key while parsing MapTest".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(MapTest { + map_map_of_string: intermediate_rep.map_map_of_string.into_iter().next(), + map_map_of_enum: intermediate_rep.map_map_of_enum.into_iter().next(), + map_of_enum_string: intermediate_rep.map_of_enum_string.into_iter().next(), + }) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for MapTest - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into MapTest - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into MapTest - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl MapTest { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum MapTestMapMapOfEnumValueValue { + #[serde(rename = "UPPER")] + Upper, + #[serde(rename = "lower")] + Lower, +} + +impl std::fmt::Display for MapTestMapMapOfEnumValueValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + MapTestMapMapOfEnumValueValue::Upper => write!(f, "UPPER"), + MapTestMapMapOfEnumValueValue::Lower => write!(f, "lower"), + } + } +} + +impl std::str::FromStr for MapTestMapMapOfEnumValueValue { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match s { + "UPPER" => std::result::Result::Ok(MapTestMapMapOfEnumValueValue::Upper), + "lower" => std::result::Result::Ok(MapTestMapMapOfEnumValueValue::Lower), + _ => std::result::Result::Err(format!("Value not valid: {s}")), + } + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for MapTestMapMapOfEnumValueValue - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into MapTestMapMapOfEnumValueValue - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into MapTestMapMapOfEnumValueValue - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl MapTestMapMapOfEnumValueValue { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct MixedPropertiesAndAdditionalPropertiesClass { + #[serde(rename = "uuid")] + + #[serde(skip_serializing_if="Option::is_none")] + pub uuid: Option, + + #[serde(rename = "dateTime")] + + #[serde(skip_serializing_if="Option::is_none")] + pub date_time: Option>, + + #[serde(rename = "map")] + + #[cfg_attr(feature = "validate", validate)] + #[serde(skip_serializing_if="Option::is_none")] + pub map: Option>, + +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for MixedPropertiesAndAdditionalPropertiesClass { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for MixedPropertiesAndAdditionalPropertiesClass { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + + +impl MixedPropertiesAndAdditionalPropertiesClass { + #[allow(clippy::new_without_default)] + pub fn new() -> MixedPropertiesAndAdditionalPropertiesClass { + MixedPropertiesAndAdditionalPropertiesClass { + uuid: None, + date_time: None, + map: None, + } + } +} + +/// Converts the MixedPropertiesAndAdditionalPropertiesClass value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for MixedPropertiesAndAdditionalPropertiesClass { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let params: Vec> = vec![ + // Skipping non-primitive type uuid in query parameter serialization + // Skipping non-primitive type dateTime in query parameter serialization + // Skipping map map in query parameter serialization + ]; + + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a MixedPropertiesAndAdditionalPropertiesClass value +/// as specified in +/// Should be implemented in a serde deserializer +impl std::str::FromStr for MixedPropertiesAndAdditionalPropertiesClass { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + /// An intermediate representation of the struct to use for parsing. + #[derive(Default)] + #[allow(dead_code)] + struct IntermediateRep { + pub uuid: Vec, + pub date_time: Vec>, + pub map: Vec>, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(','); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing MixedPropertiesAndAdditionalPropertiesClass".to_string()) + }; + + if let Some(key) = key_result { + #[allow(clippy::match_single_binding)] + match key { + #[allow(clippy::redundant_clone)] + "uuid" => intermediate_rep.uuid.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "dateTime" => intermediate_rep.date_time.push( as std::str::FromStr>::from_str(val).map_err(|x| x.to_string())?), + "map" => return std::result::Result::Err("Parsing a container in this style is not supported in MixedPropertiesAndAdditionalPropertiesClass".to_string()), + _ => return std::result::Result::Err("Unexpected key while parsing MixedPropertiesAndAdditionalPropertiesClass".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(MixedPropertiesAndAdditionalPropertiesClass { + uuid: intermediate_rep.uuid.into_iter().next(), + date_time: intermediate_rep.date_time.into_iter().next(), + map: intermediate_rep.map.into_iter().next(), + }) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for MixedPropertiesAndAdditionalPropertiesClass - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into MixedPropertiesAndAdditionalPropertiesClass - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into MixedPropertiesAndAdditionalPropertiesClass - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl MixedPropertiesAndAdditionalPropertiesClass { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +/// Model for testing model name starting with number +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +#[serde(rename = "Name")] +pub struct Model200Response { + #[serde(rename = "name")] + + #[serde(skip_serializing_if="Option::is_none")] + pub name: Option, + + #[serde(rename = "class")] + + #[serde(skip_serializing_if="Option::is_none")] + pub class: Option, + +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for Model200Response { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for Model200Response { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + + +impl Model200Response { + #[allow(clippy::new_without_default)] + pub fn new() -> Model200Response { + Model200Response { + name: None, + class: None, + } + } +} + +/// Converts the Model200Response value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for Model200Response { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let params: Vec> = vec![ + self.name.as_ref().map(|name| { + [ + "name".to_string(), + name.to_string(), + ].join(",") + }), + self.class.as_ref().map(|class| { + [ + "class".to_string(), + class.to_string(), + ].join(",") + }), + ]; + + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a Model200Response value +/// as specified in +/// Should be implemented in a serde deserializer +impl std::str::FromStr for Model200Response { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + /// An intermediate representation of the struct to use for parsing. + #[derive(Default)] + #[allow(dead_code)] + struct IntermediateRep { + pub name: Vec, + pub class: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(','); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing Model200Response".to_string()) + }; + + if let Some(key) = key_result { + #[allow(clippy::match_single_binding)] + match key { + #[allow(clippy::redundant_clone)] + "name" => intermediate_rep.name.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "class" => intermediate_rep.class.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing Model200Response".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(Model200Response { + name: intermediate_rep.name.into_iter().next(), + class: intermediate_rep.class.into_iter().next(), + }) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for Model200Response - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into Model200Response - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Model200Response - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl Model200Response { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +/// Model for testing model name same as property name +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +#[serde(rename = "Name")] +pub struct Name { + #[serde(rename = "name")] + + pub name: i32, + + #[serde(rename = "snake_case")] + + #[serde(skip_serializing_if="Option::is_none")] + pub snake_case: Option, + + #[serde(rename = "property")] + + #[serde(skip_serializing_if="Option::is_none")] + pub property: Option, + + #[serde(rename = "123Number")] + + #[serde(skip_serializing_if="Option::is_none")] + pub param_123_number: Option, + +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for Name { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for Name { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + + +impl Name { + #[allow(clippy::new_without_default)] + pub fn new(name: i32, ) -> Name { + Name { + name, + snake_case: None, + property: None, + param_123_number: None, + } + } +} + +/// Converts the Name value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for Name { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let params: Vec> = vec![ + Some("name".to_string()), + Some(self.name.to_string()), + self.snake_case.as_ref().map(|snake_case| { + [ + "snake_case".to_string(), + snake_case.to_string(), + ].join(",") + }), + self.property.as_ref().map(|property| { + [ + "property".to_string(), + property.to_string(), + ].join(",") + }), + self.param_123_number.as_ref().map(|param_123_number| { + [ + "123Number".to_string(), + param_123_number.to_string(), + ].join(",") + }), + ]; + + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a Name value +/// as specified in +/// Should be implemented in a serde deserializer +impl std::str::FromStr for Name { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + /// An intermediate representation of the struct to use for parsing. + #[derive(Default)] + #[allow(dead_code)] + struct IntermediateRep { + pub name: Vec, + pub snake_case: Vec, + pub property: Vec, + pub param_123_number: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(','); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing Name".to_string()) + }; + + if let Some(key) = key_result { + #[allow(clippy::match_single_binding)] + match key { + #[allow(clippy::redundant_clone)] + "name" => intermediate_rep.name.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "snake_case" => intermediate_rep.snake_case.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "property" => intermediate_rep.property.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "123Number" => intermediate_rep.param_123_number.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing Name".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(Name { + name: intermediate_rep.name.into_iter().next().ok_or_else(|| "name missing in Name".to_string())?, + snake_case: intermediate_rep.snake_case.into_iter().next(), + property: intermediate_rep.property.into_iter().next(), + param_123_number: intermediate_rep.param_123_number.into_iter().next(), + }) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for Name - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into Name - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Name - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl Name { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct NumberOnly { + #[serde(rename = "JustNumber")] + + #[serde(skip_serializing_if="Option::is_none")] + pub just_number: Option, + +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for NumberOnly { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for NumberOnly { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + + +impl NumberOnly { + #[allow(clippy::new_without_default)] + pub fn new() -> NumberOnly { + NumberOnly { + just_number: None, + } + } +} + +/// Converts the NumberOnly value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for NumberOnly { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let params: Vec> = vec![ + self.just_number.as_ref().map(|just_number| { + [ + "JustNumber".to_string(), + just_number.to_string(), + ].join(",") + }), + ]; + + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) + } +} + +/// Converts Query Parameters representation (style=form, explode=false) to a NumberOnly value +/// as specified in +/// Should be implemented in a serde deserializer +impl std::str::FromStr for NumberOnly { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + /// An intermediate representation of the struct to use for parsing. + #[derive(Default)] + #[allow(dead_code)] + struct IntermediateRep { + pub just_number: Vec, + } + + let mut intermediate_rep = IntermediateRep::default(); + + // Parse into intermediate representation + let mut string_iter = s.split(','); + let mut key_result = string_iter.next(); + + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing NumberOnly".to_string()) + }; + + if let Some(key) = key_result { + #[allow(clippy::match_single_binding)] + match key { + #[allow(clippy::redundant_clone)] + "JustNumber" => intermediate_rep.just_number.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing NumberOnly".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(NumberOnly { + just_number: intermediate_rep.just_number.into_iter().next(), + }) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for NumberOnly - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into NumberOnly - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into NumberOnly - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl NumberOnly { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct ObjectContainingObjectWithOnlyAdditionalProperties { + #[serde(rename = "inner")] + + #[cfg_attr(feature = "validate", validate)] + #[serde(skip_serializing_if="Option::is_none")] + pub inner: Option, + +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for ObjectContainingObjectWithOnlyAdditionalProperties { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for ObjectContainingObjectWithOnlyAdditionalProperties { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + + +impl ObjectContainingObjectWithOnlyAdditionalProperties { + #[allow(clippy::new_without_default)] + pub fn new() -> ObjectContainingObjectWithOnlyAdditionalProperties { + ObjectContainingObjectWithOnlyAdditionalProperties { + inner: None, + } + } +} + +/// Converts the ObjectContainingObjectWithOnlyAdditionalProperties value to the Query Parameters representation (style=form, explode=false) +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for EnumTest { - fn to_string(&self) -> String { +impl std::fmt::Display for ObjectContainingObjectWithOnlyAdditionalProperties { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ + // Skipping non-primitive type inner in query parameter serialization + ]; - self.enum_string.as_ref().map(|enum_string| { - [ - "enum_string".to_string(), - enum_string.to_string(), - ].join(",") - }), + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) + } +} +/// Converts Query Parameters representation (style=form, explode=false) to a ObjectContainingObjectWithOnlyAdditionalProperties value +/// as specified in +/// Should be implemented in a serde deserializer +impl std::str::FromStr for ObjectContainingObjectWithOnlyAdditionalProperties { + type Err = String; - Some("enum_string_required".to_string()), - Some(self.enum_string_required.to_string()), + fn from_str(s: &str) -> std::result::Result { + /// An intermediate representation of the struct to use for parsing. + #[derive(Default)] + #[allow(dead_code)] + struct IntermediateRep { + pub inner: Vec, + } + let mut intermediate_rep = IntermediateRep::default(); - self.enum_integer.as_ref().map(|enum_integer| { - [ - "enum_integer".to_string(), - enum_integer.to_string(), - ].join(",") - }), + // Parse into intermediate representation + let mut string_iter = s.split(','); + let mut key_result = string_iter.next(); + while key_result.is_some() { + let val = match string_iter.next() { + Some(x) => x, + None => return std::result::Result::Err("Missing value while parsing ObjectContainingObjectWithOnlyAdditionalProperties".to_string()) + }; - self.enum_number.as_ref().map(|enum_number| { - [ - "enum_number".to_string(), - enum_number.to_string(), - ].join(",") - }), + if let Some(key) = key_result { + #[allow(clippy::match_single_binding)] + match key { + #[allow(clippy::redundant_clone)] + "inner" => intermediate_rep.inner.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing ObjectContainingObjectWithOnlyAdditionalProperties".to_string()) + } + } + + // Get the next key + key_result = string_iter.next(); + } + + // Use the intermediate representation to return the struct + std::result::Result::Ok(ObjectContainingObjectWithOnlyAdditionalProperties { + inner: intermediate_rep.inner.into_iter().next(), + }) + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for ObjectContainingObjectWithOnlyAdditionalProperties - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into ObjectContainingObjectWithOnlyAdditionalProperties - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ObjectContainingObjectWithOnlyAdditionalProperties - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl ObjectContainingObjectWithOnlyAdditionalProperties { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] +pub struct ObjectWithOnlyAdditionalProperties( + std::collections::HashMap +); + +impl std::convert::From> for ObjectWithOnlyAdditionalProperties { + fn from(x: std::collections::HashMap) -> Self { + ObjectWithOnlyAdditionalProperties(x) + } +} + +impl std::convert::From for std::collections::HashMap { + fn from(x: ObjectWithOnlyAdditionalProperties) -> Self { + x.0 + } +} + +impl std::ops::Deref for ObjectWithOnlyAdditionalProperties { + type Target = std::collections::HashMap; + fn deref(&self) -> &std::collections::HashMap { + &self.0 + } +} - // Skipping outerEnum in query parameter serialization +impl std::ops::DerefMut for ObjectWithOnlyAdditionalProperties { + fn deref_mut(&mut self) -> &mut std::collections::HashMap { + &mut self.0 + } +} - ]; +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for ObjectWithOnlyAdditionalProperties { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} - params.into_iter().flatten().collect::>().join(",") +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for ObjectWithOnlyAdditionalProperties { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} +/// Converts the ObjectWithOnlyAdditionalProperties value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for ObjectWithOnlyAdditionalProperties { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Display for this model is not supported + write!(f, "") } } -/// Converts Query Parameters representation (style=form, explode=false) to a EnumTest value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// Converts Query Parameters representation (style=form, explode=false) to a ObjectWithOnlyAdditionalProperties value +/// as specified in /// Should be implemented in a serde deserializer -impl std::str::FromStr for EnumTest { - type Err = String; +impl ::std::str::FromStr for ObjectWithOnlyAdditionalProperties { + type Err = &'static str; fn from_str(s: &str) -> std::result::Result { - /// An intermediate representation of the struct to use for parsing. - #[derive(Default)] - #[allow(dead_code)] - struct IntermediateRep { - pub enum_string: Vec, - pub enum_string_required: Vec, - pub enum_integer: Vec, - pub enum_number: Vec, - pub outer_enum: Vec, - } - - let mut intermediate_rep = IntermediateRep::default(); - - // Parse into intermediate representation - let mut string_iter = s.split(','); - let mut key_result = string_iter.next(); - - while key_result.is_some() { - let val = match string_iter.next() { - Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing EnumTest".to_string()) - }; - - if let Some(key) = key_result { - #[allow(clippy::match_single_binding)] - match key { - #[allow(clippy::redundant_clone)] - "enum_string" => intermediate_rep.enum_string.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "enum_string_required" => intermediate_rep.enum_string_required.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "enum_integer" => intermediate_rep.enum_integer.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "enum_number" => intermediate_rep.enum_number.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "outerEnum" => intermediate_rep.outer_enum.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing EnumTest".to_string()) - } - } - - // Get the next key - key_result = string_iter.next(); - } - - // Use the intermediate representation to return the struct - std::result::Result::Ok(EnumTest { - enum_string: intermediate_rep.enum_string.into_iter().next(), - enum_string_required: intermediate_rep.enum_string_required.into_iter().next().ok_or_else(|| "enum_string_required missing in EnumTest".to_string())?, - enum_integer: intermediate_rep.enum_integer.into_iter().next(), - enum_number: intermediate_rep.enum_number.into_iter().next(), - outer_enum: intermediate_rep.outer_enum.into_iter().next(), - }) + std::result::Result::Err("Parsing ObjectWithOnlyAdditionalProperties is not supported") } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for EnumTest - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for ObjectWithOnlyAdditionalProperties - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into EnumTest - {}", - value, err)) + format!("Unable to convert header value '{value}' into ObjectWithOnlyAdditionalProperties - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); -impl EnumTest { + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ObjectWithOnlyAdditionalProperties - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl ObjectWithOnlyAdditionalProperties { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -2519,203 +6519,120 @@ impl EnumTest { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct FormatTest { - #[serde(rename = "integer")] - #[validate( - range(min = 10, max = 100), - )] - #[serde(skip_serializing_if="Option::is_none")] - pub integer: Option, - - #[serde(rename = "int32")] - #[validate( - range(min = 20, max = 200), - )] - #[serde(skip_serializing_if="Option::is_none")] - pub int32: Option, +#[serde(rename = "Order")] +pub struct Order { + #[serde(rename = "id")] - #[serde(rename = "int64")] #[serde(skip_serializing_if="Option::is_none")] - pub int64: Option, + pub id: Option, - #[serde(rename = "number")] - #[validate( - range(min = 32.1, max = 543.2), - )] - pub number: f64, + #[serde(rename = "petId")] - #[serde(rename = "float")] - #[validate( - range(min = 54.3, max = 987.6), - )] #[serde(skip_serializing_if="Option::is_none")] - pub float: Option, + pub pet_id: Option, - #[serde(rename = "double")] - #[validate( - range(min = 67.8, max = 123.4), - )] - #[serde(skip_serializing_if="Option::is_none")] - pub double: Option, + #[serde(rename = "quantity")] - #[serde(rename = "string")] - #[validate( - regex = "RE_FORMATTEST_STRING", - )] #[serde(skip_serializing_if="Option::is_none")] - pub string: Option, + pub quantity: Option, - #[serde(rename = "byte")] - #[validate( - custom ="validate_byte_formattest_byte" - )] - pub byte: swagger::ByteArray, + #[serde(rename = "shipDate")] - #[serde(rename = "binary")] #[serde(skip_serializing_if="Option::is_none")] - pub binary: Option, + pub ship_date: Option>, - #[serde(rename = "date")] - pub date: chrono::naive::NaiveDate, + #[serde(rename = "status")] - #[serde(rename = "dateTime")] + #[cfg_attr(feature = "validate", validate)] #[serde(skip_serializing_if="Option::is_none")] - pub date_time: Option>, + pub status: Option, - #[serde(rename = "uuid")] - #[serde(skip_serializing_if="Option::is_none")] - pub uuid: Option, + #[serde(rename = "complete")] - #[serde(rename = "password")] - #[validate( - length(min = 10, max = 64), - )] - pub password: String, + #[serde(skip_serializing_if="Option::is_none")] + pub complete: Option, } -lazy_static::lazy_static! { - static ref RE_FORMATTEST_STRING: regex::Regex = regex::Regex::new(r"/[a-z]/i").unwrap(); -} -lazy_static::lazy_static! { - static ref RE_FORMATTEST_BYTE: regex::bytes::Regex = regex::bytes::Regex::new(r"^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$").unwrap(); +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for Order { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } } -fn validate_byte_formattest_byte( - b: &swagger::ByteArray -) -> Result<(), validator::ValidationError> { - if !RE_FORMATTEST_BYTE.is_match(b) { - return Err(validator::ValidationError::new("Character not allowed")); + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for Order { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) } - Ok(()) } -impl FormatTest { + +impl Order { #[allow(clippy::new_without_default)] - pub fn new(number: f64, byte: swagger::ByteArray, date: chrono::naive::NaiveDate, password: String, ) -> FormatTest { - FormatTest { - integer: None, - int32: None, - int64: None, - number, - float: None, - double: None, - string: None, - byte, - binary: None, - date, - date_time: None, - uuid: None, - password, + pub fn new() -> Order { + Order { + id: None, + pet_id: None, + quantity: None, + ship_date: None, + status: None, + complete: Some(false), } } } -/// Converts the FormatTest value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// Converts the Order value to the Query Parameters representation (style=form, explode=false) +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for FormatTest { - fn to_string(&self) -> String { +impl std::fmt::Display for Order { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - - self.integer.as_ref().map(|integer| { - [ - "integer".to_string(), - integer.to_string(), - ].join(",") - }), - - - self.int32.as_ref().map(|int32| { - [ - "int32".to_string(), - int32.to_string(), - ].join(",") - }), - - - self.int64.as_ref().map(|int64| { + self.id.as_ref().map(|id| { [ - "int64".to_string(), - int64.to_string(), + "id".to_string(), + id.to_string(), ].join(",") }), - - - Some("number".to_string()), - Some(self.number.to_string()), - - - self.float.as_ref().map(|float| { + self.pet_id.as_ref().map(|pet_id| { [ - "float".to_string(), - float.to_string(), + "petId".to_string(), + pet_id.to_string(), ].join(",") }), - - - self.double.as_ref().map(|double| { + self.quantity.as_ref().map(|quantity| { [ - "double".to_string(), - double.to_string(), + "quantity".to_string(), + quantity.to_string(), ].join(",") }), - - - self.string.as_ref().map(|string| { + // Skipping non-primitive type shipDate in query parameter serialization + // Skipping non-primitive type status in query parameter serialization + self.complete.as_ref().map(|complete| { [ - "string".to_string(), - string.to_string(), + "complete".to_string(), + complete.to_string(), ].join(",") }), - - // Skipping byte in query parameter serialization - // Skipping byte in query parameter serialization - - // Skipping binary in query parameter serialization - // Skipping binary in query parameter serialization - - // Skipping date in query parameter serialization - - // Skipping dateTime in query parameter serialization - - // Skipping uuid in query parameter serialization - - - Some("password".to_string()), - Some(self.password.to_string()), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } -/// Converts Query Parameters representation (style=form, explode=false) to a FormatTest value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// Converts Query Parameters representation (style=form, explode=false) to a Order value +/// as specified in /// Should be implemented in a serde deserializer -impl std::str::FromStr for FormatTest { +impl std::str::FromStr for Order { type Err = String; fn from_str(s: &str) -> std::result::Result { @@ -2723,19 +6640,12 @@ impl std::str::FromStr for FormatTest { #[derive(Default)] #[allow(dead_code)] struct IntermediateRep { - pub integer: Vec, - pub int32: Vec, - pub int64: Vec, - pub number: Vec, - pub float: Vec, - pub double: Vec, - pub string: Vec, - pub byte: Vec, - pub binary: Vec, - pub date: Vec, - pub date_time: Vec>, - pub uuid: Vec, - pub password: Vec, + pub id: Vec, + pub pet_id: Vec, + pub quantity: Vec, + pub ship_date: Vec>, + pub status: Vec, + pub complete: Vec, } let mut intermediate_rep = IntermediateRep::default(); @@ -2747,37 +6657,25 @@ impl std::str::FromStr for FormatTest { while key_result.is_some() { let val = match string_iter.next() { Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing FormatTest".to_string()) + None => return std::result::Result::Err("Missing value while parsing Order".to_string()) }; if let Some(key) = key_result { #[allow(clippy::match_single_binding)] match key { #[allow(clippy::redundant_clone)] - "integer" => intermediate_rep.integer.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "int32" => intermediate_rep.int32.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "int64" => intermediate_rep.int64.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "number" => intermediate_rep.number.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "float" => intermediate_rep.float.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "double" => intermediate_rep.double.push(::from_str(val).map_err(|x| x.to_string())?), + "id" => intermediate_rep.id.push(::from_str(val).map_err(|x| x.to_string())?), #[allow(clippy::redundant_clone)] - "string" => intermediate_rep.string.push(::from_str(val).map_err(|x| x.to_string())?), - "byte" => return std::result::Result::Err("Parsing binary data in this style is not supported in FormatTest".to_string()), - "binary" => return std::result::Result::Err("Parsing binary data in this style is not supported in FormatTest".to_string()), + "petId" => intermediate_rep.pet_id.push(::from_str(val).map_err(|x| x.to_string())?), #[allow(clippy::redundant_clone)] - "date" => intermediate_rep.date.push(::from_str(val).map_err(|x| x.to_string())?), + "quantity" => intermediate_rep.quantity.push(::from_str(val).map_err(|x| x.to_string())?), #[allow(clippy::redundant_clone)] - "dateTime" => intermediate_rep.date_time.push( as std::str::FromStr>::from_str(val).map_err(|x| x.to_string())?), + "shipDate" => intermediate_rep.ship_date.push( as std::str::FromStr>::from_str(val).map_err(|x| x.to_string())?), #[allow(clippy::redundant_clone)] - "uuid" => intermediate_rep.uuid.push(::from_str(val).map_err(|x| x.to_string())?), + "status" => intermediate_rep.status.push(::from_str(val).map_err(|x| x.to_string())?), #[allow(clippy::redundant_clone)] - "password" => intermediate_rep.password.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing FormatTest".to_string()) + "complete" => intermediate_rep.complete.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing Order".to_string()) } } @@ -2786,214 +6684,224 @@ impl std::str::FromStr for FormatTest { } // Use the intermediate representation to return the struct - std::result::Result::Ok(FormatTest { - integer: intermediate_rep.integer.into_iter().next(), - int32: intermediate_rep.int32.into_iter().next(), - int64: intermediate_rep.int64.into_iter().next(), - number: intermediate_rep.number.into_iter().next().ok_or_else(|| "number missing in FormatTest".to_string())?, - float: intermediate_rep.float.into_iter().next(), - double: intermediate_rep.double.into_iter().next(), - string: intermediate_rep.string.into_iter().next(), - byte: intermediate_rep.byte.into_iter().next().ok_or_else(|| "byte missing in FormatTest".to_string())?, - binary: intermediate_rep.binary.into_iter().next(), - date: intermediate_rep.date.into_iter().next().ok_or_else(|| "date missing in FormatTest".to_string())?, - date_time: intermediate_rep.date_time.into_iter().next(), - uuid: intermediate_rep.uuid.into_iter().next(), - password: intermediate_rep.password.into_iter().next().ok_or_else(|| "password missing in FormatTest".to_string())?, + std::result::Result::Ok(Order { + id: intermediate_rep.id.into_iter().next(), + pet_id: intermediate_rep.pet_id.into_iter().next(), + quantity: intermediate_rep.quantity.into_iter().next(), + ship_date: intermediate_rep.ship_date.into_iter().next(), + status: intermediate_rep.status.into_iter().next(), + complete: intermediate_rep.complete.into_iter().next(), }) } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for FormatTest - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for Order - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into FormatTest - {}", - value, err)) + format!("Unable to convert header value '{value}' into Order - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl FormatTest { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. - #[allow(dead_code)] - pub(crate) fn as_xml(&self) -> String { - serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] -#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct HasOnlyReadOnly { - #[serde(rename = "bar")] - #[serde(skip_serializing_if="Option::is_none")] - pub bar: Option, - - #[serde(rename = "foo")] - #[serde(skip_serializing_if="Option::is_none")] - pub foo: Option, - -} +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Order - {err}")) + } + }) + }).collect::, String>>()?; -impl HasOnlyReadOnly { - #[allow(clippy::new_without_default)] - pub fn new() -> HasOnlyReadOnly { - HasOnlyReadOnly { - bar: None, - foo: None, + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), } } } -/// Converts the HasOnlyReadOnly value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde serializer -impl std::string::ToString for HasOnlyReadOnly { - fn to_string(&self) -> String { - let params: Vec> = vec![ - - self.bar.as_ref().map(|bar| { - [ - "bar".to_string(), - bar.to_string(), - ].join(",") - }), - - - self.foo.as_ref().map(|foo| { - [ - "foo".to_string(), - foo.to_string(), - ].join(",") - }), +impl Order { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} - ]; +/// Order Status +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum OrderStatus { + #[serde(rename = "placed")] + Placed, + #[serde(rename = "approved")] + Approved, + #[serde(rename = "delivered")] + Delivered, +} - params.into_iter().flatten().collect::>().join(",") +impl std::fmt::Display for OrderStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + OrderStatus::Placed => write!(f, "placed"), + OrderStatus::Approved => write!(f, "approved"), + OrderStatus::Delivered => write!(f, "delivered"), + } } } -/// Converts Query Parameters representation (style=form, explode=false) to a HasOnlyReadOnly value -/// as specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde deserializer -impl std::str::FromStr for HasOnlyReadOnly { +impl std::str::FromStr for OrderStatus { type Err = String; fn from_str(s: &str) -> std::result::Result { - /// An intermediate representation of the struct to use for parsing. - #[derive(Default)] - #[allow(dead_code)] - struct IntermediateRep { - pub bar: Vec, - pub foo: Vec, - } - - let mut intermediate_rep = IntermediateRep::default(); - - // Parse into intermediate representation - let mut string_iter = s.split(','); - let mut key_result = string_iter.next(); - - while key_result.is_some() { - let val = match string_iter.next() { - Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing HasOnlyReadOnly".to_string()) - }; - - if let Some(key) = key_result { - #[allow(clippy::match_single_binding)] - match key { - #[allow(clippy::redundant_clone)] - "bar" => intermediate_rep.bar.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "foo" => intermediate_rep.foo.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing HasOnlyReadOnly".to_string()) - } - } - - // Get the next key - key_result = string_iter.next(); + match s { + "placed" => std::result::Result::Ok(OrderStatus::Placed), + "approved" => std::result::Result::Ok(OrderStatus::Approved), + "delivered" => std::result::Result::Ok(OrderStatus::Delivered), + _ => std::result::Result::Err(format!("Value not valid: {s}")), } - - // Use the intermediate representation to return the struct - std::result::Result::Ok(HasOnlyReadOnly { - bar: intermediate_rep.bar.into_iter().next(), - foo: intermediate_rep.foo.into_iter().next(), - }) } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for HasOnlyReadOnly - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for OrderStatus - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into HasOnlyReadOnly - {}", - value, err)) + format!("Unable to convert header value '{value}' into OrderStatus - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl HasOnlyReadOnly { + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into OrderStatus - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl OrderStatus { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -3002,131 +6910,159 @@ impl HasOnlyReadOnly { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "validate", derive(Validate))] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct List { - #[serde(rename = "123-list")] - #[serde(skip_serializing_if="Option::is_none")] - pub param_123_list: Option, +pub struct OuterBoolean( + bool +); +impl std::convert::From for OuterBoolean { + fn from(x: bool) -> Self { + OuterBoolean(x) + } } - -impl List { - #[allow(clippy::new_without_default)] - pub fn new() -> List { - List { - param_123_list: None, - } +impl std::convert::From for bool { + fn from(x: OuterBoolean) -> Self { + x.0 } } -/// Converts the List value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde serializer -impl std::string::ToString for List { - fn to_string(&self) -> String { - let params: Vec> = vec![ - - self.param_123_list.as_ref().map(|param_123_list| { - [ - "123-list".to_string(), - param_123_list.to_string(), - ].join(",") - }), - - ]; - - params.into_iter().flatten().collect::>().join(",") +impl std::ops::Deref for OuterBoolean { + type Target = bool; + fn deref(&self) -> &bool { + &self.0 } } -/// Converts Query Parameters representation (style=form, explode=false) to a List value -/// as specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde deserializer -impl std::str::FromStr for List { - type Err = String; - - fn from_str(s: &str) -> std::result::Result { - /// An intermediate representation of the struct to use for parsing. - #[derive(Default)] - #[allow(dead_code)] - struct IntermediateRep { - pub param_123_list: Vec, - } - - let mut intermediate_rep = IntermediateRep::default(); +impl std::ops::DerefMut for OuterBoolean { + fn deref_mut(&mut self) -> &mut bool { + &mut self.0 + } +} - // Parse into intermediate representation - let mut string_iter = s.split(','); - let mut key_result = string_iter.next(); +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for OuterBoolean { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} - while key_result.is_some() { - let val = match string_iter.next() { - Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing List".to_string()) - }; +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for OuterBoolean { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} +/// Converts the OuterBoolean value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for OuterBoolean { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } +} - if let Some(key) = key_result { - #[allow(clippy::match_single_binding)] - match key { - #[allow(clippy::redundant_clone)] - "123-list" => intermediate_rep.param_123_list.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing List".to_string()) - } - } +/// Converts Query Parameters representation (style=form, explode=false) to a OuterBoolean value +/// as specified in +/// Should be implemented in a serde deserializer +impl ::std::str::FromStr for OuterBoolean { + type Err = String; - // Get the next key - key_result = string_iter.next(); + fn from_str(s: &str) -> std::result::Result { + match std::str::FromStr::from_str(s) { + std::result::Result::Ok(r) => std::result::Result::Ok(OuterBoolean(r)), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {s} to OuterBoolean: {e:?}")), } - - // Use the intermediate representation to return the struct - std::result::Result::Ok(List { - param_123_list: intermediate_rep.param_123_list.into_iter().next(), - }) } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for List - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for OuterBoolean - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into List - {}", - value, err)) + format!("Unable to convert header value '{value}' into OuterBoolean - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl List { + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into OuterBoolean - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl OuterBoolean { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -3135,61 +7071,92 @@ impl List { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct MapTest { - #[serde(rename = "map_map_of_string")] +pub struct OuterComposite { + #[serde(rename = "my_number")] + #[serde(skip_serializing_if="Option::is_none")] - pub map_map_of_string: Option>>, + pub my_number: Option, + + #[serde(rename = "my_string")] - // Note: inline enums are not fully supported by openapi-generator - #[serde(rename = "map_map_of_enum")] #[serde(skip_serializing_if="Option::is_none")] - pub map_map_of_enum: Option>>, + pub my_string: Option, + + #[serde(rename = "my_boolean")] - // Note: inline enums are not fully supported by openapi-generator - #[serde(rename = "map_of_enum_string")] #[serde(skip_serializing_if="Option::is_none")] - pub map_of_enum_string: Option>, + pub my_boolean: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for OuterComposite { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} -impl MapTest { +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for OuterComposite { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + + +impl OuterComposite { #[allow(clippy::new_without_default)] - pub fn new() -> MapTest { - MapTest { - map_map_of_string: None, - map_map_of_enum: None, - map_of_enum_string: None, + pub fn new() -> OuterComposite { + OuterComposite { + my_number: None, + my_string: None, + my_boolean: None, } } } -/// Converts the MapTest value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// Converts the OuterComposite value to the Query Parameters representation (style=form, explode=false) +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for MapTest { - fn to_string(&self) -> String { +impl std::fmt::Display for OuterComposite { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - // Skipping map_map_of_string in query parameter serialization - // Skipping map_map_of_string in query parameter serialization - - // Skipping map_map_of_enum in query parameter serialization - // Skipping map_map_of_enum in query parameter serialization - - // Skipping map_of_enum_string in query parameter serialization - + self.my_number.as_ref().map(|my_number| { + [ + "my_number".to_string(), + my_number.to_string(), + ].join(",") + }), + self.my_string.as_ref().map(|my_string| { + [ + "my_string".to_string(), + my_string.to_string(), + ].join(",") + }), + self.my_boolean.as_ref().map(|my_boolean| { + [ + "my_boolean".to_string(), + my_boolean.to_string(), + ].join(",") + }), ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } -/// Converts Query Parameters representation (style=form, explode=false) to a MapTest value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// Converts Query Parameters representation (style=form, explode=false) to a OuterComposite value +/// as specified in /// Should be implemented in a serde deserializer -impl std::str::FromStr for MapTest { +impl std::str::FromStr for OuterComposite { type Err = String; fn from_str(s: &str) -> std::result::Result { @@ -3197,9 +7164,9 @@ impl std::str::FromStr for MapTest { #[derive(Default)] #[allow(dead_code)] struct IntermediateRep { - pub map_map_of_string: Vec>>, - pub map_map_of_enum: Vec>>, - pub map_of_enum_string: Vec>, + pub my_number: Vec, + pub my_string: Vec, + pub my_boolean: Vec, } let mut intermediate_rep = IntermediateRep::default(); @@ -3211,16 +7178,19 @@ impl std::str::FromStr for MapTest { while key_result.is_some() { let val = match string_iter.next() { Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing MapTest".to_string()) + None => return std::result::Result::Err("Missing value while parsing OuterComposite".to_string()) }; if let Some(key) = key_result { #[allow(clippy::match_single_binding)] match key { - "map_map_of_string" => return std::result::Result::Err("Parsing a container in this style is not supported in MapTest".to_string()), - "map_map_of_enum" => return std::result::Result::Err("Parsing a container in this style is not supported in MapTest".to_string()), - "map_of_enum_string" => return std::result::Result::Err("Parsing a container in this style is not supported in MapTest".to_string()), - _ => return std::result::Result::Err("Unexpected key while parsing MapTest".to_string()) + #[allow(clippy::redundant_clone)] + "my_number" => intermediate_rep.my_number.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "my_string" => intermediate_rep.my_string.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "my_boolean" => intermediate_rep.my_boolean.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing OuterComposite".to_string()) } } @@ -3229,203 +7199,220 @@ impl std::str::FromStr for MapTest { } // Use the intermediate representation to return the struct - std::result::Result::Ok(MapTest { - map_map_of_string: intermediate_rep.map_map_of_string.into_iter().next(), - map_map_of_enum: intermediate_rep.map_map_of_enum.into_iter().next(), - map_of_enum_string: intermediate_rep.map_of_enum_string.into_iter().next(), + std::result::Result::Ok(OuterComposite { + my_number: intermediate_rep.my_number.into_iter().next(), + my_string: intermediate_rep.my_string.into_iter().next(), + my_boolean: intermediate_rep.my_boolean.into_iter().next(), }) } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for MapTest - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for OuterComposite - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into MapTest - {}", - value, err)) + format!("Unable to convert header value '{value}' into OuterComposite - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl MapTest { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. - #[allow(dead_code)] - pub(crate) fn as_xml(&self) -> String { - serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] -#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct MixedPropertiesAndAdditionalPropertiesClass { - #[serde(rename = "uuid")] - #[serde(skip_serializing_if="Option::is_none")] - pub uuid: Option, - - #[serde(rename = "dateTime")] - #[serde(skip_serializing_if="Option::is_none")] - pub date_time: Option>, - - #[serde(rename = "map")] - #[serde(skip_serializing_if="Option::is_none")] - pub map: Option>, - -} +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into OuterComposite - {err}")) + } + }) + }).collect::, String>>()?; -impl MixedPropertiesAndAdditionalPropertiesClass { - #[allow(clippy::new_without_default)] - pub fn new() -> MixedPropertiesAndAdditionalPropertiesClass { - MixedPropertiesAndAdditionalPropertiesClass { - uuid: None, - date_time: None, - map: None, + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), } } } -/// Converts the MixedPropertiesAndAdditionalPropertiesClass value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde serializer -impl std::string::ToString for MixedPropertiesAndAdditionalPropertiesClass { - fn to_string(&self) -> String { - let params: Vec> = vec![ - // Skipping uuid in query parameter serialization - - // Skipping dateTime in query parameter serialization - - // Skipping map in query parameter serialization - // Skipping map in query parameter serialization - - ]; - - params.into_iter().flatten().collect::>().join(",") +impl OuterComposite { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") } } -/// Converts Query Parameters representation (style=form, explode=false) to a MixedPropertiesAndAdditionalPropertiesClass value -/// as specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde deserializer -impl std::str::FromStr for MixedPropertiesAndAdditionalPropertiesClass { - type Err = String; +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum OuterEnum { + #[serde(rename = "placed")] + Placed, + #[serde(rename = "approved")] + Approved, + #[serde(rename = "delivered")] + Delivered, +} - fn from_str(s: &str) -> std::result::Result { - /// An intermediate representation of the struct to use for parsing. - #[derive(Default)] - #[allow(dead_code)] - struct IntermediateRep { - pub uuid: Vec, - pub date_time: Vec>, - pub map: Vec>, +impl std::fmt::Display for OuterEnum { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + OuterEnum::Placed => write!(f, "placed"), + OuterEnum::Approved => write!(f, "approved"), + OuterEnum::Delivered => write!(f, "delivered"), } + } +} - let mut intermediate_rep = IntermediateRep::default(); - - // Parse into intermediate representation - let mut string_iter = s.split(','); - let mut key_result = string_iter.next(); - - while key_result.is_some() { - let val = match string_iter.next() { - Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing MixedPropertiesAndAdditionalPropertiesClass".to_string()) - }; - - if let Some(key) = key_result { - #[allow(clippy::match_single_binding)] - match key { - #[allow(clippy::redundant_clone)] - "uuid" => intermediate_rep.uuid.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "dateTime" => intermediate_rep.date_time.push( as std::str::FromStr>::from_str(val).map_err(|x| x.to_string())?), - "map" => return std::result::Result::Err("Parsing a container in this style is not supported in MixedPropertiesAndAdditionalPropertiesClass".to_string()), - _ => return std::result::Result::Err("Unexpected key while parsing MixedPropertiesAndAdditionalPropertiesClass".to_string()) - } - } +impl std::str::FromStr for OuterEnum { + type Err = String; - // Get the next key - key_result = string_iter.next(); + fn from_str(s: &str) -> std::result::Result { + match s { + "placed" => std::result::Result::Ok(OuterEnum::Placed), + "approved" => std::result::Result::Ok(OuterEnum::Approved), + "delivered" => std::result::Result::Ok(OuterEnum::Delivered), + _ => std::result::Result::Err(format!("Value not valid: {s}")), } - - // Use the intermediate representation to return the struct - std::result::Result::Ok(MixedPropertiesAndAdditionalPropertiesClass { - uuid: intermediate_rep.uuid.into_iter().next(), - date_time: intermediate_rep.date_time.into_iter().next(), - map: intermediate_rep.map.into_iter().next(), - }) } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for MixedPropertiesAndAdditionalPropertiesClass - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for OuterEnum - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into MixedPropertiesAndAdditionalPropertiesClass - {}", - value, err)) + format!("Unable to convert header value '{value}' into OuterEnum - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); -impl MixedPropertiesAndAdditionalPropertiesClass { + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into OuterEnum - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl OuterEnum { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -3434,150 +7421,159 @@ impl MixedPropertiesAndAdditionalPropertiesClass { } } -/// Model for testing model name starting with number -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "validate", derive(Validate))] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -#[serde(rename = "Name")] -pub struct Model200Response { - #[serde(rename = "name")] - #[serde(skip_serializing_if="Option::is_none")] - pub name: Option, - - #[serde(rename = "class")] - #[serde(skip_serializing_if="Option::is_none")] - pub class: Option, +pub struct OuterNumber( + f64 +); +impl std::convert::From for OuterNumber { + fn from(x: f64) -> Self { + OuterNumber(x) + } } - -impl Model200Response { - #[allow(clippy::new_without_default)] - pub fn new() -> Model200Response { - Model200Response { - name: None, - class: None, - } +impl std::convert::From for f64 { + fn from(x: OuterNumber) -> Self { + x.0 } } -/// Converts the Model200Response value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde serializer -impl std::string::ToString for Model200Response { - fn to_string(&self) -> String { - let params: Vec> = vec![ - - self.name.as_ref().map(|name| { - [ - "name".to_string(), - name.to_string(), - ].join(",") - }), - +impl std::ops::Deref for OuterNumber { + type Target = f64; + fn deref(&self) -> &f64 { + &self.0 + } +} - self.class.as_ref().map(|class| { - [ - "class".to_string(), - class.to_string(), - ].join(",") - }), +impl std::ops::DerefMut for OuterNumber { + fn deref_mut(&mut self) -> &mut f64 { + &mut self.0 + } +} - ]; +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for OuterNumber { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} - params.into_iter().flatten().collect::>().join(",") +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for OuterNumber { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} +/// Converts the OuterNumber value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for OuterNumber { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) } } -/// Converts Query Parameters representation (style=form, explode=false) to a Model200Response value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// Converts Query Parameters representation (style=form, explode=false) to a OuterNumber value +/// as specified in /// Should be implemented in a serde deserializer -impl std::str::FromStr for Model200Response { +impl ::std::str::FromStr for OuterNumber { type Err = String; fn from_str(s: &str) -> std::result::Result { - /// An intermediate representation of the struct to use for parsing. - #[derive(Default)] - #[allow(dead_code)] - struct IntermediateRep { - pub name: Vec, - pub class: Vec, - } - - let mut intermediate_rep = IntermediateRep::default(); - - // Parse into intermediate representation - let mut string_iter = s.split(','); - let mut key_result = string_iter.next(); - - while key_result.is_some() { - let val = match string_iter.next() { - Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing Model200Response".to_string()) - }; - - if let Some(key) = key_result { - #[allow(clippy::match_single_binding)] - match key { - #[allow(clippy::redundant_clone)] - "name" => intermediate_rep.name.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "class" => intermediate_rep.class.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing Model200Response".to_string()) - } - } - - // Get the next key - key_result = string_iter.next(); + match std::str::FromStr::from_str(s) { + std::result::Result::Ok(r) => std::result::Result::Ok(OuterNumber(r)), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {s} to OuterNumber: {e:?}")), } - - // Use the intermediate representation to return the struct - std::result::Result::Ok(Model200Response { - name: intermediate_rep.name.into_iter().next(), - class: intermediate_rep.class.into_iter().next(), - }) } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for Model200Response - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for OuterNumber - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into Model200Response - {}", - value, err)) + format!("Unable to convert header value '{value}' into OuterNumber - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl Model200Response { + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into OuterNumber - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl OuterNumber { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -3586,179 +7582,149 @@ impl Model200Response { } } -/// Model for testing model name same as property name -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "validate", derive(Validate))] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -#[serde(rename = "Name")] -pub struct Name { - #[serde(rename = "name")] - pub name: i32, - - #[serde(rename = "snake_case")] - #[serde(skip_serializing_if="Option::is_none")] - pub snake_case: Option, - - #[serde(rename = "property")] - #[serde(skip_serializing_if="Option::is_none")] - pub property: Option, - - #[serde(rename = "123Number")] - #[serde(skip_serializing_if="Option::is_none")] - pub param_123_number: Option, +pub struct OuterString( + String +); +impl std::convert::From for OuterString { + fn from(x: String) -> Self { + OuterString(x) + } } - -impl Name { - #[allow(clippy::new_without_default)] - pub fn new(name: i32, ) -> Name { - Name { - name, - snake_case: None, - property: None, - param_123_number: None, - } +impl std::convert::From for String { + fn from(x: OuterString) -> Self { + x.0 } } -/// Converts the Name value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde serializer -impl std::string::ToString for Name { - fn to_string(&self) -> String { - let params: Vec> = vec![ - - Some("name".to_string()), - Some(self.name.to_string()), - - - self.snake_case.as_ref().map(|snake_case| { - [ - "snake_case".to_string(), - snake_case.to_string(), - ].join(",") - }), - - - self.property.as_ref().map(|property| { - [ - "property".to_string(), - property.to_string(), - ].join(",") - }), - - - self.param_123_number.as_ref().map(|param_123_number| { - [ - "123Number".to_string(), - param_123_number.to_string(), - ].join(",") - }), - - ]; - - params.into_iter().flatten().collect::>().join(",") +impl std::ops::Deref for OuterString { + type Target = String; + fn deref(&self) -> &String { + &self.0 } } -/// Converts Query Parameters representation (style=form, explode=false) to a Name value -/// as specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde deserializer -impl std::str::FromStr for Name { - type Err = String; - - fn from_str(s: &str) -> std::result::Result { - /// An intermediate representation of the struct to use for parsing. - #[derive(Default)] - #[allow(dead_code)] - struct IntermediateRep { - pub name: Vec, - pub snake_case: Vec, - pub property: Vec, - pub param_123_number: Vec, - } - - let mut intermediate_rep = IntermediateRep::default(); - - // Parse into intermediate representation - let mut string_iter = s.split(','); - let mut key_result = string_iter.next(); - - while key_result.is_some() { - let val = match string_iter.next() { - Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing Name".to_string()) - }; +impl std::ops::DerefMut for OuterString { + fn deref_mut(&mut self) -> &mut String { + &mut self.0 + } +} - if let Some(key) = key_result { - #[allow(clippy::match_single_binding)] - match key { - #[allow(clippy::redundant_clone)] - "name" => intermediate_rep.name.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "snake_case" => intermediate_rep.snake_case.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "property" => intermediate_rep.property.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "123Number" => intermediate_rep.param_123_number.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing Name".to_string()) - } - } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for OuterString { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} - // Get the next key - key_result = string_iter.next(); - } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for OuterString { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} +impl std::fmt::Display for OuterString { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0.clone()) + } +} - // Use the intermediate representation to return the struct - std::result::Result::Ok(Name { - name: intermediate_rep.name.into_iter().next().ok_or_else(|| "name missing in Name".to_string())?, - snake_case: intermediate_rep.snake_case.into_iter().next(), - property: intermediate_rep.property.into_iter().next(), - param_123_number: intermediate_rep.param_123_number.into_iter().next(), - }) +impl std::str::FromStr for OuterString { + type Err = ::std::convert::Infallible; + fn from_str(x: &str) -> std::result::Result { + std::result::Result::Ok(OuterString(x.to_owned())) } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for Name - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for OuterString - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into Name - {}", - value, err)) + format!("Unable to convert header value '{value}' into OuterString - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl Name { + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into OuterString - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl OuterString { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -3767,49 +7733,107 @@ impl Name { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct NumberOnly { - #[serde(rename = "JustNumber")] +#[serde(rename = "Pet")] +pub struct Pet { + #[serde(rename = "id")] + #[serde(skip_serializing_if="Option::is_none")] - pub just_number: Option, + pub id: Option, + + #[serde(rename = "category")] + + #[cfg_attr(feature = "validate", validate)] + #[serde(skip_serializing_if="Option::is_none")] + pub category: Option, + + #[serde(rename = "name")] + + pub name: String, + + #[serde(rename = "photoUrls")] + + pub photo_urls: Vec, + + #[serde(rename = "tags")] + + #[cfg_attr(feature = "validate", validate)] + #[serde(skip_serializing_if="Option::is_none")] + pub tags: Option>, + + #[serde(rename = "status")] + + #[cfg_attr(feature = "validate", validate)] + #[serde(skip_serializing_if="Option::is_none")] + pub status: Option, + +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for Pet { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for Pet { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } } -impl NumberOnly { +impl Pet { #[allow(clippy::new_without_default)] - pub fn new() -> NumberOnly { - NumberOnly { - just_number: None, + pub fn new(name: String, photo_urls: Vec, ) -> Pet { + Pet { + id: None, + category: None, + name, + photo_urls, + tags: None, + status: None, } } } -/// Converts the NumberOnly value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// Converts the Pet value to the Query Parameters representation (style=form, explode=false) +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for NumberOnly { - fn to_string(&self) -> String { +impl std::fmt::Display for Pet { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - - self.just_number.as_ref().map(|just_number| { + self.id.as_ref().map(|id| { [ - "JustNumber".to_string(), - just_number.to_string(), + "id".to_string(), + id.to_string(), ].join(",") }), - + // Skipping non-primitive type category in query parameter serialization + Some("name".to_string()), + Some(self.name.to_string()), + Some("photoUrls".to_string()), + Some(self.photo_urls.iter().map(|x| x.to_string()).collect::>().join(",")), + // Skipping non-primitive type tags in query parameter serialization + // Skipping non-primitive type status in query parameter serialization ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } -/// Converts Query Parameters representation (style=form, explode=false) to a NumberOnly value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// Converts Query Parameters representation (style=form, explode=false) to a Pet value +/// as specified in /// Should be implemented in a serde deserializer -impl std::str::FromStr for NumberOnly { +impl std::str::FromStr for Pet { type Err = String; fn from_str(s: &str) -> std::result::Result { @@ -3817,7 +7841,12 @@ impl std::str::FromStr for NumberOnly { #[derive(Default)] #[allow(dead_code)] struct IntermediateRep { - pub just_number: Vec, + pub id: Vec, + pub category: Vec, + pub name: Vec, + pub photo_urls: Vec>, + pub tags: Vec>, + pub status: Vec, } let mut intermediate_rep = IntermediateRep::default(); @@ -3829,15 +7858,23 @@ impl std::str::FromStr for NumberOnly { while key_result.is_some() { let val = match string_iter.next() { Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing NumberOnly".to_string()) + None => return std::result::Result::Err("Missing value while parsing Pet".to_string()) }; if let Some(key) = key_result { #[allow(clippy::match_single_binding)] match key { #[allow(clippy::redundant_clone)] - "JustNumber" => intermediate_rep.just_number.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing NumberOnly".to_string()) + "id" => intermediate_rep.id.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "category" => intermediate_rep.category.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "name" => intermediate_rep.name.push(::from_str(val).map_err(|x| x.to_string())?), + "photoUrls" => return std::result::Result::Err("Parsing a container in this style is not supported in Pet".to_string()), + "tags" => return std::result::Result::Err("Parsing a container in this style is not supported in Pet".to_string()), + #[allow(clippy::redundant_clone)] + "status" => intermediate_rep.status.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing Pet".to_string()) } } @@ -3846,238 +7883,224 @@ impl std::str::FromStr for NumberOnly { } // Use the intermediate representation to return the struct - std::result::Result::Ok(NumberOnly { - just_number: intermediate_rep.just_number.into_iter().next(), + std::result::Result::Ok(Pet { + id: intermediate_rep.id.into_iter().next(), + category: intermediate_rep.category.into_iter().next(), + name: intermediate_rep.name.into_iter().next().ok_or_else(|| "name missing in Pet".to_string())?, + photo_urls: intermediate_rep.photo_urls.into_iter().next().ok_or_else(|| "photoUrls missing in Pet".to_string())?, + tags: intermediate_rep.tags.into_iter().next(), + status: intermediate_rep.status.into_iter().next(), }) } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for NumberOnly - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for Pet - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into NumberOnly - {}", - value, err)) + format!("Unable to convert header value '{value}' into Pet - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl NumberOnly { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. - #[allow(dead_code)] - pub(crate) fn as_xml(&self) -> String { - serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] -#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct ObjectContainingObjectWithOnlyAdditionalProperties { - #[serde(rename = "inner")] - #[serde(skip_serializing_if="Option::is_none")] - pub inner: Option, - -} +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Pet - {err}")) + } + }) + }).collect::, String>>()?; -impl ObjectContainingObjectWithOnlyAdditionalProperties { - #[allow(clippy::new_without_default)] - pub fn new() -> ObjectContainingObjectWithOnlyAdditionalProperties { - ObjectContainingObjectWithOnlyAdditionalProperties { - inner: None, + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), } } } -/// Converts the ObjectContainingObjectWithOnlyAdditionalProperties value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde serializer -impl std::string::ToString for ObjectContainingObjectWithOnlyAdditionalProperties { - fn to_string(&self) -> String { - let params: Vec> = vec![ - // Skipping inner in query parameter serialization +impl Pet { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} - ]; +/// pet status in the store +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum PetStatus { + #[serde(rename = "available")] + Available, + #[serde(rename = "pending")] + Pending, + #[serde(rename = "sold")] + Sold, +} - params.into_iter().flatten().collect::>().join(",") +impl std::fmt::Display for PetStatus { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + PetStatus::Available => write!(f, "available"), + PetStatus::Pending => write!(f, "pending"), + PetStatus::Sold => write!(f, "sold"), + } } } -/// Converts Query Parameters representation (style=form, explode=false) to a ObjectContainingObjectWithOnlyAdditionalProperties value -/// as specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde deserializer -impl std::str::FromStr for ObjectContainingObjectWithOnlyAdditionalProperties { +impl std::str::FromStr for PetStatus { type Err = String; fn from_str(s: &str) -> std::result::Result { - /// An intermediate representation of the struct to use for parsing. - #[derive(Default)] - #[allow(dead_code)] - struct IntermediateRep { - pub inner: Vec, - } - - let mut intermediate_rep = IntermediateRep::default(); - - // Parse into intermediate representation - let mut string_iter = s.split(','); - let mut key_result = string_iter.next(); - - while key_result.is_some() { - let val = match string_iter.next() { - Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing ObjectContainingObjectWithOnlyAdditionalProperties".to_string()) - }; - - if let Some(key) = key_result { - #[allow(clippy::match_single_binding)] - match key { - #[allow(clippy::redundant_clone)] - "inner" => intermediate_rep.inner.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing ObjectContainingObjectWithOnlyAdditionalProperties".to_string()) - } - } - - // Get the next key - key_result = string_iter.next(); - } - - // Use the intermediate representation to return the struct - std::result::Result::Ok(ObjectContainingObjectWithOnlyAdditionalProperties { - inner: intermediate_rep.inner.into_iter().next(), - }) + match s { + "available" => std::result::Result::Ok(PetStatus::Available), + "pending" => std::result::Result::Ok(PetStatus::Pending), + "sold" => std::result::Result::Ok(PetStatus::Sold), + _ => std::result::Result::Err(format!("Value not valid: {s}")), + } } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for ObjectContainingObjectWithOnlyAdditionalProperties - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for PetStatus - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into ObjectContainingObjectWithOnlyAdditionalProperties - {}", - value, err)) + format!("Unable to convert header value '{value}' into PetStatus - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl ObjectContainingObjectWithOnlyAdditionalProperties { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. - #[allow(dead_code)] - pub(crate) fn as_xml(&self) -> String { - serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") - } -} - -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] -#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct ObjectWithOnlyAdditionalProperties(std::collections::HashMap); - -impl std::convert::From> for ObjectWithOnlyAdditionalProperties { - fn from(x: std::collections::HashMap) -> Self { - ObjectWithOnlyAdditionalProperties(x) - } -} - -impl std::convert::From for std::collections::HashMap { - fn from(x: ObjectWithOnlyAdditionalProperties) -> Self { - x.0 - } -} - -impl std::ops::Deref for ObjectWithOnlyAdditionalProperties { - type Target = std::collections::HashMap; - fn deref(&self) -> &std::collections::HashMap { - &self.0 - } -} + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); -impl std::ops::DerefMut for ObjectWithOnlyAdditionalProperties { - fn deref_mut(&mut self) -> &mut std::collections::HashMap { - &mut self.0 + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } } } -/// Converts the ObjectWithOnlyAdditionalProperties value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde serializer -impl ::std::string::ToString for ObjectWithOnlyAdditionalProperties { - fn to_string(&self) -> String { - // Skipping additionalProperties in query parameter serialization - "".to_string() - } -} +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; -/// Converts Query Parameters representation (style=form, explode=false) to a ObjectWithOnlyAdditionalProperties value -/// as specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde deserializer -impl ::std::str::FromStr for ObjectWithOnlyAdditionalProperties { - type Err = &'static str; + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into PetStatus - {err}")) + } + }) + }).collect::, String>>()?; - fn from_str(s: &str) -> std::result::Result { - std::result::Result::Err("Parsing additionalProperties for ObjectWithOnlyAdditionalProperties is not supported") + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } } } -impl ObjectWithOnlyAdditionalProperties { +impl PetStatus { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -4086,111 +8109,80 @@ impl ObjectWithOnlyAdditionalProperties { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -#[serde(rename = "Order")] -pub struct Order { - #[serde(rename = "id")] - #[serde(skip_serializing_if="Option::is_none")] - pub id: Option, +pub struct ReadOnlyFirst { + #[serde(rename = "bar")] - #[serde(rename = "petId")] #[serde(skip_serializing_if="Option::is_none")] - pub pet_id: Option, + pub bar: Option, - #[serde(rename = "quantity")] - #[serde(skip_serializing_if="Option::is_none")] - pub quantity: Option, + #[serde(rename = "baz")] - #[serde(rename = "shipDate")] #[serde(skip_serializing_if="Option::is_none")] - pub ship_date: Option>, + pub baz: Option, - /// Order Status - // Note: inline enums are not fully supported by openapi-generator - #[serde(rename = "status")] - #[serde(skip_serializing_if="Option::is_none")] - pub status: Option, +} - #[serde(rename = "complete")] - #[serde(skip_serializing_if="Option::is_none")] - pub complete: Option, +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for ReadOnlyFirst { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for ReadOnlyFirst { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } } -impl Order { +impl ReadOnlyFirst { #[allow(clippy::new_without_default)] - pub fn new() -> Order { - Order { - id: None, - pet_id: None, - quantity: None, - ship_date: None, - status: None, - complete: Some(false), + pub fn new() -> ReadOnlyFirst { + ReadOnlyFirst { + bar: None, + baz: None, } } } -/// Converts the Order value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// Converts the ReadOnlyFirst value to the Query Parameters representation (style=form, explode=false) +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for Order { - fn to_string(&self) -> String { +impl std::fmt::Display for ReadOnlyFirst { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - - self.id.as_ref().map(|id| { - [ - "id".to_string(), - id.to_string(), - ].join(",") - }), - - - self.pet_id.as_ref().map(|pet_id| { - [ - "petId".to_string(), - pet_id.to_string(), - ].join(",") - }), - - - self.quantity.as_ref().map(|quantity| { - [ - "quantity".to_string(), - quantity.to_string(), - ].join(",") - }), - - // Skipping shipDate in query parameter serialization - - - self.status.as_ref().map(|status| { + self.bar.as_ref().map(|bar| { [ - "status".to_string(), - status.to_string(), + "bar".to_string(), + bar.to_string(), ].join(",") }), - - - self.complete.as_ref().map(|complete| { + self.baz.as_ref().map(|baz| { [ - "complete".to_string(), - complete.to_string(), + "baz".to_string(), + baz.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } -/// Converts Query Parameters representation (style=form, explode=false) to a Order value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// Converts Query Parameters representation (style=form, explode=false) to a ReadOnlyFirst value +/// as specified in /// Should be implemented in a serde deserializer -impl std::str::FromStr for Order { +impl std::str::FromStr for ReadOnlyFirst { type Err = String; fn from_str(s: &str) -> std::result::Result { @@ -4198,12 +8190,8 @@ impl std::str::FromStr for Order { #[derive(Default)] #[allow(dead_code)] struct IntermediateRep { - pub id: Vec, - pub pet_id: Vec, - pub quantity: Vec, - pub ship_date: Vec>, - pub status: Vec, - pub complete: Vec, + pub bar: Vec, + pub baz: Vec, } let mut intermediate_rep = IntermediateRep::default(); @@ -4215,25 +8203,17 @@ impl std::str::FromStr for Order { while key_result.is_some() { let val = match string_iter.next() { Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing Order".to_string()) + None => return std::result::Result::Err("Missing value while parsing ReadOnlyFirst".to_string()) }; if let Some(key) = key_result { #[allow(clippy::match_single_binding)] match key { #[allow(clippy::redundant_clone)] - "id" => intermediate_rep.id.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "petId" => intermediate_rep.pet_id.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "quantity" => intermediate_rep.quantity.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "shipDate" => intermediate_rep.ship_date.push( as std::str::FromStr>::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "status" => intermediate_rep.status.push(::from_str(val).map_err(|x| x.to_string())?), + "bar" => intermediate_rep.bar.push(::from_str(val).map_err(|x| x.to_string())?), #[allow(clippy::redundant_clone)] - "complete" => intermediate_rep.complete.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing Order".to_string()) + "baz" => intermediate_rep.baz.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing ReadOnlyFirst".to_string()) } } @@ -4242,96 +8222,92 @@ impl std::str::FromStr for Order { } // Use the intermediate representation to return the struct - std::result::Result::Ok(Order { - id: intermediate_rep.id.into_iter().next(), - pet_id: intermediate_rep.pet_id.into_iter().next(), - quantity: intermediate_rep.quantity.into_iter().next(), - ship_date: intermediate_rep.ship_date.into_iter().next(), - status: intermediate_rep.status.into_iter().next(), - complete: intermediate_rep.complete.into_iter().next(), + std::result::Result::Ok(ReadOnlyFirst { + bar: intermediate_rep.bar.into_iter().next(), + baz: intermediate_rep.baz.into_iter().next(), }) } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for Order - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for ReadOnlyFirst - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into Order - {}", - value, err)) + format!("Unable to convert header value '{value}' into ReadOnlyFirst - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl Order { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. - #[allow(dead_code)] - pub(crate) fn as_xml(&self) -> String { - serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") - } -} - -#[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] -#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct OuterBoolean(bool); + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); -impl std::convert::From for OuterBoolean { - fn from(x: bool) -> Self { - OuterBoolean(x) + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } } } -impl std::convert::From for bool { - fn from(x: OuterBoolean) -> Self { - x.0 - } -} +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; -impl std::ops::Deref for OuterBoolean { - type Target = bool; - fn deref(&self) -> &bool { - &self.0 - } -} + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ReadOnlyFirst - {err}")) + } + }) + }).collect::, String>>()?; -impl std::ops::DerefMut for OuterBoolean { - fn deref_mut(&mut self) -> &mut bool { - &mut self.0 + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } } } - -impl OuterBoolean { +impl ReadOnlyFirst { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -4340,75 +8316,70 @@ impl OuterBoolean { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +/// Model for testing reserved words +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct OuterComposite { - #[serde(rename = "my_number")] - #[serde(skip_serializing_if="Option::is_none")] - pub my_number: Option, - - #[serde(rename = "my_string")] - #[serde(skip_serializing_if="Option::is_none")] - pub my_string: Option, +#[serde(rename = "Return")] +pub struct Return { + #[serde(rename = "return")] - #[serde(rename = "my_boolean")] #[serde(skip_serializing_if="Option::is_none")] - pub my_boolean: Option, + pub r#return: Option, } - -impl OuterComposite { - #[allow(clippy::new_without_default)] - pub fn new() -> OuterComposite { - OuterComposite { - my_number: None, - my_string: None, - my_boolean: None, - } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for Return { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) } } -/// Converts the OuterComposite value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde serializer -impl std::string::ToString for OuterComposite { - fn to_string(&self) -> String { - let params: Vec> = vec![ - - self.my_number.as_ref().map(|my_number| { - [ - "my_number".to_string(), - my_number.to_string(), - ].join(",") - }), - +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for Return { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} - self.my_string.as_ref().map(|my_string| { - [ - "my_string".to_string(), - my_string.to_string(), - ].join(",") - }), +impl Return { + #[allow(clippy::new_without_default)] + pub fn new() -> Return { + Return { + r#return: None, + } + } +} - self.my_boolean.as_ref().map(|my_boolean| { +/// Converts the Return value to the Query Parameters representation (style=form, explode=false) +/// specified in +/// Should be implemented in a serde serializer +impl std::fmt::Display for Return { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let params: Vec> = vec![ + self.r#return.as_ref().map(|r#return| { [ - "my_boolean".to_string(), - my_boolean.to_string(), + "return".to_string(), + r#return.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } -/// Converts Query Parameters representation (style=form, explode=false) to a OuterComposite value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// Converts Query Parameters representation (style=form, explode=false) to a Return value +/// as specified in /// Should be implemented in a serde deserializer -impl std::str::FromStr for OuterComposite { +impl std::str::FromStr for Return { type Err = String; fn from_str(s: &str) -> std::result::Result { @@ -4416,9 +8387,7 @@ impl std::str::FromStr for OuterComposite { #[derive(Default)] #[allow(dead_code)] struct IntermediateRep { - pub my_number: Vec, - pub my_string: Vec, - pub my_boolean: Vec, + pub r#return: Vec, } let mut intermediate_rep = IntermediateRep::default(); @@ -4430,19 +8399,15 @@ impl std::str::FromStr for OuterComposite { while key_result.is_some() { let val = match string_iter.next() { Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing OuterComposite".to_string()) + None => return std::result::Result::Err("Missing value while parsing Return".to_string()) }; if let Some(key) = key_result { #[allow(clippy::match_single_binding)] match key { #[allow(clippy::redundant_clone)] - "my_number" => intermediate_rep.my_number.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "my_string" => intermediate_rep.my_string.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "my_boolean" => intermediate_rep.my_boolean.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing OuterComposite".to_string()) + "return" => intermediate_rep.r#return.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing Return".to_string()) } } @@ -4451,141 +8416,91 @@ impl std::str::FromStr for OuterComposite { } // Use the intermediate representation to return the struct - std::result::Result::Ok(OuterComposite { - my_number: intermediate_rep.my_number.into_iter().next(), - my_string: intermediate_rep.my_string.into_iter().next(), - my_boolean: intermediate_rep.my_boolean.into_iter().next(), + std::result::Result::Ok(Return { + r#return: intermediate_rep.r#return.into_iter().next(), }) } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for OuterComposite - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for Return - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into OuterComposite - {}", - value, err)) + format!("Unable to convert header value '{value}' into Return - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl OuterComposite { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. - #[allow(dead_code)] - pub(crate) fn as_xml(&self) -> String { - serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") - } -} - -/// Enumeration of values. -/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` -/// which helps with FFI. -#[allow(non_camel_case_types)] -#[repr(C)] -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)] -#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] -pub enum OuterEnum { - #[serde(rename = "placed")] - Placed, - #[serde(rename = "approved")] - Approved, - #[serde(rename = "delivered")] - Delivered, -} - -impl std::fmt::Display for OuterEnum { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match *self { - OuterEnum::Placed => write!(f, "placed"), - OuterEnum::Approved => write!(f, "approved"), - OuterEnum::Delivered => write!(f, "delivered"), - } - } -} - -impl std::str::FromStr for OuterEnum { - type Err = String; + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); - fn from_str(s: &str) -> std::result::Result { - match s { - "placed" => std::result::Result::Ok(OuterEnum::Placed), - "approved" => std::result::Result::Ok(OuterEnum::Approved), - "delivered" => std::result::Result::Ok(OuterEnum::Delivered), - _ => std::result::Result::Err(format!("Value not valid: {}", s)), + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } -impl OuterEnum { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. - #[allow(dead_code)] - pub(crate) fn as_xml(&self) -> String { - serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") - } -} - -#[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] -#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct OuterNumber(f64); - -impl std::convert::From for OuterNumber { - fn from(x: f64) -> Self { - OuterNumber(x) - } -} - -impl std::convert::From for f64 { - fn from(x: OuterNumber) -> Self { - x.0 - } -} +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; -impl std::ops::Deref for OuterNumber { - type Target = f64; - fn deref(&self) -> &f64 { - &self.0 - } -} + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Return - {err}")) + } + }) + }).collect::, String>>()?; -impl std::ops::DerefMut for OuterNumber { - fn deref_mut(&mut self) -> &mut f64 { - &mut self.0 + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } } } - -impl OuterNumber { +impl Return { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -4594,147 +8509,81 @@ impl OuterNumber { } } -#[derive(Debug, Clone, PartialEq, PartialOrd, serde::Serialize, serde::Deserialize)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct OuterString(String); - -impl std::convert::From for OuterString { - fn from(x: String) -> Self { - OuterString(x) - } -} +#[serde(rename = "Tag")] +pub struct Tag { + #[serde(rename = "id")] -impl std::string::ToString for OuterString { - fn to_string(&self) -> String { - self.0.to_string() - } -} + #[serde(skip_serializing_if="Option::is_none")] + pub id: Option, -impl std::str::FromStr for OuterString { - type Err = std::string::ParseError; - fn from_str(x: &str) -> std::result::Result { - std::result::Result::Ok(OuterString(x.to_string())) - } -} + #[serde(rename = "name")] -impl std::convert::From for String { - fn from(x: OuterString) -> Self { - x.0 - } -} + #[serde(skip_serializing_if="Option::is_none")] + pub name: Option, -impl std::ops::Deref for OuterString { - type Target = String; - fn deref(&self) -> &String { - &self.0 - } } -impl std::ops::DerefMut for OuterString { - fn deref_mut(&mut self) -> &mut String { - &mut self.0 +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for Tag { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) } } - -impl OuterString { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. - #[allow(dead_code)] - pub(crate) fn as_xml(&self) -> String { - serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for Tag { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] -#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -#[serde(rename = "Pet")] -pub struct Pet { - #[serde(rename = "id")] - #[serde(skip_serializing_if="Option::is_none")] - pub id: Option, - - #[serde(rename = "category")] - #[serde(skip_serializing_if="Option::is_none")] - pub category: Option, - - #[serde(rename = "name")] - pub name: String, - - #[serde(rename = "photoUrls")] - pub photo_urls: Vec, - - #[serde(rename = "tags")] - #[serde(skip_serializing_if="Option::is_none")] - pub tags: Option>, - - /// pet status in the store - // Note: inline enums are not fully supported by openapi-generator - #[serde(rename = "status")] - #[serde(skip_serializing_if="Option::is_none")] - pub status: Option, - -} - -impl Pet { +impl Tag { #[allow(clippy::new_without_default)] - pub fn new(name: String, photo_urls: Vec, ) -> Pet { - Pet { + pub fn new() -> Tag { + Tag { id: None, - category: None, - name, - photo_urls, - tags: None, - status: None, + name: None, } } } -/// Converts the Pet value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// Converts the Tag value to the Query Parameters representation (style=form, explode=false) +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for Pet { - fn to_string(&self) -> String { +impl std::fmt::Display for Tag { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.id.as_ref().map(|id| { [ "id".to_string(), id.to_string(), ].join(",") }), - - // Skipping category in query parameter serialization - - - Some("name".to_string()), - Some(self.name.to_string()), - - - Some("photoUrls".to_string()), - Some(self.photo_urls.iter().map(|x| x.to_string()).collect::>().join(",")), - - // Skipping tags in query parameter serialization - - - self.status.as_ref().map(|status| { + self.name.as_ref().map(|name| { [ - "status".to_string(), - status.to_string(), + "name".to_string(), + name.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } -/// Converts Query Parameters representation (style=form, explode=false) to a Pet value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// Converts Query Parameters representation (style=form, explode=false) to a Tag value +/// as specified in /// Should be implemented in a serde deserializer -impl std::str::FromStr for Pet { +impl std::str::FromStr for Tag { type Err = String; fn from_str(s: &str) -> std::result::Result { @@ -4743,11 +8592,7 @@ impl std::str::FromStr for Pet { #[allow(dead_code)] struct IntermediateRep { pub id: Vec, - pub category: Vec, pub name: Vec, - pub photo_urls: Vec>, - pub tags: Vec>, - pub status: Vec, } let mut intermediate_rep = IntermediateRep::default(); @@ -4759,23 +8604,17 @@ impl std::str::FromStr for Pet { while key_result.is_some() { let val = match string_iter.next() { Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing Pet".to_string()) + None => return std::result::Result::Err("Missing value while parsing Tag".to_string()) }; if let Some(key) = key_result { #[allow(clippy::match_single_binding)] match key { #[allow(clippy::redundant_clone)] - "id" => intermediate_rep.id.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "category" => intermediate_rep.category.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "name" => intermediate_rep.name.push(::from_str(val).map_err(|x| x.to_string())?), - "photoUrls" => return std::result::Result::Err("Parsing a container in this style is not supported in Pet".to_string()), - "tags" => return std::result::Result::Err("Parsing a container in this style is not supported in Pet".to_string()), + "id" => intermediate_rep.id.push(::from_str(val).map_err(|x| x.to_string())?), #[allow(clippy::redundant_clone)] - "status" => intermediate_rep.status.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing Pet".to_string()) + "name" => intermediate_rep.name.push(::from_str(val).map_err(|x| x.to_string())?), + _ => return std::result::Result::Err("Unexpected key while parsing Tag".to_string()) } } @@ -4784,207 +8623,215 @@ impl std::str::FromStr for Pet { } // Use the intermediate representation to return the struct - std::result::Result::Ok(Pet { + std::result::Result::Ok(Tag { id: intermediate_rep.id.into_iter().next(), - category: intermediate_rep.category.into_iter().next(), - name: intermediate_rep.name.into_iter().next().ok_or_else(|| "name missing in Pet".to_string())?, - photo_urls: intermediate_rep.photo_urls.into_iter().next().ok_or_else(|| "photoUrls missing in Pet".to_string())?, - tags: intermediate_rep.tags.into_iter().next(), - status: intermediate_rep.status.into_iter().next(), + name: intermediate_rep.name.into_iter().next(), }) } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for Pet - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for Tag - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into Pet - {}", - value, err)) + format!("Unable to convert header value '{value}' into Tag - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); -impl Pet { - /// Helper function to allow us to convert this model to an XML string. - /// Will panic if serialisation fails. - #[allow(dead_code)] - pub(crate) fn as_xml(&self) -> String { - serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] -#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct ReadOnlyFirst { - #[serde(rename = "bar")] - #[serde(skip_serializing_if="Option::is_none")] - pub bar: Option, - - #[serde(rename = "baz")] - #[serde(skip_serializing_if="Option::is_none")] - pub baz: Option, - -} +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into Tag - {err}")) + } + }) + }).collect::, String>>()?; -impl ReadOnlyFirst { - #[allow(clippy::new_without_default)] - pub fn new() -> ReadOnlyFirst { - ReadOnlyFirst { - bar: None, - baz: None, + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), } } } -/// Converts the ReadOnlyFirst value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde serializer -impl std::string::ToString for ReadOnlyFirst { - fn to_string(&self) -> String { - let params: Vec> = vec![ - - self.bar.as_ref().map(|bar| { - [ - "bar".to_string(), - bar.to_string(), - ].join(",") - }), - - - self.baz.as_ref().map(|baz| { - [ - "baz".to_string(), - baz.to_string(), - ].join(",") - }), +impl Tag { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} - ]; +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum TestEnumParametersEnumHeaderStringArrayParameterInner { + #[serde(rename = ">")] + GreaterThan, + #[serde(rename = "$")] + Dollar, +} - params.into_iter().flatten().collect::>().join(",") +impl std::fmt::Display for TestEnumParametersEnumHeaderStringArrayParameterInner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + TestEnumParametersEnumHeaderStringArrayParameterInner::GreaterThan => write!(f, ">"), + TestEnumParametersEnumHeaderStringArrayParameterInner::Dollar => write!(f, "$"), + } } } -/// Converts Query Parameters representation (style=form, explode=false) to a ReadOnlyFirst value -/// as specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde deserializer -impl std::str::FromStr for ReadOnlyFirst { +impl std::str::FromStr for TestEnumParametersEnumHeaderStringArrayParameterInner { type Err = String; fn from_str(s: &str) -> std::result::Result { - /// An intermediate representation of the struct to use for parsing. - #[derive(Default)] - #[allow(dead_code)] - struct IntermediateRep { - pub bar: Vec, - pub baz: Vec, - } - - let mut intermediate_rep = IntermediateRep::default(); - - // Parse into intermediate representation - let mut string_iter = s.split(','); - let mut key_result = string_iter.next(); - - while key_result.is_some() { - let val = match string_iter.next() { - Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing ReadOnlyFirst".to_string()) - }; - - if let Some(key) = key_result { - #[allow(clippy::match_single_binding)] - match key { - #[allow(clippy::redundant_clone)] - "bar" => intermediate_rep.bar.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "baz" => intermediate_rep.baz.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing ReadOnlyFirst".to_string()) - } - } - - // Get the next key - key_result = string_iter.next(); + match s { + ">" => std::result::Result::Ok(TestEnumParametersEnumHeaderStringArrayParameterInner::GreaterThan), + "$" => std::result::Result::Ok(TestEnumParametersEnumHeaderStringArrayParameterInner::Dollar), + _ => std::result::Result::Err(format!("Value not valid: {s}")), } - - // Use the intermediate representation to return the struct - std::result::Result::Ok(ReadOnlyFirst { - bar: intermediate_rep.bar.into_iter().next(), - baz: intermediate_rep.baz.into_iter().next(), - }) } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for ReadOnlyFirst - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for TestEnumParametersEnumHeaderStringArrayParameterInner - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into ReadOnlyFirst - {}", - value, err)) + format!("Unable to convert header value '{value}' into TestEnumParametersEnumHeaderStringArrayParameterInner - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl ReadOnlyFirst { + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into TestEnumParametersEnumHeaderStringArrayParameterInner - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl TestEnumParametersEnumHeaderStringArrayParameterInner { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -4993,133 +8840,248 @@ impl ReadOnlyFirst { } } -/// Model for testing reserved words -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] -#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -#[serde(rename = "Return")] -pub struct Return { - #[serde(rename = "return")] - #[serde(skip_serializing_if="Option::is_none")] - pub r#return: Option, +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum TestEnumParametersEnumHeaderStringParameter { + #[serde(rename = "_abc")] + Abc, + #[serde(rename = "-efg")] + Efg, + #[serde(rename = "(xyz)")] + LeftParenthesisXyzRightParenthesis, +} +impl std::fmt::Display for TestEnumParametersEnumHeaderStringParameter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + TestEnumParametersEnumHeaderStringParameter::Abc => write!(f, "_abc"), + TestEnumParametersEnumHeaderStringParameter::Efg => write!(f, "-efg"), + TestEnumParametersEnumHeaderStringParameter::LeftParenthesisXyzRightParenthesis => write!(f, "(xyz)"), + } + } } +impl std::str::FromStr for TestEnumParametersEnumHeaderStringParameter { + type Err = String; -impl Return { - #[allow(clippy::new_without_default)] - pub fn new() -> Return { - Return { - r#return: None, + fn from_str(s: &str) -> std::result::Result { + match s { + "_abc" => std::result::Result::Ok(TestEnumParametersEnumHeaderStringParameter::Abc), + "-efg" => std::result::Result::Ok(TestEnumParametersEnumHeaderStringParameter::Efg), + "(xyz)" => std::result::Result::Ok(TestEnumParametersEnumHeaderStringParameter::LeftParenthesisXyzRightParenthesis), + _ => std::result::Result::Err(format!("Value not valid: {s}")), } } } -/// Converts the Return value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde serializer -impl std::string::ToString for Return { - fn to_string(&self) -> String { - let params: Vec> = vec![ +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue - self.r#return.as_ref().map(|r#return| { - [ - "return".to_string(), - r#return.to_string(), - ].join(",") - }), +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; - ]; + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for TestEnumParametersEnumHeaderStringParameter - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; - params.into_iter().flatten().collect::>().join(",") + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into TestEnumParametersEnumHeaderStringParameter - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } } } -/// Converts Query Parameters representation (style=form, explode=false) to a Return value -/// as specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde deserializer -impl std::str::FromStr for Return { - type Err = String; +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; - fn from_str(s: &str) -> std::result::Result { - /// An intermediate representation of the struct to use for parsing. - #[derive(Default)] - #[allow(dead_code)] - struct IntermediateRep { - pub r#return: Vec, + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } + } +} - let mut intermediate_rep = IntermediateRep::default(); +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; - // Parse into intermediate representation - let mut string_iter = s.split(','); - let mut key_result = string_iter.next(); + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into TestEnumParametersEnumHeaderStringParameter - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl TestEnumParametersEnumHeaderStringParameter { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} + +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum TestEnumParametersEnumQueryDoubleParameter { + #[serde(rename = "1.1")] + Variant11, + #[serde(rename = "-1.2")] + Variant12, +} - while key_result.is_some() { - let val = match string_iter.next() { - Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing Return".to_string()) - }; +impl std::fmt::Display for TestEnumParametersEnumQueryDoubleParameter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + TestEnumParametersEnumQueryDoubleParameter::Variant11 => write!(f, "1.1"), + TestEnumParametersEnumQueryDoubleParameter::Variant12 => write!(f, "-1.2"), + } + } +} - if let Some(key) = key_result { - #[allow(clippy::match_single_binding)] - match key { - #[allow(clippy::redundant_clone)] - "return" => intermediate_rep.r#return.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing Return".to_string()) - } - } +impl std::str::FromStr for TestEnumParametersEnumQueryDoubleParameter { + type Err = String; - // Get the next key - key_result = string_iter.next(); + fn from_str(s: &str) -> std::result::Result { + match s { + "1.1" => std::result::Result::Ok(TestEnumParametersEnumQueryDoubleParameter::Variant11), + "-1.2" => std::result::Result::Ok(TestEnumParametersEnumQueryDoubleParameter::Variant12), + _ => std::result::Result::Err(format!("Value not valid: {s}")), } - - // Use the intermediate representation to return the struct - std::result::Result::Ok(Return { - r#return: intermediate_rep.r#return.into_iter().next(), - }) } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for Return - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for TestEnumParametersEnumQueryDoubleParameter - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into Return - {}", - value, err)) + format!("Unable to convert header value '{value}' into TestEnumParametersEnumQueryDoubleParameter - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; -impl Return { + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into TestEnumParametersEnumQueryDoubleParameter - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl TestEnumParametersEnumQueryDoubleParameter { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -5128,149 +9090,244 @@ impl Return { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] -#[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -#[serde(rename = "Tag")] -pub struct Tag { - #[serde(rename = "id")] - #[serde(skip_serializing_if="Option::is_none")] - pub id: Option, - - #[serde(rename = "name")] - #[serde(skip_serializing_if="Option::is_none")] - pub name: Option, +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(i32)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde_repr::Serialize_repr, serde_repr::Deserialize_repr, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum TestEnumParametersEnumQueryIntegerParameter { + Variant1 = 1, + Variant2 = -2, +} +impl std::fmt::Display for TestEnumParametersEnumQueryIntegerParameter { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", *self as i32) + } } +impl std::str::FromStr for TestEnumParametersEnumQueryIntegerParameter { + type Err = String; -impl Tag { - #[allow(clippy::new_without_default)] - pub fn new() -> Tag { - Tag { - id: None, - name: None, + fn from_str(s: &str) -> std::result::Result { + match s.parse::() { + std::result::Result::Ok(1) => std::result::Result::Ok(TestEnumParametersEnumQueryIntegerParameter::Variant1), + std::result::Result::Ok(-2) => std::result::Result::Ok(TestEnumParametersEnumQueryIntegerParameter::Variant2), + _ => std::result::Result::Err(format!("Value not valid: {s}")), } } } -/// Converts the Tag value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde serializer -impl std::string::ToString for Tag { - fn to_string(&self) -> String { - let params: Vec> = vec![ - - self.id.as_ref().map(|id| { - [ - "id".to_string(), - id.to_string(), - ].join(",") - }), +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; - self.name.as_ref().map(|name| { - [ - "name".to_string(), - name.to_string(), - ].join(",") - }), + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for TestEnumParametersEnumQueryIntegerParameter - value: {hdr_value} is invalid {e}")) + } + } +} - ]; +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; - params.into_iter().flatten().collect::>().join(",") + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into TestEnumParametersEnumQueryIntegerParameter - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } } } -/// Converts Query Parameters representation (style=form, explode=false) to a Tag value -/// as specified in https://swagger.io/docs/specification/serialization/ -/// Should be implemented in a serde deserializer -impl std::str::FromStr for Tag { - type Err = String; +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; - fn from_str(s: &str) -> std::result::Result { - /// An intermediate representation of the struct to use for parsing. - #[derive(Default)] - #[allow(dead_code)] - struct IntermediateRep { - pub id: Vec, - pub name: Vec, + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } + } +} - let mut intermediate_rep = IntermediateRep::default(); +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; - // Parse into intermediate representation - let mut string_iter = s.split(','); - let mut key_result = string_iter.next(); + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into TestEnumParametersEnumQueryIntegerParameter - {err}")) + } + }) + }).collect::, String>>()?; - while key_result.is_some() { - let val = match string_iter.next() { - Some(x) => x, - None => return std::result::Result::Err("Missing value while parsing Tag".to_string()) - }; + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} - if let Some(key) = key_result { - #[allow(clippy::match_single_binding)] - match key { - #[allow(clippy::redundant_clone)] - "id" => intermediate_rep.id.push(::from_str(val).map_err(|x| x.to_string())?), - #[allow(clippy::redundant_clone)] - "name" => intermediate_rep.name.push(::from_str(val).map_err(|x| x.to_string())?), - _ => return std::result::Result::Err("Unexpected key while parsing Tag".to_string()) - } - } +impl TestEnumParametersEnumQueryIntegerParameter { + /// Helper function to allow us to convert this model to an XML string. + /// Will panic if serialisation fails. + #[allow(dead_code)] + pub(crate) fn as_xml(&self) -> String { + serde_xml_rs::to_string(&self).expect("impossible to fail to serialize") + } +} - // Get the next key - key_result = string_iter.next(); +/// Form parameter enum test (string) +/// Enumeration of values. +/// Since this enum's variants do not hold data, we can easily define them as `#[repr(C)]` +/// which helps with FFI. +#[allow(non_camel_case_types)] +#[repr(C)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize, Hash)] +#[cfg_attr(feature = "validate", derive(Validate))] +#[cfg_attr(feature = "conversion", derive(frunk_enum_derive::LabelledGenericEnum))] +pub enum TestEnumParametersRequestEnumFormString { + #[serde(rename = "_abc")] + Abc, + #[serde(rename = "-efg")] + Efg, + #[serde(rename = "(xyz)")] + LeftParenthesisXyzRightParenthesis, +} + +impl std::fmt::Display for TestEnumParametersRequestEnumFormString { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match *self { + TestEnumParametersRequestEnumFormString::Abc => write!(f, "_abc"), + TestEnumParametersRequestEnumFormString::Efg => write!(f, "-efg"), + TestEnumParametersRequestEnumFormString::LeftParenthesisXyzRightParenthesis => write!(f, "(xyz)"), } + } +} - // Use the intermediate representation to return the struct - std::result::Result::Ok(Tag { - id: intermediate_rep.id.into_iter().next(), - name: intermediate_rep.name.into_iter().next(), - }) +impl std::str::FromStr for TestEnumParametersRequestEnumFormString { + type Err = String; + + fn from_str(s: &str) -> std::result::Result { + match s { + "_abc" => std::result::Result::Ok(TestEnumParametersRequestEnumFormString::Abc), + "-efg" => std::result::Result::Ok(TestEnumParametersRequestEnumFormString::Efg), + "(xyz)" => std::result::Result::Ok(TestEnumParametersRequestEnumFormString::LeftParenthesisXyzRightParenthesis), + _ => std::result::Result::Err(format!("Value not valid: {s}")), + } } } -// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom> for hyper::header::HeaderValue { +impl std::convert::TryFrom> for hyper::header::HeaderValue { type Error = String; - fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { let hdr_value = hdr_value.to_string(); match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for Tag - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for TestEnumParametersRequestEnumFormString - value: {hdr_value} is invalid {e}")) } } } #[cfg(any(feature = "client", feature = "server"))] -impl std::convert::TryFrom for header::IntoHeaderValue { +impl std::convert::TryFrom for header::IntoHeaderValue { type Error = String; fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { match hdr_value.to_str() { std::result::Result::Ok(value) => { - match ::from_str(value) { + match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into Tag - {}", - value, err)) + format!("Unable to convert header value '{value}' into TestEnumParametersRequestEnumFormString - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); -impl Tag { + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into TestEnumParametersRequestEnumFormString - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +impl TestEnumParametersRequestEnumFormString { /// Helper function to allow us to convert this model to an XML string. /// Will panic if serialisation fails. #[allow(dead_code)] @@ -5279,45 +9336,73 @@ impl Tag { } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] #[serde(rename = "User")] pub struct User { #[serde(rename = "id")] + #[serde(skip_serializing_if="Option::is_none")] pub id: Option, #[serde(rename = "username")] + #[serde(skip_serializing_if="Option::is_none")] pub username: Option, #[serde(rename = "firstName")] + #[serde(skip_serializing_if="Option::is_none")] pub first_name: Option, #[serde(rename = "lastName")] + #[serde(skip_serializing_if="Option::is_none")] pub last_name: Option, #[serde(rename = "email")] + #[serde(skip_serializing_if="Option::is_none")] pub email: Option, #[serde(rename = "password")] + #[serde(skip_serializing_if="Option::is_none")] pub password: Option, #[serde(rename = "phone")] + #[serde(skip_serializing_if="Option::is_none")] pub phone: Option, /// User Status #[serde(rename = "userStatus")] + #[serde(skip_serializing_if="Option::is_none")] pub user_status: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for User { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for User { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl User { #[allow(clippy::new_without_default)] @@ -5336,83 +9421,67 @@ impl User { } /// Converts the User value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for User { - fn to_string(&self) -> String { +impl std::fmt::Display for User { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.id.as_ref().map(|id| { [ "id".to_string(), id.to_string(), ].join(",") }), - - self.username.as_ref().map(|username| { [ "username".to_string(), username.to_string(), ].join(",") }), - - self.first_name.as_ref().map(|first_name| { [ "firstName".to_string(), first_name.to_string(), ].join(",") }), - - self.last_name.as_ref().map(|last_name| { [ "lastName".to_string(), last_name.to_string(), ].join(",") }), - - self.email.as_ref().map(|email| { [ "email".to_string(), email.to_string(), ].join(",") }), - - self.password.as_ref().map(|password| { [ "password".to_string(), password.to_string(), ].join(",") }), - - self.phone.as_ref().map(|phone| { [ "phone".to_string(), phone.to_string(), ].join(",") }), - - self.user_status.as_ref().map(|user_status| { [ "userStatus".to_string(), user_status.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a User value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for User { type Err = String; @@ -5496,8 +9565,7 @@ impl std::convert::TryFrom> for hyper::header::Hea match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for User - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for User - value: {hdr_value} is invalid {e}")) } } } @@ -5512,17 +9580,57 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into User - {}", - value, err)) + format!("Unable to convert header value '{value}' into User - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into User - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} impl User { /// Helper function to allow us to convert this model to an XML string. diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/server/mod.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/server/mod.rs index 887af3ab9bf5..83e6ca4f40a6 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/server/mod.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/server/mod.rs @@ -1,10 +1,14 @@ +use bytes::Bytes; use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt}; -use hyper::{Request, Response, StatusCode, Body, HeaderMap}; +use http_body_util::{combinators::BoxBody, Full}; +use hyper::{body::{Body, Incoming}, HeaderMap, Request, Response, StatusCode}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; use log::warn; +#[cfg(feature = "validate")] +use serde_valid::Validate; #[allow(unused_imports)] use std::convert::{TryFrom, TryInto}; -use std::error::Error; +use std::{convert::Infallible, error::Error}; use std::future::Future; use std::marker::PhantomData; use std::task::{Context, Poll}; @@ -13,14 +17,14 @@ pub use swagger::auth::Authorization; use swagger::auth::Scopes; use url::form_urlencoded; use multipart::server::Multipart; -use multipart::server::save::SaveResult; +use multipart::server::save::{PartialReason, SaveResult}; #[allow(unused_imports)] use crate::{models, header, AuthenticationApi}; pub use crate::context; -type ServiceFuture = BoxFuture<'static, Result, crate::ServiceError>>; +type ServiceFuture = BoxFuture<'static, Result>, crate::ServiceError>>; use crate::{Api, TestSpecialTagsResponse, @@ -30,33 +34,33 @@ use crate::{Api, FakeOuterNumberSerializeResponse, FakeOuterStringSerializeResponse, FakeResponseWithNumericalDescriptionResponse, - HyphenParamResponse, TestBodyWithQueryParamsResponse, TestClientModelResponse, TestEndpointParametersResponse, TestEnumParametersResponse, TestInlineAdditionalPropertiesResponse, TestJsonFormDataResponse, + HyphenParamResponse, TestClassnameResponse, AddPetResponse, - DeletePetResponse, FindPetsByStatusResponse, FindPetsByTagsResponse, - GetPetByIdResponse, UpdatePetResponse, + DeletePetResponse, + GetPetByIdResponse, UpdatePetWithFormResponse, UploadFileResponse, - DeleteOrderResponse, GetInventoryResponse, - GetOrderByIdResponse, PlaceOrderResponse, + DeleteOrderResponse, + GetOrderByIdResponse, CreateUserResponse, CreateUsersWithArrayInputResponse, CreateUsersWithListInputResponse, - DeleteUserResponse, - GetUserByNameResponse, LoginUserResponse, LogoutUserResponse, + DeleteUserResponse, + GetUserByNameResponse, UpdateUserResponse }; @@ -157,28 +161,65 @@ mod paths { } -pub struct MakeService where +pub struct MakeService +where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { api_impl: T, + multipart_form_size_limit: Option, marker: PhantomData, + validation: bool } -impl MakeService where +impl MakeService +where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { pub fn new(api_impl: T) -> Self { MakeService { api_impl, - marker: PhantomData + multipart_form_size_limit: Some(8 * 1024 * 1024), + marker: PhantomData, + validation: false } } + + /// Configure size limit when inspecting a multipart/form body. + /// + /// Default is 8 MiB. + /// + /// Set to None for no size limit, which presents a Denial of Service attack risk. + pub fn multipart_form_size_limit(mut self, multipart_form_size_limit: Option) -> Self { + self.multipart_form_size_limit = multipart_form_size_limit; + self + } + + // Turn on/off validation for the service being made. + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation; + } } +impl Clone for MakeService +where + T: Api + Clone + Send + 'static, + C: Has + Has> + Send + Sync + 'static +{ + fn clone(&self) -> Self { + Self { + api_impl: self.api_impl.clone(), + multipart_form_size_limit: Some(8 * 1024 * 1024), + marker: PhantomData, + validation: self.validation + } + } +} -impl hyper::service::Service for MakeService where +impl hyper::service::Service for MakeService +where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { @@ -186,43 +227,85 @@ impl hyper::service::Service for MakeService where type Error = crate::ServiceError; type Future = future::Ready>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } + fn call(&self, target: Target) -> Self::Future { + let service = Service::new(self.api_impl.clone(), self.validation) + .multipart_form_size_limit(self.multipart_form_size_limit); - fn call(&mut self, target: Target) -> Self::Future { - future::ok(Service::new( - self.api_impl.clone(), - )) + future::ok(service) } } -fn method_not_allowed() -> Result, crate::ServiceError> { +fn method_not_allowed() -> Result>, crate::ServiceError> { Ok( Response::builder().status(StatusCode::METHOD_NOT_ALLOWED) - .body(Body::empty()) + .body(BoxBody::new(http_body_util::Empty::new())) .expect("Unable to create Method Not Allowed response") ) } +#[allow(unused_macros)] +#[cfg(not(feature = "validate"))] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => (); +} + +#[allow(unused_macros)] +#[cfg(feature = "validate")] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => { + let $parameter = if $validation { + match $parameter.validate() { + Ok(()) => $parameter, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .header(CONTENT_TYPE, mime::TEXT_PLAIN.as_ref()) + .body(BoxBody::new(format!("Invalid value in body parameter {}: {}", $base_name, e))) + .expect(&format!("Unable to create Bad Request response for invalid value in body parameter {}", $base_name))), + } + } else { + $parameter + }; + } +} + pub struct Service where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { api_impl: T, + multipart_form_size_limit: Option, marker: PhantomData, + // Enable regex pattern validation of received JSON models + validation: bool, } impl Service where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { - pub fn new(api_impl: T) -> Self { + pub fn new(api_impl: T, validation: bool) -> Self { Service { api_impl, - marker: PhantomData + multipart_form_size_limit: Some(8 * 1024 * 1024), + marker: PhantomData, + validation, } } + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation + } + + + /// Configure size limit when extracting a multipart/form body. + /// + /// Default is 8 MiB. + /// + /// Set to None for no size limit, which presents a Denial of Service attack risk. + pub fn multipart_form_size_limit(mut self, multipart_form_size_limit: Option) -> Self { + self.multipart_form_size_limit = multipart_form_size_limit; + self + } } impl Clone for Service where @@ -232,55 +315,76 @@ impl Clone for Service where fn clone(&self) -> Self { Service { api_impl: self.api_impl.clone(), + multipart_form_size_limit: Some(8 * 1024 * 1024), marker: self.marker, + validation: self.validation, } } } -impl hyper::service::Service<(Request, C)> for Service where +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + +fn body_from_str(s: &str) -> BoxBody { + BoxBody::new(Full::new(Bytes::copy_from_slice(s.as_bytes()))) +} + +impl hyper::service::Service<(Request, C)> for Service where T: Api + Clone + Send + Sync + 'static, - C: Has + Has> + Send + Sync + 'static + C: Has + Has> + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, { - type Response = Response; + type Response = Response>; type Error = crate::ServiceError; type Future = ServiceFuture; - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - self.api_impl.poll_ready(cx) - } - - fn call(&mut self, req: (Request, C)) -> Self::Future { async fn run(mut api_impl: T, req: (Request, C)) -> Result, crate::ServiceError> where - T: Api + Clone + Send + 'static, - C: Has + Has> + Send + Sync + 'static - { - let (request, context) = req; - let (parts, body) = request.into_parts(); - let (method, uri, headers) = (parts.method, parts.uri, parts.headers); - let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); - - match method { + fn call(&self, req: (Request, C)) -> Self::Future { + async fn run( + mut api_impl: T, + req: (Request, C), + validation: bool, + multipart_form_size_limit: Option, + ) -> Result>, crate::ServiceError> + where + T: Api + Clone + Send + 'static, + C: Has + Has> + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, + { + let (request, context) = req; + let (parts, body) = request.into_parts(); + let (method, uri, headers) = (parts.method, parts.uri, parts.headers); + let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); + + match method { // TestSpecialTags - PATCH /another-fake/dummy hyper::Method::PATCH if path.matched(paths::ID_ANOTHER_FAKE_DUMMY) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_body: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); + warn!("Ignoring unknown field in body: {path}"); unused_elements.push(path.to_string()); }) { Ok(param_body) => param_body, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter body - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), } + } else { None }; @@ -288,15 +392,18 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_body) => param_body, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter body")) + .body(BoxBody::new("Missing required body parameter body".to_string())) .expect("Unable to create Bad Request response for missing body parameter body")), }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); + let result = api_impl.test_special_tags( param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -305,10 +412,9 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { TestSpecialTagsResponse::SuccessfulOperation @@ -317,17 +423,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for TEST_SPECIAL_TAGS_SUCCESSFUL_OPERATION")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -335,8 +442,8 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, @@ -345,7 +452,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.call123example( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -356,13 +463,14 @@ impl hyper::service::Service<(Request, C)> for Service where Call123exampleResponse::Success => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -371,31 +479,32 @@ impl hyper::service::Service<(Request, C)> for Service where // FakeOuterBooleanSerialize - POST /fake/outer/boolean hyper::Method::POST if path.matched(paths::ID_FAKE_OUTER_BOOLEAN) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_body: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); - match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) { - Ok(param_body) => param_body, - Err(_) => None, - } + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {path}"); + unused_elements.push(path.to_string()); + }).unwrap_or_default() + } else { None }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); + let result = api_impl.fake_outer_boolean_serialize( param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -404,10 +513,9 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { FakeOuterBooleanSerializeResponse::OutputBoolean @@ -416,17 +524,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("*/*") - .expect("Unable to create Content-Type header for FAKE_OUTER_BOOLEAN_SERIALIZE_OUTPUT_BOOLEAN")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("*/*")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -434,38 +543,39 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, // FakeOuterCompositeSerialize - POST /fake/outer/composite hyper::Method::POST if path.matched(paths::ID_FAKE_OUTER_COMPOSITE) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_body: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); - match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) { - Ok(param_body) => param_body, - Err(_) => None, - } + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {path}"); + unused_elements.push(path.to_string()); + }).unwrap_or_default() + } else { None }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); + let result = api_impl.fake_outer_composite_serialize( param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -474,10 +584,9 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { FakeOuterCompositeSerializeResponse::OutputComposite @@ -486,17 +595,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("*/*") - .expect("Unable to create Content-Type header for FAKE_OUTER_COMPOSITE_SERIALIZE_OUTPUT_COMPOSITE")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("*/*")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -504,38 +614,39 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, // FakeOuterNumberSerialize - POST /fake/outer/number hyper::Method::POST if path.matched(paths::ID_FAKE_OUTER_NUMBER) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_body: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); - match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) { - Ok(param_body) => param_body, - Err(_) => None, - } + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {path}"); + unused_elements.push(path.to_string()); + }).unwrap_or_default() + } else { None }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); + let result = api_impl.fake_outer_number_serialize( param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -544,10 +655,9 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { FakeOuterNumberSerializeResponse::OutputNumber @@ -556,17 +666,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("*/*") - .expect("Unable to create Content-Type header for FAKE_OUTER_NUMBER_SERIALIZE_OUTPUT_NUMBER")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("*/*")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -574,38 +685,39 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, // FakeOuterStringSerialize - POST /fake/outer/string hyper::Method::POST if path.matched(paths::ID_FAKE_OUTER_STRING) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_body: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); - match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) { - Ok(param_body) => param_body, - Err(_) => None, - } + serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {path}"); + unused_elements.push(path.to_string()); + }).unwrap_or_default() + } else { None }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); + let result = api_impl.fake_outer_string_serialize( param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -614,10 +726,9 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { FakeOuterStringSerializeResponse::OutputString @@ -626,17 +737,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("*/*") - .expect("Unable to create Content-Type header for FAKE_OUTER_STRING_SERIALIZE_OUTPUT_STRING")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("*/*")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -644,8 +756,8 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, @@ -654,7 +766,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.fake_response_with_numerical_description( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -665,66 +777,14 @@ impl hyper::service::Service<(Request, C)> for Service where FakeResponseWithNumericalDescriptionResponse::Status200 => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); - }, - } - - Ok(response) - }, - - // HyphenParam - GET /fake/hyphenParam/{hyphen-param} - hyper::Method::GET if path.matched(paths::ID_FAKE_HYPHENPARAM_HYPHEN_PARAM) => { - // Path parameters - let path: &str = uri.path(); - let path_params = - paths::REGEX_FAKE_HYPHENPARAM_HYPHEN_PARAM - .captures(path) - .unwrap_or_else(|| - panic!("Path {} matched RE FAKE_HYPHENPARAM_HYPHEN_PARAM in set but failed match against \"{}\"", path, paths::REGEX_FAKE_HYPHENPARAM_HYPHEN_PARAM.as_str()) - ); - - let param_hyphen_param = match percent_encoding::percent_decode(path_params["hyphen-param"].as_bytes()).decode_utf8() { - Ok(param_hyphen_param) => match param_hyphen_param.parse::() { - Ok(param_hyphen_param) => param_hyphen_param, - Err(e) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse path parameter hyphen-param: {}", e))) - .expect("Unable to create Bad Request response for invalid path parameter")), - }, - Err(_) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["hyphen-param"]))) - .expect("Unable to create Bad Request response for invalid percent decode")) - }; - - let result = api_impl.hyphen_param( - param_hyphen_param, - &context - ).await; - let mut response = Response::new(Body::empty()); - response.headers_mut().insert( - HeaderName::from_static("x-span-id"), - HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) - .expect("Unable to create X-Span-ID header value")); - match result { - Ok(rsp) => match rsp { - HyphenParamResponse::Success - => { - *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -746,7 +806,7 @@ impl hyper::service::Service<(Request, C)> for Service where Ok(param_query) => Some(param_query), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse query parameter query - doesn't match schema: {}", e))) + .body(body_from_string(format!("Couldn't parse query parameter query - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid query parameter query")), } }, @@ -756,29 +816,30 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_query) => param_query, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required query parameter query")) + .body(body_from_str("Missing required query parameter query")) .expect("Unable to create Bad Request response for missing query parameter query")), }; - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_body: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); + warn!("Ignoring unknown field in body: {path}"); unused_elements.push(path.to_string()); }) { Ok(param_body) => param_body, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter body - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), } + } else { None }; @@ -786,16 +847,19 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_body) => param_body, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter body")) + .body(BoxBody::new("Missing required body parameter body".to_string())) .expect("Unable to create Bad Request response for missing body parameter body")), }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); + let result = api_impl.test_body_with_query_params( param_query, param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -804,22 +868,22 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { TestBodyWithQueryParamsResponse::Success => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -827,32 +891,33 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, // TestClientModel - PATCH /fake hyper::Method::PATCH if path.matched(paths::ID_FAKE) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_body: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); + warn!("Ignoring unknown field in body: {path}"); unused_elements.push(path.to_string()); }) { Ok(param_body) => param_body, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter body - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), } + } else { None }; @@ -860,15 +925,18 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_body) => param_body, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter body")) + .body(BoxBody::new("Missing required body parameter body".to_string())) .expect("Unable to create Bad Request response for missing body parameter body")), }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); + let result = api_impl.test_client_model( param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -877,10 +945,9 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { TestClientModelResponse::SuccessfulOperation @@ -889,17 +956,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for TEST_CLIENT_MODEL_SUCCESSFUL_OPERATION")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -907,8 +975,8 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, @@ -919,26 +987,47 @@ impl hyper::service::Service<(Request, C)> for Service where Some(ref authorization) => authorization, None => return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) + .body(body_from_str("Unauthenticated")) .expect("Unable to create Authentication Forbidden response")), }; } + // Handle body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); + match result { + Ok(body) => { // Form parameters - let param_integer = Some(56); - let param_int32 = Some(56); - let param_int64 = Some(789); - let param_number = 8.14; - let param_float = Some(3.4); - let param_double = 1.2; - let param_string = Some("string_example".to_string()); - let param_pattern_without_delimiter = "pattern_without_delimiter_example".to_string(); - let param_byte = swagger::ByteArray(Vec::from("BYTE_ARRAY_DATA_HERE")); - let param_binary = Some(swagger::ByteArray(Vec::from("BINARY_DATA_HERE"))); - let param_date = None; - let param_date_time = None; - let param_password = Some("password_example".to_string()); - let param_callback = Some("callback_example".to_string()); + let param_integer = + Some(56); + let param_int32 = + Some(56); + let param_int64 = + Some(789); + let param_number = + 8.14; + let param_float = + Some(3.4); + let param_double = + 1.2; + let param_string = + Some("string_example".to_string()); + let param_pattern_without_delimiter = + "pattern_without_delimiter_example".to_string(); + let param_byte = + swagger::ByteArray(Vec::from("BYTE_ARRAY_DATA_HERE")); + let param_binary = + Some(swagger::ByteArray(Vec::from("BINARY_DATA_HERE"))); + let param_date = + None; + let param_date_time = + None; + let param_password = + Some("password_example".to_string()); + let param_callback = + Some("callback_example".to_string()); + let result = api_impl.test_endpoint_parameters( param_number, @@ -957,7 +1046,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_callback, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -968,21 +1057,29 @@ impl hyper::service::Service<(Request, C)> for Service where TestEndpointParametersResponse::InvalidUsernameSupplied => { *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, TestEndpointParametersResponse::UserNotFound => { *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } Ok(response) + }, + Err(e) => Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), + } }, // TestEnumParameters - GET /fake @@ -991,13 +1088,13 @@ impl hyper::service::Service<(Request, C)> for Service where let param_enum_header_string_array = headers.get(HeaderName::from_static("enum_header_string_array")); let param_enum_header_string_array = match param_enum_header_string_array { - Some(v) => match header::IntoHeaderValue::>::try_from((*v).clone()) { + Some(v) => match header::IntoHeaderValue::>::try_from((*v).clone()) { Ok(result) => Some(result.0), Err(err) => { return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Invalid header enum_header_string_array - {}", err))) + .body(body_from_string(format!("Invalid header enum_header_string_array - {err}"))) .expect("Unable to create Bad Request response for invalid header enum_header_string_array")); }, @@ -1009,13 +1106,13 @@ impl hyper::service::Service<(Request, C)> for Service where let param_enum_header_string = headers.get(HeaderName::from_static("enum_header_string")); let param_enum_header_string = match param_enum_header_string { - Some(v) => match header::IntoHeaderValue::::try_from((*v).clone()) { + Some(v) => match header::IntoHeaderValue::::try_from((*v).clone()) { Ok(result) => Some(result.0), Err(err) => { return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Invalid header enum_header_string - {}", err))) + .body(body_from_string(format!("Invalid header enum_header_string - {err}"))) .expect("Unable to create Bad Request response for invalid header enum_header_string")); }, @@ -1040,55 +1137,69 @@ impl hyper::service::Service<(Request, C)> for Service where let param_enum_query_string = match param_enum_query_string { Some(param_enum_query_string) => { let param_enum_query_string = - ::from_str + ::from_str (¶m_enum_query_string); match param_enum_query_string { Ok(param_enum_query_string) => Some(param_enum_query_string), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse query parameter enum_query_string - doesn't match schema: {}", e))) + .body(body_from_string(format!("Couldn't parse query parameter enum_query_string - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid query parameter enum_query_string")), } }, None => None, }; + #[cfg(not(feature = "validate"))] + run_validation!(param_enum_query_string, "enum_query_string", validation); let param_enum_query_integer = query_params.iter().filter(|e| e.0 == "enum_query_integer").map(|e| e.1.clone()) .next(); let param_enum_query_integer = match param_enum_query_integer { Some(param_enum_query_integer) => { let param_enum_query_integer = - ::from_str + ::from_str (¶m_enum_query_integer); match param_enum_query_integer { Ok(param_enum_query_integer) => Some(param_enum_query_integer), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse query parameter enum_query_integer - doesn't match schema: {}", e))) + .body(body_from_string(format!("Couldn't parse query parameter enum_query_integer - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid query parameter enum_query_integer")), } }, None => None, }; + #[cfg(not(feature = "validate"))] + run_validation!(param_enum_query_integer, "enum_query_integer", validation); let param_enum_query_double = query_params.iter().filter(|e| e.0 == "enum_query_double").map(|e| e.1.clone()) .next(); let param_enum_query_double = match param_enum_query_double { Some(param_enum_query_double) => { let param_enum_query_double = - ::from_str + ::from_str (¶m_enum_query_double); match param_enum_query_double { Ok(param_enum_query_double) => Some(param_enum_query_double), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse query parameter enum_query_double - doesn't match schema: {}", e))) + .body(body_from_string(format!("Couldn't parse query parameter enum_query_double - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid query parameter enum_query_double")), } }, None => None, }; + #[cfg(not(feature = "validate"))] + run_validation!(param_enum_query_double, "enum_query_double", validation); + // Handle body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); + match result { + Ok(body) => { // Form parameters - let param_enum_form_string = Some("enum_form_string_example".to_string()); + let param_enum_form_string = + Some(models::TestEnumParametersRequestEnumFormString::Abc); + let result = api_impl.test_enum_parameters( param_enum_header_string_array.as_ref(), @@ -1100,7 +1211,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_enum_form_string, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1111,44 +1222,53 @@ impl hyper::service::Service<(Request, C)> for Service where TestEnumParametersResponse::InvalidRequest => { *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, TestEnumParametersResponse::NotFound => { *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } Ok(response) + }, + Err(e) => Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), + } }, // TestInlineAdditionalProperties - POST /fake/inline-additionalProperties hyper::Method::POST if path.matched(paths::ID_FAKE_INLINE_ADDITIONALPROPERTIES) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_param: Option> = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); + warn!("Ignoring unknown field in body: {path}"); unused_elements.push(path.to_string()); }) { Ok(param_param) => param_param, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter param - doesn't match schema: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter param - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter param due to schema")), } + } else { None }; @@ -1156,15 +1276,16 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_param) => param_param, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter param")) + .body(BoxBody::new("Missing required body parameter param".to_string())) .expect("Unable to create Bad Request response for missing body parameter param")), }; + let result = api_impl.test_inline_additional_properties( param_param, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1173,22 +1294,22 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { TestInlineAdditionalPropertiesResponse::SuccessfulOperation => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1196,23 +1317,32 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter param: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter param")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, // TestJsonFormData - GET /fake/jsonFormData hyper::Method::GET if path.matched(paths::ID_FAKE_JSONFORMDATA) => { + // Handle body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); + match result { + Ok(body) => { // Form parameters - let param_param = "param_example".to_string(); - let param_param2 = "param2_example".to_string(); + let param_param = + "param_example".to_string(); + let param_param2 = + "param2_example".to_string(); + let result = api_impl.test_json_form_data( param_param, param_param2, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1223,13 +1353,74 @@ impl hyper::service::Service<(Request, C)> for Service where TestJsonFormDataResponse::SuccessfulOperation => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = body_from_str("An internal error occurred"); + }, + } + + Ok(response) + }, + Err(e) => Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), + } + }, + + // HyphenParam - GET /fake/hyphenParam/{hyphen-param} + hyper::Method::GET if path.matched(paths::ID_FAKE_HYPHENPARAM_HYPHEN_PARAM) => { + // Path parameters + let path: &str = uri.path(); + let path_params = + paths::REGEX_FAKE_HYPHENPARAM_HYPHEN_PARAM + .captures(path) + .unwrap_or_else(|| + panic!("Path {} matched RE FAKE_HYPHENPARAM_HYPHEN_PARAM in set but failed match against \"{}\"", path, paths::REGEX_FAKE_HYPHENPARAM_HYPHEN_PARAM.as_str()) + ); + + let param_hyphen_param = match percent_encoding::percent_decode(path_params["hyphen-param"].as_bytes()).decode_utf8() { + Ok(param_hyphen_param) => match param_hyphen_param.parse::() { + Ok(param_hyphen_param) => param_hyphen_param, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Couldn't parse path parameter hyphen-param: {e}"))) + .expect("Unable to create Bad Request response for invalid path parameter")), + }, + Err(_) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["hyphen-param"]))) + .expect("Unable to create Bad Request response for invalid percent decode")) + }; + + let result = api_impl.hyphen_param( + param_hyphen_param, + &context + ).await; + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) + .expect("Unable to create X-Span-ID header value")); + + match result { + Ok(rsp) => match rsp { + HyphenParamResponse::Success + => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1243,30 +1434,31 @@ impl hyper::service::Service<(Request, C)> for Service where Some(ref authorization) => authorization, None => return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) + .body(body_from_str("Unauthenticated")) .expect("Unable to create Authentication Forbidden response")), }; } - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_body: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); + warn!("Ignoring unknown field in body: {path}"); unused_elements.push(path.to_string()); }) { Ok(param_body) => param_body, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter body - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), } + } else { None }; @@ -1274,15 +1466,18 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_body) => param_body, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter body")) + .body(BoxBody::new("Missing required body parameter body".to_string())) .expect("Unable to create Bad Request response for missing body parameter body")), }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); + let result = api_impl.test_classname( param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1291,10 +1486,9 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { TestClassnameResponse::SuccessfulOperation @@ -1303,17 +1497,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for TEST_CLASSNAME_SUCCESSFUL_OPERATION")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1321,8 +1516,8 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, @@ -1333,7 +1528,7 @@ impl hyper::service::Service<(Request, C)> for Service where Some(ref authorization) => authorization, None => return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) + .body(body_from_str("Unauthenticated")) .expect("Unable to create Authentication Forbidden response")), }; @@ -1348,9 +1543,9 @@ impl hyper::service::Service<(Request, C)> for Service where let missing_scopes = required_scopes.difference(scopes); return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from(missing_scopes.fold( + .body(BoxBody::new(missing_scopes.fold( "Insufficient authorization, missing scopes".to_string(), - |s, scope| format!("{} {}", s, scope)) + |s, scope| format!("{s} {scope}")) )) .expect("Unable to create Authentication Insufficient response") ); @@ -1358,25 +1553,26 @@ impl hyper::service::Service<(Request, C)> for Service where } } - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_body: Option = if !body.is_empty() { let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); + warn!("Ignoring unknown field in body: {path}"); unused_elements.push(path.to_string()); }) { Ok(param_body) => param_body, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter body - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), } + } else { None }; @@ -1384,15 +1580,18 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_body) => param_body, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter body")) + .body(BoxBody::new("Missing required body parameter body".to_string())) .expect("Unable to create Bad Request response for missing body parameter body")), }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); + let result = api_impl.add_pet( param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1401,22 +1600,22 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { AddPetResponse::InvalidInput => { *response.status_mut() = StatusCode::from_u16(405).expect("Unable to turn 405 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1424,19 +1623,19 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, - // DeletePet - DELETE /pet/{petId} - hyper::Method::DELETE if path.matched(paths::ID_PET_PETID) => { + // FindPetsByStatus - GET /pet/findByStatus + hyper::Method::GET if path.matched(paths::ID_PET_FINDBYSTATUS) => { { let authorization = match *(&context as &dyn Has>).get() { Some(ref authorization) => authorization, None => return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) + .body(body_from_str("Unauthenticated")) .expect("Unable to create Authentication Forbidden response")), }; @@ -1451,9 +1650,9 @@ impl hyper::service::Service<(Request, C)> for Service where let missing_scopes = required_scopes.difference(scopes); return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from(missing_scopes.fold( + .body(BoxBody::new(missing_scopes.fold( "Insufficient authorization, missing scopes".to_string(), - |s, scope| format!("{} {}", s, scope)) + |s, scope| format!("{s} {scope}")) )) .expect("Unable to create Authentication Insufficient response") ); @@ -1461,121 +1660,17 @@ impl hyper::service::Service<(Request, C)> for Service where } } - // Path parameters - let path: &str = uri.path(); - let path_params = - paths::REGEX_PET_PETID - .captures(path) - .unwrap_or_else(|| - panic!("Path {} matched RE PET_PETID in set but failed match against \"{}\"", path, paths::REGEX_PET_PETID.as_str()) - ); - - let param_pet_id = match percent_encoding::percent_decode(path_params["petId"].as_bytes()).decode_utf8() { - Ok(param_pet_id) => match param_pet_id.parse::() { - Ok(param_pet_id) => param_pet_id, - Err(e) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse path parameter petId: {}", e))) - .expect("Unable to create Bad Request response for invalid path parameter")), - }, - Err(_) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["petId"]))) - .expect("Unable to create Bad Request response for invalid percent decode")) - }; - - // Header parameters - let param_api_key = headers.get(HeaderName::from_static("api_key")); - - let param_api_key = match param_api_key { - Some(v) => match header::IntoHeaderValue::::try_from((*v).clone()) { - Ok(result) => - Some(result.0), - Err(err) => { - return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Invalid header api_key - {}", err))) - .expect("Unable to create Bad Request response for invalid header api_key")); - - }, - }, - None => { - None - } - }; - - let result = api_impl.delete_pet( - param_pet_id, - param_api_key, - &context - ).await; - let mut response = Response::new(Body::empty()); - response.headers_mut().insert( - HeaderName::from_static("x-span-id"), - HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) - .expect("Unable to create X-Span-ID header value")); - - match result { - Ok(rsp) => match rsp { - DeletePetResponse::InvalidPetValue - => { - *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); - }, - } - - Ok(response) - }, - - // FindPetsByStatus - GET /pet/findByStatus - hyper::Method::GET if path.matched(paths::ID_PET_FINDBYSTATUS) => { - { - let authorization = match *(&context as &dyn Has>).get() { - Some(ref authorization) => authorization, - None => return Ok(Response::builder() - .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) - .expect("Unable to create Authentication Forbidden response")), - }; - - // Authorization - if let Scopes::Some(ref scopes) = authorization.scopes { - let required_scopes: std::collections::BTreeSet = vec![ - "write:pets".to_string(), // modify pets in your account - "read:pets".to_string(), // read your pets - ].into_iter().collect(); - - if !required_scopes.is_subset(scopes) { - let missing_scopes = required_scopes.difference(scopes); - return Ok(Response::builder() - .status(StatusCode::FORBIDDEN) - .body(Body::from(missing_scopes.fold( - "Insufficient authorization, missing scopes".to_string(), - |s, scope| format!("{} {}", s, scope)) - )) - .expect("Unable to create Authentication Insufficient response") - ); - } - } - } - - // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) - let query_params = form_urlencoded::parse(uri.query().unwrap_or_default().as_bytes()).collect::>(); - let param_status = query_params.iter().filter(|e| e.0 == "status").map(|e| e.1.clone()) - .filter_map(|param_status| param_status.parse().ok()) - .collect::>(); + // Query parameters (note that non-required or collection query parameters will ignore garbage values, rather than causing a 400 response) + let query_params = form_urlencoded::parse(uri.query().unwrap_or_default().as_bytes()).collect::>(); + let param_status = query_params.iter().filter(|e| e.0 == "status").map(|e| e.1.clone()) + .filter_map(|param_status| param_status.parse().ok()) + .collect::>(); let result = api_impl.find_pets_by_status( param_status.as_ref(), &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1589,21 +1684,23 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/xml") - .expect("Unable to create Content-Type header for FIND_PETS_BY_STATUS_SUCCESSFUL_OPERATION")); - let body_content = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/xml")); + // XML Body + let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, FindPetsByStatusResponse::InvalidStatusValue => { *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1617,7 +1714,7 @@ impl hyper::service::Service<(Request, C)> for Service where Some(ref authorization) => authorization, None => return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) + .body(body_from_str("Unauthenticated")) .expect("Unable to create Authentication Forbidden response")), }; @@ -1632,9 +1729,9 @@ impl hyper::service::Service<(Request, C)> for Service where let missing_scopes = required_scopes.difference(scopes); return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from(missing_scopes.fold( + .body(BoxBody::new(missing_scopes.fold( "Insufficient authorization, missing scopes".to_string(), - |s, scope| format!("{} {}", s, scope)) + |s, scope| format!("{s} {scope}")) )) .expect("Unable to create Authentication Insufficient response") ); @@ -1652,7 +1749,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_tags.as_ref(), &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1666,99 +1763,23 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/xml") - .expect("Unable to create Content-Type header for FIND_PETS_BY_TAGS_SUCCESSFUL_OPERATION")); - let body_content = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/xml")); + // XML Body + let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, FindPetsByTagsResponse::InvalidTagValue => { *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); - }, - } - - Ok(response) - }, - - // GetPetById - GET /pet/{petId} - hyper::Method::GET if path.matched(paths::ID_PET_PETID) => { - { - let authorization = match *(&context as &dyn Has>).get() { - Some(ref authorization) => authorization, - None => return Ok(Response::builder() - .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) - .expect("Unable to create Authentication Forbidden response")), - }; - } - - // Path parameters - let path: &str = uri.path(); - let path_params = - paths::REGEX_PET_PETID - .captures(path) - .unwrap_or_else(|| - panic!("Path {} matched RE PET_PETID in set but failed match against \"{}\"", path, paths::REGEX_PET_PETID.as_str()) - ); - - let param_pet_id = match percent_encoding::percent_decode(path_params["petId"].as_bytes()).decode_utf8() { - Ok(param_pet_id) => match param_pet_id.parse::() { - Ok(param_pet_id) => param_pet_id, - Err(e) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse path parameter petId: {}", e))) - .expect("Unable to create Bad Request response for invalid path parameter")), - }, - Err(_) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["petId"]))) - .expect("Unable to create Bad Request response for invalid percent decode")) - }; - - let result = api_impl.get_pet_by_id( - param_pet_id, - &context - ).await; - let mut response = Response::new(Body::empty()); - response.headers_mut().insert( - HeaderName::from_static("x-span-id"), - HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) - .expect("Unable to create X-Span-ID header value")); - match result { - Ok(rsp) => match rsp { - GetPetByIdResponse::SuccessfulOperation - (body) - => { - *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); - response.headers_mut().insert( - CONTENT_TYPE, - HeaderValue::from_str("application/xml") - .expect("Unable to create Content-Type header for GET_PET_BY_ID_SUCCESSFUL_OPERATION")); - let body_content = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); - }, - GetPetByIdResponse::InvalidIDSupplied - => { - *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); - }, - GetPetByIdResponse::PetNotFound - => { - *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode"); }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1772,7 +1793,7 @@ impl hyper::service::Service<(Request, C)> for Service where Some(ref authorization) => authorization, None => return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) + .body(body_from_str("Unauthenticated")) .expect("Unable to create Authentication Forbidden response")), }; @@ -1787,9 +1808,9 @@ impl hyper::service::Service<(Request, C)> for Service where let missing_scopes = required_scopes.difference(scopes); return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from(missing_scopes.fold( + .body(BoxBody::new(missing_scopes.fold( "Insufficient authorization, missing scopes".to_string(), - |s, scope| format!("{} {}", s, scope)) + |s, scope| format!("{s} {scope}")) )) .expect("Unable to create Authentication Insufficient response") ); @@ -1797,25 +1818,26 @@ impl hyper::service::Service<(Request, C)> for Service where } } - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_body: Option = if !body.is_empty() { let deserializer = &mut serde_xml_rs::de::Deserializer::new_from_reader(&*body); match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); + warn!("Ignoring unknown field in body: {path}"); unused_elements.push(path.to_string()); }) { Ok(param_body) => param_body, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter body - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), } + } else { None }; @@ -1823,15 +1845,18 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_body) => param_body, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter body")) + .body(BoxBody::new("Missing required body parameter body".to_string())) .expect("Unable to create Bad Request response for missing body parameter body")), }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); + let result = api_impl.update_pet( param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1840,30 +1865,32 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { UpdatePetResponse::InvalidIDSupplied => { *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, UpdatePetResponse::PetNotFound => { *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode"); + }, UpdatePetResponse::ValidationException => { *response.status_mut() = StatusCode::from_u16(405).expect("Unable to turn 405 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -1871,19 +1898,19 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, - // UpdatePetWithForm - POST /pet/{petId} - hyper::Method::POST if path.matched(paths::ID_PET_PETID) => { + // DeletePet - DELETE /pet/{petId} + hyper::Method::DELETE if path.matched(paths::ID_PET_PETID) => { { let authorization = match *(&context as &dyn Has>).get() { Some(ref authorization) => authorization, None => return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) + .body(body_from_str("Unauthenticated")) .expect("Unable to create Authentication Forbidden response")), }; @@ -1898,9 +1925,9 @@ impl hyper::service::Service<(Request, C)> for Service where let missing_scopes = required_scopes.difference(scopes); return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from(missing_scopes.fold( + .body(BoxBody::new(missing_scopes.fold( "Insufficient authorization, missing scopes".to_string(), - |s, scope| format!("{} {}", s, scope)) + |s, scope| format!("{s} {scope}")) )) .expect("Unable to create Authentication Insufficient response") ); @@ -1922,26 +1949,41 @@ impl hyper::service::Service<(Request, C)> for Service where Ok(param_pet_id) => param_pet_id, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse path parameter petId: {}", e))) + .body(body_from_string(format!("Couldn't parse path parameter petId: {e}"))) .expect("Unable to create Bad Request response for invalid path parameter")), }, Err(_) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["petId"]))) + .body(body_from_string(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["petId"]))) .expect("Unable to create Bad Request response for invalid percent decode")) }; - // Form parameters - let param_name = Some("name_example".to_string()); - let param_status = Some("status_example".to_string()); + // Header parameters + let param_api_key = headers.get(HeaderName::from_static("api_key")); - let result = api_impl.update_pet_with_form( + let param_api_key = match param_api_key { + Some(v) => match header::IntoHeaderValue::::try_from((*v).clone()) { + Ok(result) => + Some(result.0), + Err(err) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Invalid header api_key - {err}"))) + .expect("Unable to create Bad Request response for invalid header api_key")); + + }, + }, + None => { + None + } + }; + + let result = api_impl.delete_pet( param_pet_id, - param_name, - param_status, + param_api_key, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -1949,69 +1991,42 @@ impl hyper::service::Service<(Request, C)> for Service where match result { Ok(rsp) => match rsp { - UpdatePetWithFormResponse::InvalidInput + DeletePetResponse::InvalidPetValue => { - *response.status_mut() = StatusCode::from_u16(405).expect("Unable to turn 405 into a StatusCode"); + *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } Ok(response) }, - // UploadFile - POST /pet/{petId}/uploadImage - hyper::Method::POST if path.matched(paths::ID_PET_PETID_UPLOADIMAGE) => { + // GetPetById - GET /pet/{petId} + hyper::Method::GET if path.matched(paths::ID_PET_PETID) => { { let authorization = match *(&context as &dyn Has>).get() { Some(ref authorization) => authorization, None => return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) + .body(body_from_str("Unauthenticated")) .expect("Unable to create Authentication Forbidden response")), }; - - // Authorization - if let Scopes::Some(ref scopes) = authorization.scopes { - let required_scopes: std::collections::BTreeSet = vec![ - "write:pets".to_string(), // modify pets in your account - "read:pets".to_string(), // read your pets - ].into_iter().collect(); - - if !required_scopes.is_subset(scopes) { - let missing_scopes = required_scopes.difference(scopes); - return Ok(Response::builder() - .status(StatusCode::FORBIDDEN) - .body(Body::from(missing_scopes.fold( - "Insufficient authorization, missing scopes".to_string(), - |s, scope| format!("{} {}", s, scope)) - )) - .expect("Unable to create Authentication Insufficient response") - ); - } - } } - let boundary = match swagger::multipart::form::boundary(&headers) { - Some(boundary) => boundary.to_string(), - None => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from("Couldn't find valid multipart body".to_string())) - .expect("Unable to create Bad Request response for incorrect boundary")), - }; - // Path parameters let path: &str = uri.path(); let path_params = - paths::REGEX_PET_PETID_UPLOADIMAGE + paths::REGEX_PET_PETID .captures(path) .unwrap_or_else(|| - panic!("Path {} matched RE PET_PETID_UPLOADIMAGE in set but failed match against \"{}\"", path, paths::REGEX_PET_PETID_UPLOADIMAGE.as_str()) + panic!("Path {} matched RE PET_PETID in set but failed match against \"{}\"", path, paths::REGEX_PET_PETID.as_str()) ); let param_pet_id = match percent_encoding::percent_decode(path_params["petId"].as_bytes()).decode_utf8() { @@ -2019,49 +2034,291 @@ impl hyper::service::Service<(Request, C)> for Service where Ok(param_pet_id) => param_pet_id, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse path parameter petId: {}", e))) + .body(body_from_string(format!("Couldn't parse path parameter petId: {e}"))) .expect("Unable to create Bad Request response for invalid path parameter")), }, Err(_) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["petId"]))) + .body(body_from_string(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["petId"]))) .expect("Unable to create Bad Request response for invalid percent decode")) }; - // Form Body parameters (note that non-required body parameters will ignore garbage - // values, rather than causing a 400 response). Produce warning header and logs for - // any unused fields. - let result = body.into_raw(); - match result.await { - Ok(body) => { - use std::io::Read; + let result = api_impl.get_pet_by_id( + param_pet_id, + &context + ).await; + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) + .expect("Unable to create X-Span-ID header value")); - // Read Form Parameters from body - let mut entries = match Multipart::with_body(&body.to_vec()[..], boundary).save().temp() { - SaveResult::Full(entries) => { - entries - }, - _ => { - return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from("Unable to process all message parts".to_string())) - .expect("Unable to create Bad Request response due to failure to process all message")) - }, - }; - let field_additional_metadata = entries.fields.remove("additional_metadata"); - let param_additional_metadata = match field_additional_metadata { - Some(field) => { - let mut reader = field[0].data.readable().expect("Unable to read field for additional_metadata"); - Some({ - let mut data = String::new(); - reader.read_to_string(&mut data).expect("Reading saved String should never fail"); + match result { + Ok(rsp) => match rsp { + GetPetByIdResponse::SuccessfulOperation + (body) + => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + response.headers_mut().insert( + CONTENT_TYPE, + HeaderValue::from_static("application/xml")); + // XML Body + let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + + }, + GetPetByIdResponse::InvalidIDSupplied + => { + *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + + }, + GetPetByIdResponse::PetNotFound + => { + *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode"); + + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = body_from_str("An internal error occurred"); + }, + } + + Ok(response) + }, + + // UpdatePetWithForm - POST /pet/{petId} + hyper::Method::POST if path.matched(paths::ID_PET_PETID) => { + { + let authorization = match *(&context as &dyn Has>).get() { + Some(ref authorization) => authorization, + None => return Ok(Response::builder() + .status(StatusCode::FORBIDDEN) + .body(body_from_str("Unauthenticated")) + .expect("Unable to create Authentication Forbidden response")), + }; + + // Authorization + if let Scopes::Some(ref scopes) = authorization.scopes { + let required_scopes: std::collections::BTreeSet = vec![ + "write:pets".to_string(), // modify pets in your account + "read:pets".to_string(), // read your pets + ].into_iter().collect(); + + if !required_scopes.is_subset(scopes) { + let missing_scopes = required_scopes.difference(scopes); + return Ok(Response::builder() + .status(StatusCode::FORBIDDEN) + .body(BoxBody::new(missing_scopes.fold( + "Insufficient authorization, missing scopes".to_string(), + |s, scope| format!("{s} {scope}")) + )) + .expect("Unable to create Authentication Insufficient response") + ); + } + } + } + + // Path parameters + let path: &str = uri.path(); + let path_params = + paths::REGEX_PET_PETID + .captures(path) + .unwrap_or_else(|| + panic!("Path {} matched RE PET_PETID in set but failed match against \"{}\"", path, paths::REGEX_PET_PETID.as_str()) + ); + + let param_pet_id = match percent_encoding::percent_decode(path_params["petId"].as_bytes()).decode_utf8() { + Ok(param_pet_id) => match param_pet_id.parse::() { + Ok(param_pet_id) => param_pet_id, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Couldn't parse path parameter petId: {e}"))) + .expect("Unable to create Bad Request response for invalid path parameter")), + }, + Err(_) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["petId"]))) + .expect("Unable to create Bad Request response for invalid percent decode")) + }; + + // Handle body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); + match result { + Ok(body) => { + // Form parameters + let param_name = + Some("name_example".to_string()); + let param_status = + Some("status_example".to_string()); + + + let result = api_impl.update_pet_with_form( + param_pet_id, + param_name, + param_status, + &context + ).await; + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) + .expect("Unable to create X-Span-ID header value")); + + match result { + Ok(rsp) => match rsp { + UpdatePetWithFormResponse::InvalidInput + => { + *response.status_mut() = StatusCode::from_u16(405).expect("Unable to turn 405 into a StatusCode"); + + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = body_from_str("An internal error occurred"); + }, + } + + Ok(response) + }, + Err(e) => Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), + } + }, + + // UploadFile - POST /pet/{petId}/uploadImage + hyper::Method::POST if path.matched(paths::ID_PET_PETID_UPLOADIMAGE) => { + { + let authorization = match *(&context as &dyn Has>).get() { + Some(ref authorization) => authorization, + None => return Ok(Response::builder() + .status(StatusCode::FORBIDDEN) + .body(body_from_str("Unauthenticated")) + .expect("Unable to create Authentication Forbidden response")), + }; + + // Authorization + if let Scopes::Some(ref scopes) = authorization.scopes { + let required_scopes: std::collections::BTreeSet = vec![ + "write:pets".to_string(), // modify pets in your account + "read:pets".to_string(), // read your pets + ].into_iter().collect(); + + if !required_scopes.is_subset(scopes) { + let missing_scopes = required_scopes.difference(scopes); + return Ok(Response::builder() + .status(StatusCode::FORBIDDEN) + .body(BoxBody::new(missing_scopes.fold( + "Insufficient authorization, missing scopes".to_string(), + |s, scope| format!("{s} {scope}")) + )) + .expect("Unable to create Authentication Insufficient response") + ); + } + } + } + + // Path parameters + let path: &str = uri.path(); + let path_params = + paths::REGEX_PET_PETID_UPLOADIMAGE + .captures(path) + .unwrap_or_else(|| + panic!("Path {} matched RE PET_PETID_UPLOADIMAGE in set but failed match against \"{}\"", path, paths::REGEX_PET_PETID_UPLOADIMAGE.as_str()) + ); + + let param_pet_id = match percent_encoding::percent_decode(path_params["petId"].as_bytes()).decode_utf8() { + Ok(param_pet_id) => match param_pet_id.parse::() { + Ok(param_pet_id) => param_pet_id, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Couldn't parse path parameter petId: {e}"))) + .expect("Unable to create Bad Request response for invalid path parameter")), + }, + Err(_) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["petId"]))) + .expect("Unable to create Bad Request response for invalid percent decode")) + }; + + // Handle body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); + match result { + Ok(body) => { + let boundary = match swagger::multipart::form::boundary(&headers) { + Some(boundary) => boundary.to_string(), + None => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Couldn't find valid multipart body".to_string())) + .expect("Unable to create Bad Request response for incorrect boundary")), + }; + + use std::io::Read; + + // Read Form Parameters from body + let mut entries = match Multipart::with_body(&body.to_vec()[..], boundary) + .save() + .size_limit(multipart_form_size_limit) + .temp() + { + SaveResult::Full(entries) => { + entries + }, + SaveResult::Partial(_, PartialReason::CountLimit) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Unable to process message part due to excessive parts".to_string())) + .expect("Unable to create Bad Request response due to excessive parts")) + }, + SaveResult::Partial(_, PartialReason::SizeLimit) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Unable to process message part due to excessive data".to_string())) + .expect("Unable to create Bad Request response due to excessive data")) + }, + SaveResult::Partial(_, PartialReason::Utf8Error(_)) => { + return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Unable to process message part due to invalid data".to_string())) + .expect("Unable to create Bad Request response due to invalid data")) + }, + SaveResult::Partial(_, PartialReason::IoError(_)) => { + return Ok(Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(BoxBody::new("Failed to process message part due an internal error".to_string())) + .expect("Unable to create Internal Server Error response due to an internal error")) + }, + SaveResult::Error(e) => { + return Ok(Response::builder() + .status(StatusCode::INTERNAL_SERVER_ERROR) + .body(BoxBody::new("Failed to process all message parts due to an internal error".to_string())) + .expect("Unable to create Internal Server Error response due to an internal error")) + }, + }; + let field_additional_metadata = entries.fields.remove("additional_metadata"); + let param_additional_metadata = match field_additional_metadata { + Some(field) => { + let mut reader = field[0].data.readable().expect("Unable to read field for additional_metadata"); + Some({ + let mut data = String::new(); + reader.read_to_string(&mut data).expect("Reading saved String should never fail"); let additional_metadata_model: String = match serde_json::from_str(&data) { Ok(model) => model, Err(e) => { return Ok( Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("additional_metadata data does not match API definition : {}", e))) + .body(BoxBody::new(format!("additional_metadata data does not match API definition : {e}"))) .expect("Unable to create Bad Request due to missing required form parameter additional_metadata")) } }; @@ -2085,7 +2342,7 @@ impl hyper::service::Service<(Request, C)> for Service where return Ok( Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("file data does not match API definition : {}", e))) + .body(BoxBody::new(format!("file data does not match API definition : {e}"))) .expect("Unable to create Bad Request due to missing required form parameter file")) } }; @@ -2096,37 +2353,176 @@ impl hyper::service::Service<(Request, C)> for Service where None } }; - let result = api_impl.upload_file( - param_pet_id, - param_additional_metadata, - param_file, + + + let result = api_impl.upload_file( + param_pet_id, + param_additional_metadata, + param_file, + &context + ).await; + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) + .expect("Unable to create X-Span-ID header value")); + + match result { + Ok(rsp) => match rsp { + UploadFileResponse::SuccessfulOperation + (body) + => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + response.headers_mut().insert( + CONTENT_TYPE, + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = body_from_str("An internal error occurred"); + }, + } + + Ok(response) + }, + Err(e) => Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), + } + }, + + // GetInventory - GET /store/inventory + hyper::Method::GET if path.matched(paths::ID_STORE_INVENTORY) => { + { + let authorization = match *(&context as &dyn Has>).get() { + Some(ref authorization) => authorization, + None => return Ok(Response::builder() + .status(StatusCode::FORBIDDEN) + .body(body_from_str("Unauthenticated")) + .expect("Unable to create Authentication Forbidden response")), + }; + } + + let result = api_impl.get_inventory( + &context + ).await; + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) + .expect("Unable to create X-Span-ID header value")); + + match result { + Ok(rsp) => match rsp { + GetInventoryResponse::SuccessfulOperation + (body) + => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + response.headers_mut().insert( + CONTENT_TYPE, + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = body_from_str("An internal error occurred"); + }, + } + + Ok(response) + }, + + // PlaceOrder - POST /store/order + hyper::Method::POST if path.matched(paths::ID_STORE_ORDER) => { + // Handle body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); + match result { + Ok(body) => { + let mut unused_elements : Vec = vec![]; + let param_body: Option = if !body.is_empty() { + let deserializer = &mut serde_json::Deserializer::from_slice(&body); + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {path}"); + unused_elements.push(path.to_string()); + }) { + Ok(param_body) => param_body, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new(format!("Couldn't parse body parameter body - doesn't match schema: {e}"))) + .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), + } + + } else { + None + }; + let param_body = match param_body { + Some(param_body) => param_body, + None => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Missing required body parameter body".to_string())) + .expect("Unable to create Bad Request response for missing body parameter body")), + }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); + + + let result = api_impl.place_order( + param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) .expect("Unable to create X-Span-ID header value")); + if !unused_elements.is_empty() { + response.headers_mut().insert( + HeaderName::from_static("warning"), + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) + .expect("Unable to create Warning header value")); + } match result { Ok(rsp) => match rsp { - UploadFileResponse::SuccessfulOperation + PlaceOrderResponse::SuccessfulOperation (body) => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for UPLOAD_FILE_SUCCESSFUL_OPERATION")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/xml")); + // XML Body + let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + + }, + PlaceOrderResponse::InvalidOrder + => { + *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -2134,8 +2530,8 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Couldn't read multipart body".to_string())) - .expect("Unable to create Bad Request response due to unable read multipart body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, @@ -2155,12 +2551,12 @@ impl hyper::service::Service<(Request, C)> for Service where Ok(param_order_id) => param_order_id, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse path parameter order_id: {}", e))) + .body(body_from_string(format!("Couldn't parse path parameter order_id: {e}"))) .expect("Unable to create Bad Request response for invalid path parameter")), }, Err(_) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["order_id"]))) + .body(body_from_string(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["order_id"]))) .expect("Unable to create Bad Request response for invalid percent decode")) }; @@ -2168,7 +2564,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_order_id, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -2179,63 +2575,19 @@ impl hyper::service::Service<(Request, C)> for Service where DeleteOrderResponse::InvalidIDSupplied => { *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, DeleteOrderResponse::OrderNotFound => { *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode"); - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); - }, - } - - Ok(response) - }, - - // GetInventory - GET /store/inventory - hyper::Method::GET if path.matched(paths::ID_STORE_INVENTORY) => { - { - let authorization = match *(&context as &dyn Has>).get() { - Some(ref authorization) => authorization, - None => return Ok(Response::builder() - .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) - .expect("Unable to create Authentication Forbidden response")), - }; - } - - let result = api_impl.get_inventory( - &context - ).await; - let mut response = Response::new(Body::empty()); - response.headers_mut().insert( - HeaderName::from_static("x-span-id"), - HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) - .expect("Unable to create X-Span-ID header value")); - match result { - Ok(rsp) => match rsp { - GetInventoryResponse::SuccessfulOperation - (body) - => { - *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); - response.headers_mut().insert( - CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for GET_INVENTORY_SUCCESSFUL_OPERATION")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -2254,16 +2606,16 @@ impl hyper::service::Service<(Request, C)> for Service where ); let param_order_id = match percent_encoding::percent_decode(path_params["order_id"].as_bytes()).decode_utf8() { - Ok(param_order_id) => match param_order_id.parse::() { + Ok(param_order_id) => match param_order_id.parse::() { Ok(param_order_id) => param_order_id, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse path parameter order_id: {}", e))) + .body(body_from_string(format!("Couldn't parse path parameter order_id: {e}"))) .expect("Unable to create Bad Request response for invalid path parameter")), }, Err(_) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["order_id"]))) + .body(body_from_string(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["order_id"]))) .expect("Unable to create Bad Request response for invalid percent decode")) }; @@ -2271,7 +2623,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_order_id, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -2285,136 +2637,56 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/xml") - .expect("Unable to create Content-Type header for GET_ORDER_BY_ID_SUCCESSFUL_OPERATION")); - let body_content = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/xml")); + // XML Body + let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, GetOrderByIdResponse::InvalidIDSupplied => { *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, GetOrderByIdResponse::OrderNotFound => { *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode"); - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); - }, - } - - Ok(response) - }, - - // PlaceOrder - POST /store/order - hyper::Method::POST if path.matched(paths::ID_STORE_ORDER) => { - // Body parameters (note that non-required body parameters will ignore garbage - // values, rather than causing a 400 response). Produce warning header and logs for - // any unused fields. - let result = body.into_raw().await; - match result { - Ok(body) => { - let mut unused_elements = Vec::new(); - let param_body: Option = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&body); - match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) { - Ok(param_body) => param_body, - Err(e) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) - .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), - } - } else { - None - }; - let param_body = match param_body { - Some(param_body) => param_body, - None => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter body")) - .expect("Unable to create Bad Request response for missing body parameter body")), - }; - - let result = api_impl.place_order( - param_body, - &context - ).await; - let mut response = Response::new(Body::empty()); - response.headers_mut().insert( - HeaderName::from_static("x-span-id"), - HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) - .expect("Unable to create X-Span-ID header value")); - - if !unused_elements.is_empty() { - response.headers_mut().insert( - HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) - .expect("Unable to create Warning header value")); - } - match result { - Ok(rsp) => match rsp { - PlaceOrderResponse::SuccessfulOperation - (body) - => { - *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); - response.headers_mut().insert( - CONTENT_TYPE, - HeaderValue::from_str("application/xml") - .expect("Unable to create Content-Type header for PLACE_ORDER_SUCCESSFUL_OPERATION")); - let body_content = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); - }, - PlaceOrderResponse::InvalidOrder - => { - *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } Ok(response) - }, - Err(e) => Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), - } }, // CreateUser - POST /user hyper::Method::POST if path.matched(paths::ID_USER) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_body: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); + warn!("Ignoring unknown field in body: {path}"); unused_elements.push(path.to_string()); }) { Ok(param_body) => param_body, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter body - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), } + } else { None }; @@ -2422,15 +2694,18 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_body) => param_body, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter body")) + .body(BoxBody::new("Missing required body parameter body".to_string())) .expect("Unable to create Bad Request response for missing body parameter body")), }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); + let result = api_impl.create_user( param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -2439,22 +2714,22 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { CreateUserResponse::SuccessfulOperation => { *response.status_mut() = StatusCode::from_u16(0).expect("Unable to turn 0 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -2462,105 +2737,33 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, // CreateUsersWithArrayInput - POST /user/createWithArray hyper::Method::POST if path.matched(paths::ID_USER_CREATEWITHARRAY) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_body: Option> = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); + warn!("Ignoring unknown field in body: {path}"); unused_elements.push(path.to_string()); }) { Ok(param_body) => param_body, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter body - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), } - } else { - None - }; - let param_body = match param_body { - Some(param_body) => param_body, - None => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter body")) - .expect("Unable to create Bad Request response for missing body parameter body")), - }; - - let result = api_impl.create_users_with_array_input( - param_body.as_ref(), - &context - ).await; - let mut response = Response::new(Body::empty()); - response.headers_mut().insert( - HeaderName::from_static("x-span-id"), - HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) - .expect("Unable to create X-Span-ID header value")); - - if !unused_elements.is_empty() { - response.headers_mut().insert( - HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) - .expect("Unable to create Warning header value")); - } - match result { - Ok(rsp) => match rsp { - CreateUsersWithArrayInputResponse::SuccessfulOperation - => { - *response.status_mut() = StatusCode::from_u16(0).expect("Unable to turn 0 into a StatusCode"); - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); - }, - } - - Ok(response) - }, - Err(e) => Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), - } - }, - - // CreateUsersWithListInput - POST /user/createWithList - hyper::Method::POST if path.matched(paths::ID_USER_CREATEWITHLIST) => { - // Body parameters (note that non-required body parameters will ignore garbage - // values, rather than causing a 400 response). Produce warning header and logs for - // any unused fields. - let result = body.into_raw().await; - match result { - Ok(body) => { - let mut unused_elements = Vec::new(); - let param_body: Option> = if !body.is_empty() { - let deserializer = &mut serde_json::Deserializer::from_slice(&body); - match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); - unused_elements.push(path.to_string()); - }) { - Ok(param_body) => param_body, - Err(e) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) - .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), - } } else { None }; @@ -2568,174 +2771,129 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_body) => param_body, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter body")) + .body(BoxBody::new("Missing required body parameter body".to_string())) .expect("Unable to create Bad Request response for missing body parameter body")), }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); - let result = api_impl.create_users_with_list_input( - param_body.as_ref(), - &context - ).await; - let mut response = Response::new(Body::empty()); - response.headers_mut().insert( - HeaderName::from_static("x-span-id"), - HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) - .expect("Unable to create X-Span-ID header value")); - - if !unused_elements.is_empty() { - response.headers_mut().insert( - HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) - .expect("Unable to create Warning header value")); - } - - match result { - Ok(rsp) => match rsp { - CreateUsersWithListInputResponse::SuccessfulOperation - => { - *response.status_mut() = StatusCode::from_u16(0).expect("Unable to turn 0 into a StatusCode"); - }, - }, - Err(_) => { - // Application code returned an error. This should not happen, as the implementation should - // return a valid response. - *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); - }, - } - - Ok(response) - }, - Err(e) => Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), - } - }, - - // DeleteUser - DELETE /user/{username} - hyper::Method::DELETE if path.matched(paths::ID_USER_USERNAME) => { - // Path parameters - let path: &str = uri.path(); - let path_params = - paths::REGEX_USER_USERNAME - .captures(path) - .unwrap_or_else(|| - panic!("Path {} matched RE USER_USERNAME in set but failed match against \"{}\"", path, paths::REGEX_USER_USERNAME.as_str()) - ); - - let param_username = match percent_encoding::percent_decode(path_params["username"].as_bytes()).decode_utf8() { - Ok(param_username) => match param_username.parse::() { - Ok(param_username) => param_username, - Err(e) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse path parameter username: {}", e))) - .expect("Unable to create Bad Request response for invalid path parameter")), - }, - Err(_) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["username"]))) - .expect("Unable to create Bad Request response for invalid percent decode")) - }; - let result = api_impl.delete_user( - param_username, + let result = api_impl.create_users_with_array_input( + param_body.as_ref(), &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) .expect("Unable to create X-Span-ID header value")); + if !unused_elements.is_empty() { + response.headers_mut().insert( + HeaderName::from_static("warning"), + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) + .expect("Unable to create Warning header value")); + } match result { Ok(rsp) => match rsp { - DeleteUserResponse::InvalidUsernameSupplied - => { - *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); - }, - DeleteUserResponse::UserNotFound + CreateUsersWithArrayInputResponse::SuccessfulOperation => { - *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode"); + *response.status_mut() = StatusCode::from_u16(0).expect("Unable to turn 0 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } Ok(response) + }, + Err(e) => Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), + } }, - // GetUserByName - GET /user/{username} - hyper::Method::GET if path.matched(paths::ID_USER_USERNAME) => { - // Path parameters - let path: &str = uri.path(); - let path_params = - paths::REGEX_USER_USERNAME - .captures(path) - .unwrap_or_else(|| - panic!("Path {} matched RE USER_USERNAME in set but failed match against \"{}\"", path, paths::REGEX_USER_USERNAME.as_str()) - ); + // CreateUsersWithListInput - POST /user/createWithList + hyper::Method::POST if path.matched(paths::ID_USER_CREATEWITHLIST) => { + // Handle body parameters (note that non-required body parameters will ignore garbage + // values, rather than causing a 400 response). Produce warning header and logs for + // any unused fields. + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); + match result { + Ok(body) => { + let mut unused_elements : Vec = vec![]; + let param_body: Option> = if !body.is_empty() { + let deserializer = &mut serde_json::Deserializer::from_slice(&body); + match serde_ignored::deserialize(deserializer, |path| { + warn!("Ignoring unknown field in body: {path}"); + unused_elements.push(path.to_string()); + }) { + Ok(param_body) => param_body, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new(format!("Couldn't parse body parameter body - doesn't match schema: {e}"))) + .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), + } - let param_username = match percent_encoding::percent_decode(path_params["username"].as_bytes()).decode_utf8() { - Ok(param_username) => match param_username.parse::() { - Ok(param_username) => param_username, - Err(e) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse path parameter username: {}", e))) - .expect("Unable to create Bad Request response for invalid path parameter")), - }, - Err(_) => return Ok(Response::builder() - .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["username"]))) - .expect("Unable to create Bad Request response for invalid percent decode")) - }; + } else { + None + }; + let param_body = match param_body { + Some(param_body) => param_body, + None => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(BoxBody::new("Missing required body parameter body".to_string())) + .expect("Unable to create Bad Request response for missing body parameter body")), + }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); - let result = api_impl.get_user_by_name( - param_username, + + let result = api_impl.create_users_with_list_input( + param_body.as_ref(), &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) .expect("Unable to create X-Span-ID header value")); + if !unused_elements.is_empty() { + response.headers_mut().insert( + HeaderName::from_static("warning"), + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) + .expect("Unable to create Warning header value")); + } match result { Ok(rsp) => match rsp { - GetUserByNameResponse::SuccessfulOperation - (body) - => { - *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); - response.headers_mut().insert( - CONTENT_TYPE, - HeaderValue::from_str("application/xml") - .expect("Unable to create Content-Type header for GET_USER_BY_NAME_SUCCESSFUL_OPERATION")); - let body_content = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); - }, - GetUserByNameResponse::InvalidUsernameSupplied - => { - *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); - }, - GetUserByNameResponse::UserNotFound + CreateUsersWithListInputResponse::SuccessfulOperation => { - *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode"); + *response.status_mut() = StatusCode::from_u16(0).expect("Unable to turn 0 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } Ok(response) + }, + Err(e) => Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), + } }, // LoginUser - GET /user/login @@ -2753,7 +2911,7 @@ impl hyper::service::Service<(Request, C)> for Service where Ok(param_username) => Some(param_username), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse query parameter username - doesn't match schema: {}", e))) + .body(body_from_string(format!("Couldn't parse query parameter username - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid query parameter username")), } }, @@ -2763,7 +2921,7 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_username) => param_username, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required query parameter username")) + .body(body_from_str("Missing required query parameter username")) .expect("Unable to create Bad Request response for missing query parameter username")), }; let param_password = query_params.iter().filter(|e| e.0 == "password").map(|e| e.1.clone()) @@ -2777,7 +2935,7 @@ impl hyper::service::Service<(Request, C)> for Service where Ok(param_password) => Some(param_password), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse query parameter password - doesn't match schema: {}", e))) + .body(body_from_string(format!("Couldn't parse query parameter password - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid query parameter password")), } }, @@ -2787,7 +2945,7 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_password) => param_password, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required query parameter password")) + .body(body_from_str("Missing required query parameter password")) .expect("Unable to create Bad Request response for missing query parameter password")), }; @@ -2796,7 +2954,7 @@ impl hyper::service::Service<(Request, C)> for Service where param_password, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -2811,13 +2969,15 @@ impl hyper::service::Service<(Request, C)> for Service where x_expires_after } => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + if let Some(x_rate_limit) = x_rate_limit { let x_rate_limit = match header::IntoHeaderValue(x_rate_limit).try_into() { Ok(val) => val, Err(e) => { return Ok(Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Body::from(format!("An internal server error occurred handling x_rate_limit header - {}", e))) + .body(body_from_string(format!("An internal server error occurred handling x_rate_limit header - {e}"))) .expect("Unable to create Internal Server Error for invalid response header")) } }; @@ -2827,13 +2987,14 @@ impl hyper::service::Service<(Request, C)> for Service where x_rate_limit ); } + if let Some(x_expires_after) = x_expires_after { let x_expires_after = match header::IntoHeaderValue(x_expires_after).try_into() { Ok(val) => val, Err(e) => { return Ok(Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(Body::from(format!("An internal server error occurred handling x_expires_after header - {}", e))) + .body(body_from_string(format!("An internal server error occurred handling x_expires_after header - {e}"))) .expect("Unable to create Internal Server Error for invalid response header")) } }; @@ -2843,24 +3004,25 @@ impl hyper::service::Service<(Request, C)> for Service where x_expires_after ); } - *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/xml") - .expect("Unable to create Content-Type header for LOGIN_USER_SUCCESSFUL_OPERATION")); - let body_content = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/xml")); + // XML Body + let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, LoginUserResponse::InvalidUsername => { *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -2872,7 +3034,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.logout_user( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -2883,13 +3045,144 @@ impl hyper::service::Service<(Request, C)> for Service where LogoutUserResponse::SuccessfulOperation => { *response.status_mut() = StatusCode::from_u16(0).expect("Unable to turn 0 into a StatusCode"); + + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = body_from_str("An internal error occurred"); + }, + } + + Ok(response) + }, + + // DeleteUser - DELETE /user/{username} + hyper::Method::DELETE if path.matched(paths::ID_USER_USERNAME) => { + // Path parameters + let path: &str = uri.path(); + let path_params = + paths::REGEX_USER_USERNAME + .captures(path) + .unwrap_or_else(|| + panic!("Path {} matched RE USER_USERNAME in set but failed match against \"{}\"", path, paths::REGEX_USER_USERNAME.as_str()) + ); + + let param_username = match percent_encoding::percent_decode(path_params["username"].as_bytes()).decode_utf8() { + Ok(param_username) => match param_username.parse::() { + Ok(param_username) => param_username, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Couldn't parse path parameter username: {e}"))) + .expect("Unable to create Bad Request response for invalid path parameter")), + }, + Err(_) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["username"]))) + .expect("Unable to create Bad Request response for invalid percent decode")) + }; + + let result = api_impl.delete_user( + param_username, + &context + ).await; + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) + .expect("Unable to create X-Span-ID header value")); + + match result { + Ok(rsp) => match rsp { + DeleteUserResponse::InvalidUsernameSupplied + => { + *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + + }, + DeleteUserResponse::UserNotFound + => { + *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode"); + + }, + }, + Err(_) => { + // Application code returned an error. This should not happen, as the implementation should + // return a valid response. + *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + *response.body_mut() = body_from_str("An internal error occurred"); + }, + } + + Ok(response) + }, + + // GetUserByName - GET /user/{username} + hyper::Method::GET if path.matched(paths::ID_USER_USERNAME) => { + // Path parameters + let path: &str = uri.path(); + let path_params = + paths::REGEX_USER_USERNAME + .captures(path) + .unwrap_or_else(|| + panic!("Path {} matched RE USER_USERNAME in set but failed match against \"{}\"", path, paths::REGEX_USER_USERNAME.as_str()) + ); + + let param_username = match percent_encoding::percent_decode(path_params["username"].as_bytes()).decode_utf8() { + Ok(param_username) => match param_username.parse::() { + Ok(param_username) => param_username, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Couldn't parse path parameter username: {e}"))) + .expect("Unable to create Bad Request response for invalid path parameter")), + }, + Err(_) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .body(body_from_string(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["username"]))) + .expect("Unable to create Bad Request response for invalid percent decode")) + }; + + let result = api_impl.get_user_by_name( + param_username, + &context + ).await; + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); + response.headers_mut().insert( + HeaderName::from_static("x-span-id"), + HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) + .expect("Unable to create X-Span-ID header value")); + + match result { + Ok(rsp) => match rsp { + GetUserByNameResponse::SuccessfulOperation + (body) + => { + *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + response.headers_mut().insert( + CONTENT_TYPE, + HeaderValue::from_static("application/xml")); + // XML Body + let body = serde_xml_rs::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + + }, + GetUserByNameResponse::InvalidUsernameSupplied + => { + *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + + }, + GetUserByNameResponse::UserNotFound + => { + *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -2912,34 +3205,35 @@ impl hyper::service::Service<(Request, C)> for Service where Ok(param_username) => param_username, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse path parameter username: {}", e))) + .body(body_from_string(format!("Couldn't parse path parameter username: {e}"))) .expect("Unable to create Bad Request response for invalid path parameter")), }, Err(_) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["username"]))) + .body(body_from_string(format!("Couldn't percent-decode path parameter as UTF-8: {}", &path_params["username"]))) .expect("Unable to create Bad Request response for invalid percent decode")) }; - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_body: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); + warn!("Ignoring unknown field in body: {path}"); unused_elements.push(path.to_string()); }) { Ok(param_body) => param_body, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter body - doesn't match schema: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter body - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter body due to schema")), } + } else { None }; @@ -2947,16 +3241,19 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_body) => param_body, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter body")) + .body(BoxBody::new("Missing required body parameter body".to_string())) .expect("Unable to create Bad Request response for missing body parameter body")), }; + #[cfg(not(feature = "validate"))] + run_validation!(param_body, "body", validation); + let result = api_impl.update_user( param_username, param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -2965,26 +3262,27 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { UpdateUserResponse::InvalidUserSupplied => { *response.status_mut() = StatusCode::from_u16(400).expect("Unable to turn 400 into a StatusCode"); + }, UpdateUserResponse::UserNotFound => { *response.status_mut() = StatusCode::from_u16(404).expect("Unable to turn 404 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -2992,8 +3290,8 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, @@ -3024,11 +3322,18 @@ impl hyper::service::Service<(Request, C)> for Service where _ if path.matched(paths::ID_USER_LOGIN) => method_not_allowed(), _ if path.matched(paths::ID_USER_LOGOUT) => method_not_allowed(), _ if path.matched(paths::ID_USER_USERNAME) => method_not_allowed(), - _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) - .body(Body::empty()) - .expect("Unable to create Not Found response")) + _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) + .body(BoxBody::new(http_body_util::Empty::new())) + .expect("Unable to create Not Found response")) + } } - } Box::pin(run(self.api_impl.clone(), req)) } + Box::pin(run( + self.api_impl.clone(), + req, + self.validation, + self.multipart_form_size_limit + )) + } } /// Request parser for `Api`. @@ -3051,8 +3356,6 @@ impl RequestParser for ApiRequestParser { hyper::Method::POST if path.matched(paths::ID_FAKE_OUTER_STRING) => Some("FakeOuterStringSerialize"), // FakeResponseWithNumericalDescription - GET /fake/response-with-numerical-description hyper::Method::GET if path.matched(paths::ID_FAKE_RESPONSE_WITH_NUMERICAL_DESCRIPTION) => Some("FakeResponseWithNumericalDescription"), - // HyphenParam - GET /fake/hyphenParam/{hyphen-param} - hyper::Method::GET if path.matched(paths::ID_FAKE_HYPHENPARAM_HYPHEN_PARAM) => Some("HyphenParam"), // TestBodyWithQueryParams - PUT /fake/body-with-query-params hyper::Method::PUT if path.matched(paths::ID_FAKE_BODY_WITH_QUERY_PARAMS) => Some("TestBodyWithQueryParams"), // TestClientModel - PATCH /fake @@ -3065,46 +3368,48 @@ impl RequestParser for ApiRequestParser { hyper::Method::POST if path.matched(paths::ID_FAKE_INLINE_ADDITIONALPROPERTIES) => Some("TestInlineAdditionalProperties"), // TestJsonFormData - GET /fake/jsonFormData hyper::Method::GET if path.matched(paths::ID_FAKE_JSONFORMDATA) => Some("TestJsonFormData"), + // HyphenParam - GET /fake/hyphenParam/{hyphen-param} + hyper::Method::GET if path.matched(paths::ID_FAKE_HYPHENPARAM_HYPHEN_PARAM) => Some("HyphenParam"), // TestClassname - PATCH /fake_classname_test hyper::Method::PATCH if path.matched(paths::ID_FAKE_CLASSNAME_TEST) => Some("TestClassname"), // AddPet - POST /pet hyper::Method::POST if path.matched(paths::ID_PET) => Some("AddPet"), - // DeletePet - DELETE /pet/{petId} - hyper::Method::DELETE if path.matched(paths::ID_PET_PETID) => Some("DeletePet"), // FindPetsByStatus - GET /pet/findByStatus hyper::Method::GET if path.matched(paths::ID_PET_FINDBYSTATUS) => Some("FindPetsByStatus"), // FindPetsByTags - GET /pet/findByTags hyper::Method::GET if path.matched(paths::ID_PET_FINDBYTAGS) => Some("FindPetsByTags"), - // GetPetById - GET /pet/{petId} - hyper::Method::GET if path.matched(paths::ID_PET_PETID) => Some("GetPetById"), // UpdatePet - PUT /pet hyper::Method::PUT if path.matched(paths::ID_PET) => Some("UpdatePet"), + // DeletePet - DELETE /pet/{petId} + hyper::Method::DELETE if path.matched(paths::ID_PET_PETID) => Some("DeletePet"), + // GetPetById - GET /pet/{petId} + hyper::Method::GET if path.matched(paths::ID_PET_PETID) => Some("GetPetById"), // UpdatePetWithForm - POST /pet/{petId} hyper::Method::POST if path.matched(paths::ID_PET_PETID) => Some("UpdatePetWithForm"), // UploadFile - POST /pet/{petId}/uploadImage hyper::Method::POST if path.matched(paths::ID_PET_PETID_UPLOADIMAGE) => Some("UploadFile"), - // DeleteOrder - DELETE /store/order/{order_id} - hyper::Method::DELETE if path.matched(paths::ID_STORE_ORDER_ORDER_ID) => Some("DeleteOrder"), // GetInventory - GET /store/inventory hyper::Method::GET if path.matched(paths::ID_STORE_INVENTORY) => Some("GetInventory"), - // GetOrderById - GET /store/order/{order_id} - hyper::Method::GET if path.matched(paths::ID_STORE_ORDER_ORDER_ID) => Some("GetOrderById"), // PlaceOrder - POST /store/order hyper::Method::POST if path.matched(paths::ID_STORE_ORDER) => Some("PlaceOrder"), + // DeleteOrder - DELETE /store/order/{order_id} + hyper::Method::DELETE if path.matched(paths::ID_STORE_ORDER_ORDER_ID) => Some("DeleteOrder"), + // GetOrderById - GET /store/order/{order_id} + hyper::Method::GET if path.matched(paths::ID_STORE_ORDER_ORDER_ID) => Some("GetOrderById"), // CreateUser - POST /user hyper::Method::POST if path.matched(paths::ID_USER) => Some("CreateUser"), // CreateUsersWithArrayInput - POST /user/createWithArray hyper::Method::POST if path.matched(paths::ID_USER_CREATEWITHARRAY) => Some("CreateUsersWithArrayInput"), // CreateUsersWithListInput - POST /user/createWithList hyper::Method::POST if path.matched(paths::ID_USER_CREATEWITHLIST) => Some("CreateUsersWithListInput"), - // DeleteUser - DELETE /user/{username} - hyper::Method::DELETE if path.matched(paths::ID_USER_USERNAME) => Some("DeleteUser"), - // GetUserByName - GET /user/{username} - hyper::Method::GET if path.matched(paths::ID_USER_USERNAME) => Some("GetUserByName"), // LoginUser - GET /user/login hyper::Method::GET if path.matched(paths::ID_USER_LOGIN) => Some("LoginUser"), // LogoutUser - GET /user/logout hyper::Method::GET if path.matched(paths::ID_USER_LOGOUT) => Some("LogoutUser"), + // DeleteUser - DELETE /user/{username} + hyper::Method::DELETE if path.matched(paths::ID_USER_USERNAME) => Some("DeleteUser"), + // GetUserByName - GET /user/{username} + hyper::Method::GET if path.matched(paths::ID_USER_USERNAME) => Some("GetUserByName"), // UpdateUser - PUT /user/{username} hyper::Method::PUT if path.matched(paths::ID_USER_USERNAME) => Some("UpdateUser"), _ => None, diff --git a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/server/server_auth.rs b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/server/server_auth.rs index ba78eb2f3f5d..21b1d7babd03 100644 --- a/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/server/server_auth.rs +++ b/samples/server/petstore/rust-server/output/petstore-with-fake-endpoints-models-for-testing/src/server/server_auth.rs @@ -1,11 +1,12 @@ use super::Service; use crate::{Api, AuthenticationApi}; +use headers::authorization::{Basic, Bearer}; use swagger::{ ApiError, - Authorization, - auth::{Basic, Bearer}, - Has, - XSpanIdString}; + Authorization, + Has, + XSpanIdString +}; impl AuthenticationApi for Service where T: Api + Clone + Send + 'static + AuthenticationApi, diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/.cargo/config.toml b/samples/server/petstore/rust-server/output/ping-bearer-auth/.cargo/config.toml new file mode 100644 index 000000000000..df91f0f117f3 --- /dev/null +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/.cargo/config.toml @@ -0,0 +1,19 @@ +[build] +rustflags = [ + "-W", "missing_docs", # detects missing documentation for public members + + "-W", "trivial_casts", # detects trivial casts which could be removed + + "-W", "trivial_numeric_casts", # detects trivial casts of numeric types which could be removed + + # unsafe is used in `TokioIo` bridging code copied from `hyper`. + # "-W", "unsafe_code", # usage of `unsafe` code + + "-W", "unused_qualifications", # detects unnecessarily qualified names + + "-W", "unused_extern_crates", # extern crates that are never used + + "-W", "unused_import_braces", # unnecessary braces around an imported item + + "-D", "warnings", # all warnings should be denied +] diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/.openapi-generator/FILES b/samples/server/petstore/rust-server/output/ping-bearer-auth/.openapi-generator/FILES index f67b7ce47ca8..913ced3d98a4 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/.openapi-generator/FILES +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/.openapi-generator/FILES @@ -1,8 +1,9 @@ -.cargo/config +.cargo/config.toml .gitignore Cargo.toml README.md api/openapi.yaml +bin/cli.rs docs/default_api.md examples/ca.pem examples/client/client_auth.rs diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/.openapi-generator/VERSION b/samples/server/petstore/rust-server/output/ping-bearer-auth/.openapi-generator/VERSION index f1358e30d8ae..f7962df3e243 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/.openapi-generator/VERSION +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/.openapi-generator/VERSION @@ -1 +1 @@ -8.0.0-SNAPSHOT +7.22.0-SNAPSHOT diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/Cargo.toml b/samples/server/petstore/rust-server/output/ping-bearer-auth/Cargo.toml index 3a6860128b44..92666ec67329 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/Cargo.toml +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/Cargo.toml @@ -8,74 +8,122 @@ license = "Unlicense" edition = "2018" [features] -default = ["client", "server"] +default = ["client", "server", "client-tls"] client = [ - "hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url" + "hyper", "percent-encoding", "hyper-util/http1", "hyper-util/http2", "url" +] +# TLS support - automatically selects backend based on target OS: +# - macOS/Windows/iOS: native-tls via hyper-tls +# - Other platforms: OpenSSL via hyper-openssl +# Dependencies are in target-specific sections below +client-tls = [ + "client", + "dep:native-tls", + "dep:hyper-tls", + "dep:openssl", + "dep:hyper-openssl", + "swagger/tls" ] server = [ - "serde_ignored", "hyper", "regex", "percent-encoding", "url", "lazy_static" + "serde_ignored", "hyper", "percent-encoding", "url", + "lazy_static", "regex" +] +cli = [ + "anyhow", "clap", "clap-verbosity-flag", "simple_logger", "tokio" ] conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"] -[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] -native-tls = { version = "0.2", optional = true } -hyper-tls = { version = "0.5", optional = true } - -[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] -hyper-openssl = { version = "0.9", optional = true } -openssl = {version = "0.10", optional = true } +mock = ["mockall"] +validate = ["regex", "serde_valid", "swagger/serdevalid"] [dependencies] # Common -async-trait = "0.1.24" +async-trait = "0.1.89" chrono = { version = "0.4", features = ["serde"] } futures = "0.3" -swagger = { version = "6.1", features = ["serdejson", "server", "client", "tls", "tcp"] } -log = "0.4.0" +swagger = { version = "7.0.0", features = ["serdejson", "server", "client"] } +headers = "0.4.1" +log = "0.4.29" + mime = "0.3" +mockall = { version = "0.14", optional = true } + serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -validator = { version = "0.16", features = ["derive"] } +serde_valid = { version = "2.0", optional = true } + +validator = { version = "0.20", features = ["derive"] } # Crates included if required by the API definition # Common between server and client features -hyper = {version = "0.14", features = ["full"], optional = true} -serde_ignored = {version = "0.1.1", optional = true} -url = {version = "2.1", optional = true} +bytes = "1.11" +http-body-util = "0.1.3" +hyper = { version = "1.9.0", features = ["full"], optional = true } +hyper-util = { version = "0.1.20", features = ["service"] } +serde_ignored = { version = "0.1.14", optional = true } +url = { version = "2.5", optional = true } # Client-specific +tower-service = "0.3.3" # Server, and client callback-specific -lazy_static = { version = "1.4", optional = true } -percent-encoding = {version = "2.1.0", optional = true} -regex = {version = "1.3", optional = true} +lazy_static = { version = "1.5", optional = true } +regex = { version = "1.12", optional = true } +percent-encoding = { version = "2.3.2", optional = true } + +# CLI-specific +anyhow = { version = "1", optional = true } +clap = { version = "4.6.0", features = ["env"], optional = true } +clap-verbosity-flag = { version = "3.0", optional = true } +simple_logger = { version = "5.2.0", features = ["stderr"], optional = true } +tokio = { version = "1.50.0", features = ["rt-multi-thread", "macros"], optional = true } # Conversion -frunk = { version = "0.3.0", optional = true } -frunk_derives = { version = "0.3.0", optional = true } -frunk_core = { version = "0.3.0", optional = true } -frunk-enum-derive = { version = "0.2.0", optional = true } -frunk-enum-core = { version = "0.2.0", optional = true } +frunk = { version = "0.4.4", optional = true } +frunk_derives = { version = "0.4.4", optional = true } +frunk_core = { version = "0.4.4", optional = true } +frunk-enum-derive = { version = "0.3.0", optional = true } +frunk-enum-core = { version = "0.3.0", optional = true } -# Bearer authentication -jsonwebtoken = { version = "9.3.0", optional = false } +# TLS dependencies - platform-specific backends +# On macOS/Windows/iOS, use native-tls via hyper-tls +[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] +native-tls = { version = "0.2", optional = true } +hyper-tls = { version = "0.6", optional = true } + +# On other platforms (Linux, etc.), use OpenSSL via hyper-openssl +[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] +openssl = { version = "0.10", optional = true } +hyper-openssl = { version = "0.10", optional = true } [dev-dependencies] -clap = "2.25" -env_logger = "0.7" -tokio = { version = "1.14", features = ["full"] } +always_send = "0.1.1" +clap = "4.6.0" +env_logger = "0.11" +tokio = { version = "1.50.0", features = ["full"] } native-tls = "0.2" +pin-project = "1.1.11" + +# Bearer authentication, used in examples +jsonwebtoken = {version = "10.3.0", features = ["rust_crypto"]} [target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies] -tokio-openssl = "0.6" openssl = "0.10" +tokio-openssl = "0.6" [[example]] -name = "client" +name = "ping-bearer-auth-client" +path = "examples/client/main.rs" required-features = ["client"] [[example]] -name = "server" +name = "ping-bearer-auth-server" +path = "examples/server/main.rs" required-features = ["server"] + +[[bin]] +name = "ping-bearer-auth" +path = "bin/cli.rs" +required-features = ["client", "cli"] diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/README.md b/samples/server/petstore/rust-server/output/ping-bearer-auth/README.md index 559f00885f4c..3b097677855f 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/README.md +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/README.md @@ -14,7 +14,7 @@ To see how to make this your own, look here: [README]((https://openapi-generator.tech)) - API version: 1.0 -- Generator version: 8.0.0-SNAPSHOT +- Generator version: 7.22.0-SNAPSHOT @@ -23,6 +23,7 @@ This autogenerated project defines an API crate `ping-bearer-auth` which contain * Data types representing the underlying data model. * A `Client` type which implements `Api` and issues HTTP requests for each operation. * A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. +* A CLI tool to drive basic API operations from the command line. It also contains an example server and client which make use of `ping-bearer-auth`: @@ -34,41 +35,65 @@ It also contains an example server and client which make use of `ping-bearer-aut arguments on the command line. You can use the example server and client as a basis for your own code. -See below for [more detail on implementing a server](#writing-a-server). +See below for [more detail on the examples](#using-the-generated-library). + +## CLI + +Run the included CLI tool with: + +``` +cargo run --bin cli --features=cli +``` + +To pass in arguments, put them after `--`, for example: + +``` +cargo run --bin cli --features=cli -- --help +``` + +See the help text for available options. + +To build a standalone tool, use: + +``` +cargo build --bin cli --features=cli --release +``` + +You'll find the binary at `target/release/cli`. ## Examples Run examples with: ``` -cargo run --example +cargo run --example ping-bearer-auth- ``` To pass in arguments to the examples, put them after `--`, for example: ``` -cargo run --example client -- --help +cargo run --example ping-bearer-auth-client -- --help ``` ### Running the example server To run the server, follow these simple steps: ``` -cargo run --example server +cargo run --example ping-bearer-auth-server ``` ### Running the example client To run a client, follow one of the following simple steps: ``` -cargo run --example client PingGet +cargo run --example ping-bearer-auth-client PingGet ``` ### HTTPS The examples can be run in HTTPS mode by passing in the flag `--https`, for example: ``` -cargo run --example server -- --https +cargo run --example ping-bearer-auth-server -- --https ``` This will use the keys/certificates from the examples directory. Note that the @@ -84,8 +109,36 @@ The generated library has a few optional features that can be activated through * `client` * This defaults to enabled and creates the basic skeleton of a client implementation based on hyper * The constructed client implements the API trait by making remote API call. +* `client-tls` + * This default to enabled and provides HTTPS support with automatic TLS backend selection: + - macOS/Windows/iOS: native-tls + hyper-tls + - Linux/Unix/others: OpenSSL + hyper-openssl * `conversions` * This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types. +* `cli` + * This defaults to disabled and is required for building the included CLI tool. +* `validate` + * This defaults to disabled and allows JSON Schema validation of received data using `MakeService::set_validation` or `Service::set_validation`. + * Note, enabling validation will have a performance penalty, especially if the API heavily uses regex based checks. + +### HTTPS/TLS Support + +HTTPS support is included by default. To disable it (for example, to reduce dependencies), you can: + +```toml +[dependencies] +ping-bearer-auth = { version = "1.0.0", default-features = false, features = ["client", "server"] } +``` + +**For server with callbacks that need HTTPS:** +```toml +[dependencies] +ping-bearer-auth = { version = "1.0.0", features = ["server", "client-tls"] } +``` + +The TLS backend is automatically selected based on your target platform: +- **macOS, Windows, iOS**: Uses `native-tls` (system TLS libraries) +- **Linux, Unix, other platforms**: Uses `openssl` See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`. diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/bin/cli.rs b/samples/server/petstore/rust-server/output/ping-bearer-auth/bin/cli.rs new file mode 100644 index 000000000000..7256eebe98c3 --- /dev/null +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/bin/cli.rs @@ -0,0 +1,164 @@ +//! CLI tool driving the API client +use anyhow::{anyhow, Context, Result}; +use clap::Parser; +use log::{debug, info}; +// models may be unused if all inputs are primitive types +#[allow(unused_imports)] +use ping_bearer_auth::{ + models, ApiNoContext, Client, ContextWrapperExt, + PingGetResponse, +}; +use simple_logger::SimpleLogger; +use swagger::{AuthData, ContextBuilder, EmptyContext, Push, XSpanIdString}; + +type ClientContext = swagger::make_context_ty!( + ContextBuilder, + EmptyContext, + Option, + XSpanIdString +); + +#[derive(Parser, Debug)] +#[clap( + name = "ping test", + version = "1.0", + about = "CLI access to ping test" +)] +struct Cli { + #[clap(subcommand)] + operation: Operation, + + /// Address or hostname of the server hosting this API, including optional port + #[clap(short = 'a', long, default_value = "http://localhost")] + server_address: String, + + /// Path to the client private key if using client-side TLS authentication + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_certificate", "server_certificate"]))] + client_key: Option, + + /// Path to the client's public certificate associated with the private key + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_key", "server_certificate"]))] + client_certificate: Option, + + /// Path to CA certificate used to authenticate the server + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long)] + server_certificate: Option, + + /// If set, write output to file instead of stdout + #[clap(short, long)] + output_file: Option, + + #[command(flatten)] + verbosity: clap_verbosity_flag::Verbosity, + + /// Bearer token if used for authentication + #[arg(env = "PING_BEARER_AUTH_BEARER_TOKEN", hide_env = true)] + bearer_token: Option, +} + +#[derive(Parser, Debug)] +enum Operation { + PingGet { + }, +} + +// On Linux/Unix with OpenSSL (client-tls feature), support certificate pinning and mutual TLS +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + if args.client_certificate.is_some() { + debug!("Using mutual TLS"); + let client = Client::try_new_https_mutual( + &args.server_address, + args.server_certificate.clone().unwrap(), + args.client_key.clone().unwrap(), + args.client_certificate.clone().unwrap(), + ) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else if args.server_certificate.is_some() { + debug!("Using TLS with pinned server certificate"); + let client = + Client::try_new_https_pinned(&args.server_address, args.server_certificate.clone().unwrap()) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else { + debug!("Using client without certificates"); + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) + } +} + +// On macOS/Windows/iOS or without client-tls feature, use simple client (no cert pinning/mutual TLS) +#[cfg(any( + not(feature = "client-tls"), + all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")) +))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + // Client::try_new() automatically detects the URL scheme (http:// or https://) + // and creates the appropriate client. + // Note: Certificate pinning and mutual TLS are only available on Linux/Unix with OpenSSL + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) +} + +#[tokio::main] +async fn main() -> Result<()> { + let args = Cli::parse(); + if let Some(log_level) = args.verbosity.log_level() { + SimpleLogger::new().with_level(log_level.to_level_filter()).init()?; + } + + debug!("Arguments: {:?}", &args); + + let mut auth_data: Option = None; + + if let Some(ref bearer_token) = args.bearer_token { + debug!("Using bearer token"); + auth_data = AuthData::bearer(bearer_token); + } + + #[allow(trivial_casts)] + let context = swagger::make_context!( + ContextBuilder, + EmptyContext, + auth_data, + XSpanIdString::default() + ); + + let client = create_client(&args, context)?; + + let result = match args.operation { + Operation::PingGet { + } => { + info!("Performing a PingGet request"); + + let result = client.ping_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + PingGetResponse::OK + => "OK\n".to_string() + , + } + } + }; + + if let Some(output_file) = args.output_file { + std::fs::write(output_file, result)? + } else { + println!("{}", result); + } + Ok(()) +} + +// May be unused if all inputs are primitive types +#[allow(dead_code)] +fn parse_json(json_string: &str) -> Result { + serde_json::from_str(json_string).map_err(|err| anyhow!("Error parsing input: {}", err)) +} diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/client/main.rs b/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/client/main.rs index 3ef61d5f2a4b..38d66b01a81c 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/client/main.rs +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/client/main.rs @@ -7,7 +7,7 @@ use futures::{future, Stream, stream}; use ping_bearer_auth::{Api, ApiNoContext, Claims, Client, ContextWrapperExt, models, PingGetResponse, }; -use clap::{App, Arg}; +use clap::{Command, Arg}; // NOTE: Set environment variable RUST_LOG to the name of the executable (or "cargo run") to activate console logging for all loglevels. // See https://docs.rs/env_logger/latest/env_logger/ for more details @@ -30,25 +30,23 @@ use client_auth::build_token; fn main() { env_logger::init(); - let matches = App::new("client") - .arg(Arg::with_name("operation") + let matches = Command::new("client") + .arg(Arg::new("operation") .help("Sets the operation to run") - .possible_values(&[ - "PingGet", - ]) + .value_parser(Vec::<&str>::from([ + "PingGet", + ])) .required(true) .index(1)) - .arg(Arg::with_name("https") + .arg(Arg::new("https") .long("https") .help("Whether to use HTTPS or not")) - .arg(Arg::with_name("host") + .arg(Arg::new("host") .long("host") - .takes_value(true) .default_value("localhost") .help("Hostname to contact")) - .arg(Arg::with_name("port") + .arg(Arg::new("port") .long("port") - .takes_value(true) .default_value("8080") .help("Port to contact")) .get_matches(); @@ -57,53 +55,68 @@ fn main() { // In a real (production) system this Bearer token should be obtained via an external Identity/Authentication-server // Ensure that you set the correct algorithm and encodingkey that matches what is used on the server side. // See https://github.com/Keats/jsonwebtoken for more information - let auth_token = build_token( Claims { - sub: "tester@acme.com".to_owned(), + sub: "tester@acme.com".to_owned(), company: "ACME".to_owned(), iss: "my_identity_provider".to_owned(), // added a very long expiry time aud: "org.acme.Resource_Server".to_string(), exp: 10000000000, // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ - ].join(", ") - }, + scopes: + "".to_owned() + }, b"secret").unwrap(); let auth_data = if !auth_token.is_empty() { - Some(AuthData::Bearer(swagger::auth::Bearer { token: auth_token})) + Some(AuthData::Bearer(auth_token)) } else { // No Bearer-token available, so return None None }; - let is_https = matches.is_present("https"); + let is_https = matches.contains_id("https"); let base_url = format!("{}://{}:{}", if is_https { "https" } else { "http" }, - matches.value_of("host").unwrap(), - matches.value_of("port").unwrap()); + matches.get_one::("host").unwrap(), + matches.get_one::("port").unwrap()); let context: ClientContext = swagger::make_context!(ContextBuilder, EmptyContext, auth_data, XSpanIdString::default()); - let mut client : Box> = if matches.is_present("https") { - // Using Simple HTTPS - let client = Box::new(Client::try_new_https(&base_url) - .expect("Failed to create HTTPS client")); - Box::new(client.with_context(context)) - } else { - // Using HTTP - let client = Box::new(Client::try_new_http( - &base_url) - .expect("Failed to create HTTP client")); - Box::new(client.with_context(context)) + let mut client : Box> = { + #[cfg(feature = "client-tls")] + { + if is_https { + // Using HTTPS with native-tls + let client = Box::new(Client::try_new_https(&base_url) + .expect("Failed to create HTTPS client")); + Box::new(client.with_context(context)) + } else { + // Using HTTP + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } + } + + #[cfg(not(feature = "client-tls"))] + { + if is_https { + panic!("HTTPS requested but TLS support not enabled. \ + Enable the 'client-tls' feature to use HTTPS."); + } + // Using HTTP only + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } }; let mut rt = tokio::runtime::Runtime::new().unwrap(); - match matches.value_of("operation") { + match matches.get_one::("operation").map(String::as_str) { Some("PingGet") => { let result = rt.block_on(client.ping_get( )); diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/server/main.rs b/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/server/main.rs index 6b54873a7e94..dd1bc41aaea0 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/server/main.rs +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/server/main.rs @@ -3,26 +3,26 @@ #![allow(missing_docs)] - -use clap::{App, Arg}; +use clap::{Arg, Command}; mod server; mod server_auth; - /// Create custom server, wire it to the autogenerated router, /// and pass it to the web server. #[tokio::main] async fn main() { env_logger::init(); - let matches = App::new("server") - .arg(Arg::with_name("https") - .long("https") - .help("Whether to use HTTPS or not")) + let matches = Command::new("server") + .arg( + Arg::new("https") + .long("https") + .help("Whether to use HTTPS or not"), + ) .get_matches(); let addr = "127.0.0.1:8080"; - server::create(addr, matches.is_present("https")).await; + server::create(addr, matches.contains_id("https")).await; } diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/server/server.rs b/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/server/server.rs index ffbd60200e8a..730c04688602 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/server/server.rs +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/server/server.rs @@ -4,8 +4,9 @@ use async_trait::async_trait; use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt}; -use hyper::server::conn::Http; -use hyper::service::Service; +use hyper::server::conn::http1; +use hyper_util::rt::TokioIo; +use hyper::service::{service_fn, Service}; use log::info; use std::future::Future; use std::marker::PhantomData; @@ -24,15 +25,13 @@ use ping_bearer_auth::models; /// Builds an SSL implementation for Simple HTTPS from some hard-coded file names pub async fn create(addr: &str, https: bool) { - let addr = addr.parse().expect("Failed to parse bind address"); + let addr: SocketAddr = addr.parse().expect("Failed to parse bind address"); + let listener = TcpListener::bind(&addr).await.unwrap(); let server = Server::new(); let service = MakeService::new(server); - - // This pushes a fourth layer of the middleware-stack even though Swagger assumes only three levels. - // This fourth layer creates an accept-all policy, hower the example-code already acchieves the same via a Bearer-token with full permissions, so next line is not needed (anymore). - // let service = MakeAllowAllAuthenticator::new(service, "cosmo"); + let service = MakeAllowAllAuthenticator::new(service, "cosmo"); #[allow(unused_mut)] let mut service = @@ -56,21 +55,19 @@ pub async fn create(addr: &str, https: bool) { ssl.check_private_key().expect("Failed to check private key"); let tls_acceptor = ssl.build(); - let tcp_listener = TcpListener::bind(&addr).await.unwrap(); info!("Starting a server (with https)"); loop { - if let Ok((tcp, _)) = tcp_listener.accept().await { + if let Ok((tcp, addr)) = listener.accept().await { let ssl = Ssl::new(tls_acceptor.context()).unwrap(); - let addr = tcp.peer_addr().expect("Unable to get remote address"); let service = service.call(addr); tokio::spawn(async move { let tls = tokio_openssl::SslStream::new(ssl, tcp).map_err(|_| ())?; let service = service.await.map_err(|_| ())?; - Http::new() - .serve_connection(tls, service) + http1::Builder::new() + .serve_connection(TokioIo::new(tls), service) .await .map_err(|_| ()) }); @@ -79,12 +76,40 @@ pub async fn create(addr: &str, https: bool) { } } else { info!("Starting a server (over http, so no TLS)"); - // Using HTTP - hyper::server::Server::bind(&addr).serve(service).await.unwrap() + println!("Listening on http://{}", addr); + + loop { + // When an incoming TCP connection is received grab a TCP stream for + // client<->server communication. + // + // Note, this is a .await point, this loop will loop forever but is not a busy loop. The + // .await point allows the Tokio runtime to pull the task off of the thread until the task + // has work to do. In this case, a connection arrives on the port we are listening on and + // the task is woken up, at which point the task is then put back on a thread, and is + // driven forward by the runtime, eventually yielding a TCP stream. + let (tcp_stream, addr) = listener.accept().await.expect("Failed to accept connection"); + + let service = service.call(addr).await.unwrap(); + let io = TokioIo::new(tcp_stream); + // Spin up a new task in Tokio so we can continue to listen for new TCP connection on the + // current task without waiting for the processing of the HTTP1 connection we just received + // to finish + tokio::task::spawn(async move { + // Handle the connection from the client using HTTP1 and pass any + // HTTP requests received on that connection to the `hello` function + let result = http1::Builder::new() + .serve_connection(io, service) + .await; + if let Err(err) = result + { + println!("Error serving connection: {err:?}"); + } + }); + } } } -#[derive(Copy, Clone)] +#[derive(Copy)] pub struct Server { marker: PhantomData, } @@ -95,6 +120,14 @@ impl Server { } } +impl Clone for Server { + fn clone(&self) -> Self { + Self { + marker: PhantomData, + } + } +} + use jsonwebtoken::{decode, encode, errors::Error as JwtError, Algorithm, DecodingKey, EncodingKey, Header, TokenData, Validation}; use serde::{Deserialize, Serialize}; diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/server/server_auth.rs b/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/server/server_auth.rs index e7d21b06931a..072c7f2a3d43 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/server/server_auth.rs +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/examples/server/server_auth.rs @@ -1,8 +1,8 @@ use swagger::{ ApiError, - auth::{Basic, Bearer}, - Has, + Has, XSpanIdString}; +use headers::authorization::{Basic, Bearer}; use ping_bearer_auth::{AuthenticationApi, Claims}; use crate::server::Server; use jsonwebtoken::{decode, errors as JwtError, decode_header, DecodingKey, TokenData, Validation}; @@ -15,24 +15,24 @@ use log::{error, debug}; /// Get a dummy claim with full permissions (all scopes) for testing purposes fn full_permission_claim() -> Claims { - Claims { - sub: "tester@acme.com".to_owned(), - company: "ACME".to_owned(), - iss: "mini-bank-IDP".to_owned(), - aud: "org.acme.Resource_Server".to_string(), - // added a very long expiry time - exp: 10000000000, - // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ - ].join(", ") - } + // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. + Claims { + sub: "tester@acme.com".to_owned(), + company: "ACME".to_owned(), + iss: "mini-bank-IDP".to_owned(), + aud: "org.acme.Resource_Server".to_string(), + // added a very long expiry time + exp: 10000000000, + scopes: + "".to_owned() + } } -/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. +/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. fn extract_token_data(token: &str, key: &[u8]) -> Result, JwtError::Error> { - + // Ensure that you set the correct algorithm and correct key. // See https://github.com/Keats/jsonwebtoken for more information. let header = decode_header(token)?; @@ -63,8 +63,8 @@ fn build_authorization(claims: Claims) -> Authorization { let scopes = swagger::auth::Scopes::Some(scopes); Authorization{ - subject: claims.sub, - scopes, + subject: claims.sub, + scopes, issuer: Some(claims.iss)} } @@ -87,7 +87,7 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn bearer_authorization(&self, bearer: &Bearer) -> Result { debug!("\tAuthorizationApi: Received Bearer-token, {bearer:#?}"); - match extract_token_data(&bearer.token, b"secret") { + match extract_token_data(&bearer.token(), b"secret") { Ok(auth_data) => { debug!("\tUnpack auth_data as: {auth_data:#?}"); let authorization = build_authorization(auth_data.claims); @@ -105,23 +105,22 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn apikey_authorization(&self, api_key: &str) -> Result { debug!("\tAuthorizationApi: Received api-key, {api_key:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } - + /// Implementation of the method to map a basic authentication (username and password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result { debug!("\tAuthorizationApi: Received Basic-token, {basic:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } -} - +} diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/auth.rs b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/auth.rs index cbaba3dca7c6..a6a39f79450f 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/auth.rs +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/auth.rs @@ -1,8 +1,7 @@ use std::collections::BTreeSet; -use crate::server::Authorization; use serde::{Deserialize, Serialize}; -use swagger::{ApiError, auth::{Basic, Bearer}}; - +use swagger::{ApiError, auth::Authorization}; +use headers::authorization::{Basic, Bearer}; #[derive(Debug, Serialize, Deserialize)] pub struct Claims { pub sub: String, @@ -24,7 +23,7 @@ pub trait AuthenticationApi { /// Method should be implemented (see example-code) to map Basic (Username:password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result; -} +} // Implement it for AllowAllAuthenticator (dummy is needed, but should not used as we have Bearer authorization) use swagger::auth::{AllowAllAuthenticator, RcBound, Scopes}; @@ -34,7 +33,7 @@ fn dummy_authorization() -> Authorization { // However, if you want to use it anyway this can not be unimplemented, so dummy implementation added. // unimplemented!() Authorization{ - subject: "Dummmy".to_owned(), + subject: "Dummy".to_owned(), scopes: Scopes::Some(BTreeSet::new()), // create an empty scope, as this should not be used issuer: None } diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/client/mod.rs b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/client/mod.rs index 22eb1b5814c8..49ead2648b88 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/client/mod.rs +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/client/mod.rs @@ -1,10 +1,12 @@ use async_trait::async_trait; +use bytes::Bytes; use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt}; +use http_body_util::{combinators::BoxBody, Full}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; -use hyper::{Body, Request, Response, service::Service, Uri}; +use hyper::{body::{Body, Incoming}, Request, Response, service::Service, Uri}; use percent_encoding::{utf8_percent_encode, AsciiSet}; use std::borrow::Cow; -use std::convert::TryInto; +use std::convert::{TryInto, Infallible}; use std::io::{ErrorKind, Read}; use std::error::Error; use std::future::Future; @@ -18,6 +20,7 @@ use std::string::ToString; use std::task::{Context, Poll}; use swagger::{ApiError, AuthData, BodyExt, Connector, DropContextService, Has, XSpanIdString}; use url::form_urlencoded; +use tower_service::Service as _; use crate::models; @@ -54,15 +57,14 @@ fn into_base_path(input: impl TryInto, } let host = uri.host().ok_or(ClientInitError::MissingHost)?; - let port = uri.port_u16().map(|x| format!(":{}", x)).unwrap_or_default(); - Ok(format!("{}://{}{}{}", scheme, host, port, uri.path().trim_end_matches('/'))) + let port = uri.port_u16().map(|x| format!(":{x}")).unwrap_or_default(); + Ok(format!("{scheme}://{host}{port}{}", uri.path().trim_end_matches('/'))) } /// A client that implements the API by making HTTP calls out to a server. pub struct Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -79,8 +81,7 @@ pub struct Client where impl fmt::Debug for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -92,8 +93,7 @@ impl fmt::Debug for Client where impl Clone for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -107,8 +107,19 @@ impl Clone for Client where } } -impl Client, C>, C> where - Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static, +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + Connector, + BoxBody + > + >, + C + >, + C +> where + Connector: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static, C: Clone + Send + Sync + 'static, { /// Create a client with a custom implementation of hyper::client::Connect. @@ -122,7 +133,7 @@ impl Client" /// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")` /// * `connector` - Implementation of `hyper::client::Connect` to use for the client pub fn try_new_with_connector( @@ -131,8 +142,8 @@ impl Client Result { - let client_service = hyper::client::Client::builder().build(connector); - let client_service = DropContextService::new(client_service); + let client_service = hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector); + let client_service = DropContextService::new(hyper_util::service::TowerToHyperService::new(client_service)); Ok(Self { client_service, @@ -142,28 +153,29 @@ impl Client; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HyperHttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + #[derive(Debug, Clone)] pub enum HyperClient { - Http(hyper::client::Client), - Https(hyper::client::Client), + Http(hyper_util::client::legacy::Client>), + #[cfg(feature = "client-tls")] + Https(hyper_util::client::legacy::Client>), } -impl Service> for HyperClient { - type Response = Response; - type Error = hyper::Error; - type Future = hyper::client::ResponseFuture; - - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - match self { - HyperClient::Http(client) => client.poll_ready(cx), - HyperClient::Https(client) => client.poll_ready(cx), - } - } +impl Service>> for HyperClient { + type Response = Response; + type Error = hyper_util::client::legacy::Error; + type Future = hyper_util::client::legacy::ResponseFuture; - fn call(&mut self, req: Request) -> Self::Future { + fn call(&self, req: Request>) -> Self::Future { match self { - HyperClient::Http(client) => client.call(req), - HyperClient::Https(client) => client.call(req) + HyperClient::Http(client) => client.request(req), + #[cfg(feature = "client-tls")] + HyperClient::Https(client) => client.request(req), } } } @@ -174,7 +186,7 @@ impl Client, C> where /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new( base_path: &str, ) -> Result { @@ -187,13 +199,19 @@ impl Client, C> where let client_service = match scheme.as_str() { "http" => { - HyperClient::Http(hyper::client::Client::builder().build(connector.build())) + HyperClient::Http(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector.build())) + }, + #[cfg(feature = "client-tls")] + "https" => { + let https_connector = connector + .https() + .build() + .map_err(ClientInitError::SslError)?; + HyperClient::Https(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(https_connector)) }, + #[cfg(not(feature = "client-tls"))] "https" => { - let connector = connector.https() - .build() - .map_err(ClientInitError::SslError)?; - HyperClient::Https(hyper::client::Client::builder().build(connector)) + return Err(ClientInitError::TlsNotEnabled); }, _ => { return Err(ClientInitError::InvalidScheme); @@ -210,13 +228,24 @@ impl Client, C> where } } -impl Client, C>, C> where +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + hyper_util::client::legacy::connect::HttpConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new_http( base_path: &str, ) -> Result { @@ -226,19 +255,46 @@ impl Client; - -#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] -type HttpsConnector = hyper_openssl::HttpsConnector; - -impl Client, C>, C> where +#[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] +type HttpsConnector = hyper_tls::HttpsConnector; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + +#[cfg(feature = "client-tls")] +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + HttpsConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { - /// Create a client with a TLS connection to the server + /// Create a client with a TLS connection to the server. + /// + /// # Arguments + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + pub fn try_new_https(base_path: &str) -> Result + { + let https_connector = Connector::builder() + .https() + .build() + .map_err(ClientInitError::SslError)?; + Self::try_new_with_connector(base_path, Some("https"), https_connector) + } + + /// Create a client with a TLS connection to the server using OpenSSL via swagger. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn try_new_https(base_path: &str) -> Result { let https_connector = Connector::builder() @@ -248,10 +304,10 @@ impl Client, C Self::try_new_with_connector(base_path, Some("https"), https_connector) } - /// Create a client with a TLS connection to the server using a pinned certificate + /// Create a client with a TLS connection to the server using a pinned certificate. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn try_new_https_pinned( @@ -272,7 +328,7 @@ impl Client, C /// Create a client with a mutually authenticated TLS connection to the server. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server /// * `client_key` - Path to the client private key /// * `client_certificate` - Path to the client's public certificate associated with the private key @@ -300,8 +356,7 @@ impl Client, C impl Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -335,12 +390,15 @@ pub enum ClientInitError { /// Missing Hostname MissingHost, + /// HTTPS requested but TLS features not enabled + TlsNotEnabled, + /// SSL Connection Error - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + #[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] SslError(native_tls::Error), /// SSL Connection Error - #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] SslError(openssl::error::ErrorStack), } @@ -363,28 +421,31 @@ impl Error for ClientInitError { } } +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + #[async_trait] -impl Api for Client where +impl Api for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C), + Response=Response> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Has + Has> + Clone + Send + Sync + 'static, + B: hyper::body::Body + Send + 'static + Unpin, + B::Data: Send, + B::Error: Into>, { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - match self.client_service.clone().poll_ready(cx) { - Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())), - Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)), - Poll::Pending => Poll::Pending, - } - } + #[allow(clippy::vec_init_then_push)] async fn ping_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/ping", self.base_path @@ -402,44 +463,43 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); #[allow(clippy::collapsible_match)] if let Some(auth_data) = Has::>::get(context).as_ref() { - // Currently only authentication with Basic and Bearer are supported + use headers::authorization::Credentials; #[allow(clippy::single_match, clippy::match_single_binding)] match auth_data { - AuthData::Bearer(bearer_header) => { - let auth = swagger::auth::Header(bearer_header.clone()); - let header = match HeaderValue::from_str(&format!("{}", auth)) { + AuthData::Bearer(ref bearer_header) => { + let header = match headers::Authorization::bearer(&bearer_header.to_string()) { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create Authorization header: {e}"))) }; request.headers_mut().insert( hyper::header::AUTHORIZATION, - header); + header.0.encode()); }, _ => {} } } let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 201 => { @@ -449,18 +509,16 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/context.rs b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/context.rs index e01187ca3c82..7a52731cc064 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/context.rs +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/context.rs @@ -6,9 +6,9 @@ use std::default::Default; use std::io; use std::marker::PhantomData; use std::task::{Poll, Context}; -use swagger::auth::{AuthData, Authorization, Bearer, Scopes}; +use swagger::auth::{AuthData, Authorization, Scopes}; use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString}; -use crate::{Api, AuthenticationApi}; +use crate::Api; use log::error; pub struct MakeAddContext { @@ -16,11 +16,11 @@ pub struct MakeAddContext { marker: PhantomData, } -impl MakeAddContext +impl MakeAddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, + C: Send + 'static, { pub fn new(inner: T) -> MakeAddContext { MakeAddContext { @@ -30,27 +30,34 @@ where } } +impl Clone for MakeAddContext +where + T: Clone, +{ + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + // Make a service that adds context. -impl Service for +impl Service for MakeAddContext where Target: Send, A: Default + Push + Send, B: Push, Result = C>, - C: Push, Result = D>, - D: Send + 'static, + C: Send + 'static, T: Service + Send, T::Future: Send + 'static { type Error = T::Error; - type Response = AddContext; + type Response = AddContext; type Future = BoxFuture<'static, Result>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, target: Target) -> Self::Future { + fn call(&self, target: Target) -> Self::Future { let service = self.inner.call(target); Box::pin(async move { @@ -60,21 +67,17 @@ where } /// Middleware to add context data from the request -pub struct AddContext -where - A: Default + Push, - B: Push, Result = C>, - C: Push, Result = D> +#[derive(Debug, Clone)] +pub struct AddContext { inner: T, marker: PhantomData, } -impl AddContext +impl AddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, { pub fn new(inner: T) -> Self { AddContext { @@ -84,49 +87,32 @@ where } } -impl Service> for AddContext +impl Service> for AddContext where A: Default + Push, B: Push, Result=C>, - C: Push, Result=D>, - D: Send + 'static, - T: Service<(Request, D)> + AuthenticationApi + C: Send + 'static, + T: Service<(Request, C)> { type Error = T::Error; type Future = T::Future; type Response = T::Response; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - - fn call(&mut self, request: Request) -> Self::Future { + fn call(&self, request: Request) -> Self::Future { let context = A::default().push(XSpanIdString::get_or_generate(&request)); let headers = request.headers(); { - use swagger::auth::Bearer; + use headers::authorization::Bearer; use std::ops::Deref; - if let Some(bearer) = swagger::auth::from_headers::(headers) { - let authorization = self.inner.bearer_authorization(&bearer); - let auth_data = AuthData::Bearer(bearer); - - let context = context.push(Some(auth_data)); - let context = match authorization { - Ok(auth) => context.push(Some(auth)), - Err(err) => { - error!("Error during Authorization: {err:?}"); - context.push(None::) - } - }; + if let Some(bearer) = swagger::auth::from_headers(headers) { + let context = context.push(Some(bearer)); return self.inner.call((request, context)) } } let context = context.push(None::); - let context = context.push(None::); self.inner.call((request, context)) } diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/header.rs b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/header.rs index 5bc6ebe929b9..823d2779b31f 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/header.rs +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/header.rs @@ -31,11 +31,9 @@ macro_rules! ihv_generate { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse::<$t>() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse {} as a string: {}", - stringify!($t), e)), + Err(e) => Err(format!("Unable to parse {} as a string: {e}", stringify!($t))), }, - Err(e) => Err(format!("Unable to parse header {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header {hdr_value:?} as a string - {e}")), } } } @@ -76,8 +74,7 @@ impl TryFrom for IntoHeaderValue> { y => Some(y.to_string()), }) .collect())), - Err(e) => Err(format!("Unable to parse header: {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header: {hdr_value:?} as a string - {e}")), } } } @@ -88,8 +85,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(&hdr_value.0.join(", ")) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} into a header - {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} into a header - {e}")) } } } @@ -102,8 +98,7 @@ impl TryFrom for IntoHeaderValue { fn try_from(hdr_value: HeaderValue) -> Result { match hdr_value.to_str() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())), - Err(e) => Err(format!("Unable to convert header {:?} to {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to {e}")), } } } @@ -114,8 +109,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")) } } } @@ -128,11 +122,9 @@ impl TryFrom for IntoHeaderValue { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse bool from {} - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse bool from {hdr_value} - {e}")), }, - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")), } } } @@ -143,8 +135,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0.to_string()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert: {:?} into a header: {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert: {hdr_value:?} into a header: {e}")) } } } @@ -158,11 +149,9 @@ impl TryFrom for IntoHeaderValue> { match hdr_value.to_str() { Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) { Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))), - Err(e) => Err(format!("Unable to parse: {} as date - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse: {hdr_value} as date - {e}")), }, - Err(e) => Err(format!("Unable to convert header {:?} to string {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to string {e}")), } } } @@ -173,8 +162,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} to a header: {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} to a header: {e}")), } } } diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/lib.rs b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/lib.rs index 495d022b04a3..0c42b196f262 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/lib.rs +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/lib.rs @@ -3,14 +3,15 @@ use async_trait::async_trait; use futures::Stream; +#[cfg(feature = "mock")] +use mockall::automock; use std::error::Error; use std::collections::BTreeSet; use std::task::{Poll, Context}; -use swagger::{ApiError, ContextWrapper}; +use swagger::{ApiError, ContextWrapper, auth::Authorization}; use serde::{Serialize, Deserialize}; -use crate::server::Authorization; - +#[cfg(any(feature = "client", feature = "server"))] type ServiceError = Box; pub const BASE_PATH: &str = ""; @@ -27,13 +28,10 @@ pub enum PingGetResponse { } /// API +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait Api { - fn poll_ready(&self, _cx: &mut Context) -> Poll>> { - Poll::Ready(Ok(())) - } - async fn ping_get( &self, context: &C) -> Result; @@ -41,11 +39,14 @@ pub trait Api { } /// API where `Context` isn't passed on every API call +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait ApiNoContext { - - fn poll_ready(&self, _cx: &mut Context) -> Poll>>; + // The std::task::Context struct houses a reference to std::task::Waker with the lifetime <'a>. + // Adding an anonymous lifetime `'a` to allow mockall to create a mock object with the right lifetimes. + // This is needed because the compiler is unable to determine the lifetimes on F's trait bound + // where F is the closure created by mockall. We use higher-rank trait bounds here to get around this. fn context(&self) -> &C; @@ -70,10 +71,6 @@ impl + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt for T #[async_trait] impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for ContextWrapper { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - self.api().poll_ready(cx) - } - fn context(&self) -> &C { ContextWrapper::context(self) } diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/models.rs b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/models.rs index f0f5817e64e9..e37352d5d2af 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/models.rs +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/models.rs @@ -1,7 +1,9 @@ #![allow(unused_qualifications)] - +#[cfg(not(feature = "validate"))] use validator::Validate; use crate::models; #[cfg(any(feature = "client", feature = "server"))] use crate::header; +#[cfg(feature = "validate")] +use serde_valid::Validate; diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/server/mod.rs b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/server/mod.rs index 7807c3de2bed..adce42a8b6ae 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/server/mod.rs +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/server/mod.rs @@ -1,10 +1,14 @@ +use bytes::Bytes; use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt}; -use hyper::{Request, Response, StatusCode, Body, HeaderMap}; +use http_body_util::{combinators::BoxBody, Full}; +use hyper::{body::{Body, Incoming}, HeaderMap, Request, Response, StatusCode}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; use log::warn; +#[cfg(feature = "validate")] +use serde_valid::Validate; #[allow(unused_imports)] use std::convert::{TryFrom, TryInto}; -use std::error::Error; +use std::{convert::Infallible, error::Error}; use std::future::Future; use std::marker::PhantomData; use std::task::{Context, Poll}; @@ -18,7 +22,7 @@ use crate::{models, header, AuthenticationApi}; pub use crate::context; -type ServiceFuture = BoxFuture<'static, Result, crate::ServiceError>>; +type ServiceFuture = BoxFuture<'static, Result>, crate::ServiceError>>; use crate::{Api, PingGetResponse @@ -39,28 +43,52 @@ mod paths { } -pub struct MakeService where +pub struct MakeService +where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { api_impl: T, marker: PhantomData, + validation: bool } -impl MakeService where +impl MakeService +where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { pub fn new(api_impl: T) -> Self { MakeService { api_impl, - marker: PhantomData + marker: PhantomData, + validation: false } } + + // Turn on/off validation for the service being made. + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation; + } } +impl Clone for MakeService +where + T: Api + Clone + Send + 'static, + C: Has + Has> + Send + Sync + 'static +{ + fn clone(&self) -> Self { + Self { + api_impl: self.api_impl.clone(), + marker: PhantomData, + validation: self.validation + } + } +} -impl hyper::service::Service for MakeService where +impl hyper::service::Service for MakeService +where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { @@ -68,43 +96,72 @@ impl hyper::service::Service for MakeService where type Error = crate::ServiceError; type Future = future::Ready>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } + fn call(&self, target: Target) -> Self::Future { + let service = Service::new(self.api_impl.clone(), self.validation); - fn call(&mut self, target: Target) -> Self::Future { - future::ok(Service::new( - self.api_impl.clone(), - )) + future::ok(service) } } -fn method_not_allowed() -> Result, crate::ServiceError> { +fn method_not_allowed() -> Result>, crate::ServiceError> { Ok( Response::builder().status(StatusCode::METHOD_NOT_ALLOWED) - .body(Body::empty()) + .body(BoxBody::new(http_body_util::Empty::new())) .expect("Unable to create Method Not Allowed response") ) } +#[allow(unused_macros)] +#[cfg(not(feature = "validate"))] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => (); +} + +#[allow(unused_macros)] +#[cfg(feature = "validate")] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => { + let $parameter = if $validation { + match $parameter.validate() { + Ok(()) => $parameter, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .header(CONTENT_TYPE, mime::TEXT_PLAIN.as_ref()) + .body(BoxBody::new(format!("Invalid value in body parameter {}: {}", $base_name, e))) + .expect(&format!("Unable to create Bad Request response for invalid value in body parameter {}", $base_name))), + } + } else { + $parameter + }; + } +} + pub struct Service where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { api_impl: T, marker: PhantomData, + // Enable regex pattern validation of received JSON models + validation: bool, } impl Service where T: Api + Clone + Send + 'static, C: Has + Has> + Send + Sync + 'static { - pub fn new(api_impl: T) -> Self { + pub fn new(api_impl: T, validation: bool) -> Self { Service { api_impl, - marker: PhantomData + marker: PhantomData, + validation, } } + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation + } + } impl Clone for Service where @@ -115,32 +172,50 @@ impl Clone for Service where Service { api_impl: self.api_impl.clone(), marker: self.marker, + validation: self.validation, } } } -impl hyper::service::Service<(Request, C)> for Service where +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + +fn body_from_str(s: &str) -> BoxBody { + BoxBody::new(Full::new(Bytes::copy_from_slice(s.as_bytes()))) +} + +impl hyper::service::Service<(Request, C)> for Service where T: Api + Clone + Send + Sync + 'static, - C: Has + Has> + Send + Sync + 'static + C: Has + Has> + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, { - type Response = Response; + type Response = Response>; type Error = crate::ServiceError; type Future = ServiceFuture; - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - self.api_impl.poll_ready(cx) - } - - fn call(&mut self, req: (Request, C)) -> Self::Future { async fn run(mut api_impl: T, req: (Request, C)) -> Result, crate::ServiceError> where - T: Api + Clone + Send + 'static, - C: Has + Has> + Send + Sync + 'static - { - let (request, context) = req; - let (parts, body) = request.into_parts(); - let (method, uri, headers) = (parts.method, parts.uri, parts.headers); - let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); + fn call(&self, req: (Request, C)) -> Self::Future { + async fn run( + mut api_impl: T, + req: (Request, C), + validation: bool, + ) -> Result>, crate::ServiceError> + where + T: Api + Clone + Send + 'static, + C: Has + Has> + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, + { + let (request, context) = req; + let (parts, body) = request.into_parts(); + let (method, uri, headers) = (parts.method, parts.uri, parts.headers); + let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); - match method { + match method { // PingGet - GET /ping hyper::Method::GET if path.matched(paths::ID_PING) => { @@ -149,7 +224,7 @@ impl hyper::service::Service<(Request, C)> for Service where Some(ref authorization) => authorization, None => return Ok(Response::builder() .status(StatusCode::FORBIDDEN) - .body(Body::from("Unauthenticated")) + .body(body_from_str("Unauthenticated")) .expect("Unable to create Authentication Forbidden response")), }; } @@ -157,7 +232,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.ping_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -168,13 +243,14 @@ impl hyper::service::Service<(Request, C)> for Service where PingGetResponse::OK => { *response.status_mut() = StatusCode::from_u16(201).expect("Unable to turn 201 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -182,11 +258,17 @@ impl hyper::service::Service<(Request, C)> for Service where }, _ if path.matched(paths::ID_PING) => method_not_allowed(), - _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) - .body(Body::empty()) - .expect("Unable to create Not Found response")) + _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) + .body(BoxBody::new(http_body_util::Empty::new())) + .expect("Unable to create Not Found response")) + } } - } Box::pin(run(self.api_impl.clone(), req)) } + Box::pin(run( + self.api_impl.clone(), + req, + self.validation + )) + } } /// Request parser for `Api`. diff --git a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/server/server_auth.rs b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/server/server_auth.rs index ba78eb2f3f5d..21b1d7babd03 100644 --- a/samples/server/petstore/rust-server/output/ping-bearer-auth/src/server/server_auth.rs +++ b/samples/server/petstore/rust-server/output/ping-bearer-auth/src/server/server_auth.rs @@ -1,11 +1,12 @@ use super::Service; use crate::{Api, AuthenticationApi}; +use headers::authorization::{Basic, Bearer}; use swagger::{ ApiError, - Authorization, - auth::{Basic, Bearer}, - Has, - XSpanIdString}; + Authorization, + Has, + XSpanIdString +}; impl AuthenticationApi for Service where T: Api + Clone + Send + 'static + AuthenticationApi, diff --git a/samples/server/petstore/rust-server/output/rust-server-test/.cargo/config.toml b/samples/server/petstore/rust-server/output/rust-server-test/.cargo/config.toml new file mode 100644 index 000000000000..df91f0f117f3 --- /dev/null +++ b/samples/server/petstore/rust-server/output/rust-server-test/.cargo/config.toml @@ -0,0 +1,19 @@ +[build] +rustflags = [ + "-W", "missing_docs", # detects missing documentation for public members + + "-W", "trivial_casts", # detects trivial casts which could be removed + + "-W", "trivial_numeric_casts", # detects trivial casts of numeric types which could be removed + + # unsafe is used in `TokioIo` bridging code copied from `hyper`. + # "-W", "unsafe_code", # usage of `unsafe` code + + "-W", "unused_qualifications", # detects unnecessarily qualified names + + "-W", "unused_extern_crates", # extern crates that are never used + + "-W", "unused_import_braces", # unnecessary braces around an imported item + + "-D", "warnings", # all warnings should be denied +] diff --git a/samples/server/petstore/rust-server/output/rust-server-test/.openapi-generator/FILES b/samples/server/petstore/rust-server/output/rust-server-test/.openapi-generator/FILES index 2a4b5711f84d..0d2f1da19df9 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/.openapi-generator/FILES +++ b/samples/server/petstore/rust-server/output/rust-server-test/.openapi-generator/FILES @@ -1,8 +1,9 @@ -.cargo/config +.cargo/config.toml .gitignore Cargo.toml README.md api/openapi.yaml +bin/cli.rs docs/ANullableContainer.md docs/AdditionalPropertiesObject.md docs/AllOfObject.md diff --git a/samples/server/petstore/rust-server/output/rust-server-test/.openapi-generator/VERSION b/samples/server/petstore/rust-server/output/rust-server-test/.openapi-generator/VERSION index f1358e30d8ae..f7962df3e243 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/.openapi-generator/VERSION +++ b/samples/server/petstore/rust-server/output/rust-server-test/.openapi-generator/VERSION @@ -1 +1 @@ -8.0.0-SNAPSHOT +7.22.0-SNAPSHOT diff --git a/samples/server/petstore/rust-server/output/rust-server-test/Cargo.toml b/samples/server/petstore/rust-server/output/rust-server-test/Cargo.toml index ef05cb141e37..8a9ac600d58a 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/Cargo.toml +++ b/samples/server/petstore/rust-server/output/rust-server-test/Cargo.toml @@ -8,74 +8,122 @@ license = "Unlicense" edition = "2018" [features] -default = ["client", "server"] +default = ["client", "server", "client-tls"] client = [ - "hyper", "hyper-openssl", "hyper-tls", "native-tls", "openssl", "url" + "hyper", "percent-encoding", "hyper-util/http1", "hyper-util/http2", "url" +] +# TLS support - automatically selects backend based on target OS: +# - macOS/Windows/iOS: native-tls via hyper-tls +# - Other platforms: OpenSSL via hyper-openssl +# Dependencies are in target-specific sections below +client-tls = [ + "client", + "dep:native-tls", + "dep:hyper-tls", + "dep:openssl", + "dep:hyper-openssl", + "swagger/tls" ] server = [ - "serde_ignored", "hyper", "regex", "percent-encoding", "url", "lazy_static" + "serde_ignored", "hyper", "percent-encoding", "url", + "lazy_static", "regex" +] +cli = [ + "anyhow", "clap", "clap-verbosity-flag", "simple_logger", "tokio" ] conversion = ["frunk", "frunk_derives", "frunk_core", "frunk-enum-core", "frunk-enum-derive"] -[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] -native-tls = { version = "0.2", optional = true } -hyper-tls = { version = "0.5", optional = true } - -[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] -hyper-openssl = { version = "0.9", optional = true } -openssl = {version = "0.10", optional = true } +mock = ["mockall"] +validate = ["regex", "serde_valid", "swagger/serdevalid"] [dependencies] # Common -async-trait = "0.1.24" +async-trait = "0.1.89" chrono = { version = "0.4", features = ["serde"] } futures = "0.3" -swagger = { version = "6.1", features = ["serdejson", "server", "client", "tls", "tcp"] } -log = "0.4.0" +swagger = { version = "7.0.0", features = ["serdejson", "server", "client"] } +headers = "0.4.1" +log = "0.4.29" + mime = "0.3" +mockall = { version = "0.14", optional = true } + serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -validator = { version = "0.16", features = ["derive"] } +serde_valid = { version = "2.0", optional = true } + +validator = { version = "0.20", features = ["derive"] } # Crates included if required by the API definition # Common between server and client features -hyper = {version = "0.14", features = ["full"], optional = true} -serde_ignored = {version = "0.1.1", optional = true} -url = {version = "2.1", optional = true} +bytes = "1.11" +http-body-util = "0.1.3" +hyper = { version = "1.9.0", features = ["full"], optional = true } +hyper-util = { version = "0.1.20", features = ["service"] } +serde_ignored = { version = "0.1.14", optional = true } +url = { version = "2.5", optional = true } # Client-specific +tower-service = "0.3.3" # Server, and client callback-specific -lazy_static = { version = "1.4", optional = true } -percent-encoding = {version = "2.1.0", optional = true} -regex = {version = "1.3", optional = true} +lazy_static = { version = "1.5", optional = true } +regex = { version = "1.12", optional = true } +percent-encoding = { version = "2.3.2", optional = true } + +# CLI-specific +anyhow = { version = "1", optional = true } +clap = { version = "4.6.0", features = ["env"], optional = true } +clap-verbosity-flag = { version = "3.0", optional = true } +simple_logger = { version = "5.2.0", features = ["stderr"], optional = true } +tokio = { version = "1.50.0", features = ["rt-multi-thread", "macros"], optional = true } # Conversion -frunk = { version = "0.3.0", optional = true } -frunk_derives = { version = "0.3.0", optional = true } -frunk_core = { version = "0.3.0", optional = true } -frunk-enum-derive = { version = "0.2.0", optional = true } -frunk-enum-core = { version = "0.2.0", optional = true } +frunk = { version = "0.4.4", optional = true } +frunk_derives = { version = "0.4.4", optional = true } +frunk_core = { version = "0.4.4", optional = true } +frunk-enum-derive = { version = "0.3.0", optional = true } +frunk-enum-core = { version = "0.3.0", optional = true } -# Bearer authentication -jsonwebtoken = { version = "9.3.0", optional = false } +# TLS dependencies - platform-specific backends +# On macOS/Windows/iOS, use native-tls via hyper-tls +[target.'cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))'.dependencies] +native-tls = { version = "0.2", optional = true } +hyper-tls = { version = "0.6", optional = true } + +# On other platforms (Linux, etc.), use OpenSSL via hyper-openssl +[target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dependencies] +openssl = { version = "0.10", optional = true } +hyper-openssl = { version = "0.10", optional = true } [dev-dependencies] -clap = "2.25" -env_logger = "0.7" -tokio = { version = "1.14", features = ["full"] } +always_send = "0.1.1" +clap = "4.6.0" +env_logger = "0.11" +tokio = { version = "1.50.0", features = ["full"] } native-tls = "0.2" +pin-project = "1.1.11" + +# Bearer authentication, used in examples +jsonwebtoken = {version = "10.3.0", features = ["rust_crypto"]} [target.'cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))'.dev-dependencies] -tokio-openssl = "0.6" openssl = "0.10" +tokio-openssl = "0.6" [[example]] -name = "client" +name = "rust-server-test-client" +path = "examples/client/main.rs" required-features = ["client"] [[example]] -name = "server" +name = "rust-server-test-server" +path = "examples/server/main.rs" required-features = ["server"] + +[[bin]] +name = "rust-server-test" +path = "bin/cli.rs" +required-features = ["client", "cli"] diff --git a/samples/server/petstore/rust-server/output/rust-server-test/README.md b/samples/server/petstore/rust-server/output/rust-server-test/README.md index 9c828c9fae1f..e836d0475898 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/README.md +++ b/samples/server/petstore/rust-server/output/rust-server-test/README.md @@ -14,7 +14,7 @@ To see how to make this your own, look here: [README]((https://openapi-generator.tech)) - API version: 2.3.4 -- Generator version: 8.0.0-SNAPSHOT +- Generator version: 7.22.0-SNAPSHOT @@ -23,6 +23,7 @@ This autogenerated project defines an API crate `rust-server-test` which contain * Data types representing the underlying data model. * A `Client` type which implements `Api` and issues HTTP requests for each operation. * A router which accepts HTTP requests and invokes the appropriate `Api` method for each operation. +* A CLI tool to drive basic API operations from the command line. It also contains an example server and client which make use of `rust-server-test`: @@ -34,47 +35,71 @@ It also contains an example server and client which make use of `rust-server-tes arguments on the command line. You can use the example server and client as a basis for your own code. -See below for [more detail on implementing a server](#writing-a-server). +See below for [more detail on the examples](#using-the-generated-library). + +## CLI + +Run the included CLI tool with: + +``` +cargo run --bin cli --features=cli +``` + +To pass in arguments, put them after `--`, for example: + +``` +cargo run --bin cli --features=cli -- --help +``` + +See the help text for available options. + +To build a standalone tool, use: + +``` +cargo build --bin cli --features=cli --release +``` + +You'll find the binary at `target/release/cli`. ## Examples Run examples with: ``` -cargo run --example +cargo run --example rust-server-test- ``` To pass in arguments to the examples, put them after `--`, for example: ``` -cargo run --example client -- --help +cargo run --example rust-server-test-client -- --help ``` ### Running the example server To run the server, follow these simple steps: ``` -cargo run --example server +cargo run --example rust-server-test-server ``` ### Running the example client To run a client, follow one of the following simple steps: ``` -cargo run --example client AllOfGet -cargo run --example client DummyGet -cargo run --example client FileResponseGet -cargo run --example client GetStructuredYaml -cargo run --example client HtmlPost -cargo run --example client PostYaml -cargo run --example client RawJsonGet +cargo run --example rust-server-test-client AllOfGet +cargo run --example rust-server-test-client DummyGet +cargo run --example rust-server-test-client FileResponseGet +cargo run --example rust-server-test-client GetStructuredYaml +cargo run --example rust-server-test-client HtmlPost +cargo run --example rust-server-test-client PostYaml +cargo run --example rust-server-test-client RawJsonGet ``` ### HTTPS The examples can be run in HTTPS mode by passing in the flag `--https`, for example: ``` -cargo run --example server -- --https +cargo run --example rust-server-test-server -- --https ``` This will use the keys/certificates from the examples directory. Note that the @@ -90,8 +115,36 @@ The generated library has a few optional features that can be activated through * `client` * This defaults to enabled and creates the basic skeleton of a client implementation based on hyper * The constructed client implements the API trait by making remote API call. +* `client-tls` + * This default to enabled and provides HTTPS support with automatic TLS backend selection: + - macOS/Windows/iOS: native-tls + hyper-tls + - Linux/Unix/others: OpenSSL + hyper-openssl * `conversions` * This defaults to disabled and creates extra derives on models to allow "transmogrification" between objects of structurally similar types. +* `cli` + * This defaults to disabled and is required for building the included CLI tool. +* `validate` + * This defaults to disabled and allows JSON Schema validation of received data using `MakeService::set_validation` or `Service::set_validation`. + * Note, enabling validation will have a performance penalty, especially if the API heavily uses regex based checks. + +### HTTPS/TLS Support + +HTTPS support is included by default. To disable it (for example, to reduce dependencies), you can: + +```toml +[dependencies] +rust-server-test = { version = "2.3.4", default-features = false, features = ["client", "server"] } +``` + +**For server with callbacks that need HTTPS:** +```toml +[dependencies] +rust-server-test = { version = "2.3.4", features = ["server", "client-tls"] } +``` + +The TLS backend is automatically selected based on your target platform: +- **macOS, Windows, iOS**: Uses `native-tls` (system TLS libraries) +- **Linux, Unix, other platforms**: Uses `openssl` See https://doc.rust-lang.org/cargo/reference/manifest.html#the-features-section for how to use features in your `Cargo.toml`. diff --git a/samples/server/petstore/rust-server/output/rust-server-test/api/openapi.yaml b/samples/server/petstore/rust-server/output/rust-server-test/api/openapi.yaml index fcec6c8fa8b9..163a5632db4c 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/api/openapi.yaml +++ b/samples/server/petstore/rust-server/output/rust-server-test/api/openapi.yaml @@ -20,7 +20,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/dummyPut_request' + $ref: "#/components/schemas/dummyPut_request" required: true responses: "200": @@ -108,7 +108,7 @@ paths: content: application/yaml: schema: - $ref: '#/components/schemas/get_yaml_response' + $ref: "#/components/schemas/get_yaml_response" description: OK /allOf: get: @@ -119,7 +119,7 @@ paths: content: '*/*': schema: - $ref: '#/components/schemas/allOfObject' + $ref: "#/components/schemas/allOfObject" description: OK components: requestBodies: @@ -145,12 +145,15 @@ components: type: object allOfObject: allOf: - - $ref: '#/components/schemas/baseAllOf' + - $ref: "#/components/schemas/baseAllOf" + - properties: + sampleProperty: + type: string + type: object + example: null example: sampleProperty: sampleProperty - properties: - sampleProperty: - type: string + sampleBaseProperty: sampleBaseProperty baseAllOf: properties: sampleBaseProperty: @@ -171,7 +174,7 @@ components: description: An object of objects properties: inner: - $ref: '#/components/schemas/ObjectOfObjects_inner' + $ref: "#/components/schemas/ObjectOfObjects_inner" type: object get_yaml_response: description: structured response diff --git a/samples/server/petstore/rust-server/output/rust-server-test/bin/cli.rs b/samples/server/petstore/rust-server/output/rust-server-test/bin/cli.rs new file mode 100644 index 000000000000..b9446c60ed6b --- /dev/null +++ b/samples/server/petstore/rust-server/output/rust-server-test/bin/cli.rs @@ -0,0 +1,320 @@ +//! CLI tool driving the API client +use anyhow::{anyhow, Context, Result}; +use clap::Parser; +use log::{debug, info}; +// models may be unused if all inputs are primitive types +#[allow(unused_imports)] +use rust_server_test::{ + models, ApiNoContext, Client, ContextWrapperExt, + AllOfGetResponse, + DummyGetResponse, + DummyPutResponse, + FileResponseGetResponse, + GetStructuredYamlResponse, + HtmlPostResponse, + PostYamlResponse, + RawJsonGetResponse, + SoloObjectPostResponse, +}; +use simple_logger::SimpleLogger; +use swagger::{AuthData, ContextBuilder, EmptyContext, Push, XSpanIdString}; + +type ClientContext = swagger::make_context_ty!( + ContextBuilder, + EmptyContext, + Option, + XSpanIdString +); + +#[derive(Parser, Debug)] +#[clap( + name = "rust-server-test", + version = "2.3.4", + about = "CLI access to rust-server-test" +)] +struct Cli { + #[clap(subcommand)] + operation: Operation, + + /// Address or hostname of the server hosting this API, including optional port + #[clap(short = 'a', long, default_value = "http://localhost")] + server_address: String, + + /// Path to the client private key if using client-side TLS authentication + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_certificate", "server_certificate"]))] + client_key: Option, + + /// Path to the client's public certificate associated with the private key + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long, requires_all(&["client_key", "server_certificate"]))] + client_certificate: Option, + + /// Path to CA certificate used to authenticate the server + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] + #[clap(long)] + server_certificate: Option, + + /// If set, write output to file instead of stdout + #[clap(short, long)] + output_file: Option, + + #[command(flatten)] + verbosity: clap_verbosity_flag::Verbosity, +} + +#[derive(Parser, Debug)] +enum Operation { + AllOfGet { + }, + /// A dummy endpoint to make the spec valid. + DummyGet { + }, + DummyPut { + #[clap(value_parser = parse_json::)] + nested_response: models::DummyPutRequest, + }, + /// Get a file + FileResponseGet { + }, + GetStructuredYaml { + }, + /// Test HTML handling + HtmlPost { + body: String, + }, + PostYaml { + /// The YAML body to test + value: String, + }, + /// Get an arbitrary JSON blob. + RawJsonGet { + }, + /// Send an arbitrary JSON blob + SoloObjectPost { + value: serde_json::Value, + }, +} + +// On Linux/Unix with OpenSSL (client-tls feature), support certificate pinning and mutual TLS +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + if args.client_certificate.is_some() { + debug!("Using mutual TLS"); + let client = Client::try_new_https_mutual( + &args.server_address, + args.server_certificate.clone().unwrap(), + args.client_key.clone().unwrap(), + args.client_certificate.clone().unwrap(), + ) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else if args.server_certificate.is_some() { + debug!("Using TLS with pinned server certificate"); + let client = + Client::try_new_https_pinned(&args.server_address, args.server_certificate.clone().unwrap()) + .context("Failed to create HTTPS client")?; + Ok(Box::new(client.with_context(context))) + } else { + debug!("Using client without certificates"); + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) + } +} + +// On macOS/Windows/iOS or without client-tls feature, use simple client (no cert pinning/mutual TLS) +#[cfg(any( + not(feature = "client-tls"), + all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")) +))] +fn create_client(args: &Cli, context: ClientContext) -> Result>> { + // Client::try_new() automatically detects the URL scheme (http:// or https://) + // and creates the appropriate client. + // Note: Certificate pinning and mutual TLS are only available on Linux/Unix with OpenSSL + let client = + Client::try_new(&args.server_address).context("Failed to create HTTP(S) client")?; + Ok(Box::new(client.with_context(context))) +} + +#[tokio::main] +async fn main() -> Result<()> { + let args = Cli::parse(); + if let Some(log_level) = args.verbosity.log_level() { + SimpleLogger::new().with_level(log_level.to_level_filter()).init()?; + } + + debug!("Arguments: {:?}", &args); + + let auth_data: Option = None; + + #[allow(trivial_casts)] + let context = swagger::make_context!( + ContextBuilder, + EmptyContext, + auth_data, + XSpanIdString::default() + ); + + let client = create_client(&args, context)?; + + let result = match args.operation { + Operation::AllOfGet { + } => { + info!("Performing a AllOfGet request"); + + let result = client.all_of_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + AllOfGetResponse::OK + (body) + => "OK\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::DummyGet { + } => { + info!("Performing a DummyGet request"); + + let result = client.dummy_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + DummyGetResponse::Success + => "Success\n".to_string() + , + } + } + Operation::DummyPut { + nested_response, + } => { + info!("Performing a DummyPut request"); + + let result = client.dummy_put( + nested_response, + ).await?; + debug!("Result: {:?}", result); + + match result { + DummyPutResponse::Success + => "Success\n".to_string() + , + } + } + Operation::FileResponseGet { + } => { + info!("Performing a FileResponseGet request"); + + let result = client.file_response_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + FileResponseGetResponse::Success + (body) + => "Success\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::GetStructuredYaml { + } => { + info!("Performing a GetStructuredYaml request"); + + let result = client.get_structured_yaml( + ).await?; + debug!("Result: {:?}", result); + + match result { + GetStructuredYamlResponse::OK + (body) + => "OK\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::HtmlPost { + body, + } => { + info!("Performing a HtmlPost request"); + + let result = client.html_post( + body, + ).await?; + debug!("Result: {:?}", result); + + match result { + HtmlPostResponse::Success + (body) + => "Success\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::PostYaml { + value, + } => { + info!("Performing a PostYaml request"); + + let result = client.post_yaml( + value, + ).await?; + debug!("Result: {:?}", result); + + match result { + PostYamlResponse::OK + => "OK\n".to_string() + , + } + } + Operation::RawJsonGet { + } => { + info!("Performing a RawJsonGet request"); + + let result = client.raw_json_get( + ).await?; + debug!("Result: {:?}", result); + + match result { + RawJsonGetResponse::Success + (body) + => "Success\n".to_string() + + + &serde_json::to_string_pretty(&body)?, + } + } + Operation::SoloObjectPost { + value, + } => { + info!("Performing a SoloObjectPost request"); + + let result = client.solo_object_post( + value, + ).await?; + debug!("Result: {:?}", result); + + match result { + SoloObjectPostResponse::OK + => "OK\n".to_string() + , + } + } + }; + + if let Some(output_file) = args.output_file { + std::fs::write(output_file, result)? + } else { + println!("{}", result); + } + Ok(()) +} + +// May be unused if all inputs are primitive types +#[allow(dead_code)] +fn parse_json(json_string: &str) -> Result { + serde_json::from_str(json_string).map_err(|err| anyhow!("Error parsing input: {}", err)) +} diff --git a/samples/server/petstore/rust-server/output/rust-server-test/docs/ANullableContainer.md b/samples/server/petstore/rust-server/output/rust-server-test/docs/ANullableContainer.md index faa29c8e2382..883546f323e9 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/docs/ANullableContainer.md +++ b/samples/server/petstore/rust-server/output/rust-server-test/docs/ANullableContainer.md @@ -3,8 +3,8 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**nullable_thing** | **String** | | [optional] [default to None] -**required_nullable_thing** | **String** | | +**nullable_thing** | **swagger::Nullable** | | [optional] [default to None] +**required_nullable_thing** | **swagger::Nullable** | | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/samples/server/petstore/rust-server/output/rust-server-test/docs/AllOfObject.md b/samples/server/petstore/rust-server/output/rust-server-test/docs/AllOfObject.md index d9f96cbbc22e..e3b646a70e03 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/docs/AllOfObject.md +++ b/samples/server/petstore/rust-server/output/rust-server-test/docs/AllOfObject.md @@ -3,8 +3,8 @@ ## Properties Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- -**sample_property** | **String** | | [optional] [default to None] **sample_base_property** | **String** | | [optional] [default to None] +**sample_property** | **String** | | [optional] [default to None] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/samples/server/petstore/rust-server/output/rust-server-test/examples/client/main.rs b/samples/server/petstore/rust-server/output/rust-server-test/examples/client/main.rs index d1ae748d59bb..bf307b4ffaba 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/examples/client/main.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/examples/client/main.rs @@ -15,7 +15,7 @@ use rust_server_test::{Api, ApiNoContext, Claims, Client, ContextWrapperExt, mod RawJsonGetResponse, SoloObjectPostResponse, }; -use clap::{App, Arg}; +use clap::{Command, Arg}; // NOTE: Set environment variable RUST_LOG to the name of the executable (or "cargo run") to activate console logging for all loglevels. // See https://docs.rs/env_logger/latest/env_logger/ for more details @@ -38,31 +38,29 @@ use client_auth::build_token; fn main() { env_logger::init(); - let matches = App::new("client") - .arg(Arg::with_name("operation") + let matches = Command::new("client") + .arg(Arg::new("operation") .help("Sets the operation to run") - .possible_values(&[ - "AllOfGet", - "DummyGet", - "FileResponseGet", - "GetStructuredYaml", - "HtmlPost", - "PostYaml", - "RawJsonGet", - ]) + .value_parser(Vec::<&str>::from([ + "AllOfGet", + "DummyGet", + "FileResponseGet", + "GetStructuredYaml", + "HtmlPost", + "PostYaml", + "RawJsonGet", + ])) .required(true) .index(1)) - .arg(Arg::with_name("https") + .arg(Arg::new("https") .long("https") .help("Whether to use HTTPS or not")) - .arg(Arg::with_name("host") + .arg(Arg::new("host") .long("host") - .takes_value(true) .default_value("localhost") .help("Hostname to contact")) - .arg(Arg::with_name("port") + .arg(Arg::new("port") .long("port") - .takes_value(true) .default_value("8080") .help("Port to contact")) .get_matches(); @@ -71,53 +69,68 @@ fn main() { // In a real (production) system this Bearer token should be obtained via an external Identity/Authentication-server // Ensure that you set the correct algorithm and encodingkey that matches what is used on the server side. // See https://github.com/Keats/jsonwebtoken for more information - let auth_token = build_token( Claims { - sub: "tester@acme.com".to_owned(), + sub: "tester@acme.com".to_owned(), company: "ACME".to_owned(), iss: "my_identity_provider".to_owned(), // added a very long expiry time aud: "org.acme.Resource_Server".to_string(), exp: 10000000000, // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ - ].join(", ") - }, + scopes: + "".to_owned() + }, b"secret").unwrap(); let auth_data = if !auth_token.is_empty() { - Some(AuthData::Bearer(swagger::auth::Bearer { token: auth_token})) + Some(AuthData::Bearer(auth_token)) } else { // No Bearer-token available, so return None None }; - let is_https = matches.is_present("https"); + let is_https = matches.contains_id("https"); let base_url = format!("{}://{}:{}", if is_https { "https" } else { "http" }, - matches.value_of("host").unwrap(), - matches.value_of("port").unwrap()); + matches.get_one::("host").unwrap(), + matches.get_one::("port").unwrap()); let context: ClientContext = swagger::make_context!(ContextBuilder, EmptyContext, auth_data, XSpanIdString::default()); - let mut client : Box> = if matches.is_present("https") { - // Using Simple HTTPS - let client = Box::new(Client::try_new_https(&base_url) - .expect("Failed to create HTTPS client")); - Box::new(client.with_context(context)) - } else { - // Using HTTP - let client = Box::new(Client::try_new_http( - &base_url) - .expect("Failed to create HTTP client")); - Box::new(client.with_context(context)) + let mut client : Box> = { + #[cfg(feature = "client-tls")] + { + if is_https { + // Using HTTPS with native-tls + let client = Box::new(Client::try_new_https(&base_url) + .expect("Failed to create HTTPS client")); + Box::new(client.with_context(context)) + } else { + // Using HTTP + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } + } + + #[cfg(not(feature = "client-tls"))] + { + if is_https { + panic!("HTTPS requested but TLS support not enabled. \ + Enable the 'client-tls' feature to use HTTPS."); + } + // Using HTTP only + let client = Box::new(Client::try_new_http(&base_url) + .expect("Failed to create HTTP client")); + Box::new(client.with_context(context)) + } }; let mut rt = tokio::runtime::Runtime::new().unwrap(); - match matches.value_of("operation") { + match matches.get_one::("operation").map(String::as_str) { Some("AllOfGet") => { let result = rt.block_on(client.all_of_get( )); diff --git a/samples/server/petstore/rust-server/output/rust-server-test/examples/server/main.rs b/samples/server/petstore/rust-server/output/rust-server-test/examples/server/main.rs index 7492252060e2..4ebb86603915 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/examples/server/main.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/examples/server/main.rs @@ -3,26 +3,26 @@ #![allow(missing_docs)] - -use clap::{App, Arg}; +use clap::{Arg, Command}; mod server; mod server_auth; - /// Create custom server, wire it to the autogenerated router, /// and pass it to the web server. #[tokio::main] async fn main() { env_logger::init(); - let matches = App::new("server") - .arg(Arg::with_name("https") - .long("https") - .help("Whether to use HTTPS or not")) + let matches = Command::new("server") + .arg( + Arg::new("https") + .long("https") + .help("Whether to use HTTPS or not"), + ) .get_matches(); let addr = "127.0.0.1:8080"; - server::create(addr, matches.is_present("https")).await; + server::create(addr, matches.contains_id("https")).await; } diff --git a/samples/server/petstore/rust-server/output/rust-server-test/examples/server/server.rs b/samples/server/petstore/rust-server/output/rust-server-test/examples/server/server.rs index 56fc2f63c4d2..144228beed8e 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/examples/server/server.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/examples/server/server.rs @@ -4,8 +4,9 @@ use async_trait::async_trait; use futures::{future, Stream, StreamExt, TryFutureExt, TryStreamExt}; -use hyper::server::conn::Http; -use hyper::service::Service; +use hyper::server::conn::http1; +use hyper_util::rt::TokioIo; +use hyper::service::{service_fn, Service}; use log::info; use std::future::Future; use std::marker::PhantomData; @@ -24,15 +25,13 @@ use rust_server_test::models; /// Builds an SSL implementation for Simple HTTPS from some hard-coded file names pub async fn create(addr: &str, https: bool) { - let addr = addr.parse().expect("Failed to parse bind address"); + let addr: SocketAddr = addr.parse().expect("Failed to parse bind address"); + let listener = TcpListener::bind(&addr).await.unwrap(); let server = Server::new(); let service = MakeService::new(server); - - // This pushes a fourth layer of the middleware-stack even though Swagger assumes only three levels. - // This fourth layer creates an accept-all policy, hower the example-code already acchieves the same via a Bearer-token with full permissions, so next line is not needed (anymore). - // let service = MakeAllowAllAuthenticator::new(service, "cosmo"); + let service = MakeAllowAllAuthenticator::new(service, "cosmo"); #[allow(unused_mut)] let mut service = @@ -56,21 +55,19 @@ pub async fn create(addr: &str, https: bool) { ssl.check_private_key().expect("Failed to check private key"); let tls_acceptor = ssl.build(); - let tcp_listener = TcpListener::bind(&addr).await.unwrap(); info!("Starting a server (with https)"); loop { - if let Ok((tcp, _)) = tcp_listener.accept().await { + if let Ok((tcp, addr)) = listener.accept().await { let ssl = Ssl::new(tls_acceptor.context()).unwrap(); - let addr = tcp.peer_addr().expect("Unable to get remote address"); let service = service.call(addr); tokio::spawn(async move { let tls = tokio_openssl::SslStream::new(ssl, tcp).map_err(|_| ())?; let service = service.await.map_err(|_| ())?; - Http::new() - .serve_connection(tls, service) + http1::Builder::new() + .serve_connection(TokioIo::new(tls), service) .await .map_err(|_| ()) }); @@ -79,12 +76,40 @@ pub async fn create(addr: &str, https: bool) { } } else { info!("Starting a server (over http, so no TLS)"); - // Using HTTP - hyper::server::Server::bind(&addr).serve(service).await.unwrap() + println!("Listening on http://{}", addr); + + loop { + // When an incoming TCP connection is received grab a TCP stream for + // client<->server communication. + // + // Note, this is a .await point, this loop will loop forever but is not a busy loop. The + // .await point allows the Tokio runtime to pull the task off of the thread until the task + // has work to do. In this case, a connection arrives on the port we are listening on and + // the task is woken up, at which point the task is then put back on a thread, and is + // driven forward by the runtime, eventually yielding a TCP stream. + let (tcp_stream, addr) = listener.accept().await.expect("Failed to accept connection"); + + let service = service.call(addr).await.unwrap(); + let io = TokioIo::new(tcp_stream); + // Spin up a new task in Tokio so we can continue to listen for new TCP connection on the + // current task without waiting for the processing of the HTTP1 connection we just received + // to finish + tokio::task::spawn(async move { + // Handle the connection from the client using HTTP1 and pass any + // HTTP requests received on that connection to the `hello` function + let result = http1::Builder::new() + .serve_connection(io, service) + .await; + if let Err(err) = result + { + println!("Error serving connection: {err:?}"); + } + }); + } } } -#[derive(Copy, Clone)] +#[derive(Copy)] pub struct Server { marker: PhantomData, } @@ -95,6 +120,14 @@ impl Server { } } +impl Clone for Server { + fn clone(&self) -> Self { + Self { + marker: PhantomData, + } + } +} + use jsonwebtoken::{decode, encode, errors::Error as JwtError, Algorithm, DecodingKey, EncodingKey, Header, TokenData, Validation}; use serde::{Deserialize, Serialize}; diff --git a/samples/server/petstore/rust-server/output/rust-server-test/examples/server/server_auth.rs b/samples/server/petstore/rust-server/output/rust-server-test/examples/server/server_auth.rs index 3525e452ac12..91e4570add86 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/examples/server/server_auth.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/examples/server/server_auth.rs @@ -1,8 +1,8 @@ use swagger::{ ApiError, - auth::{Basic, Bearer}, - Has, + Has, XSpanIdString}; +use headers::authorization::{Basic, Bearer}; use rust_server_test::{AuthenticationApi, Claims}; use crate::server::Server; use jsonwebtoken::{decode, errors as JwtError, decode_header, DecodingKey, TokenData, Validation}; @@ -15,24 +15,24 @@ use log::{error, debug}; /// Get a dummy claim with full permissions (all scopes) for testing purposes fn full_permission_claim() -> Claims { - Claims { - sub: "tester@acme.com".to_owned(), - company: "ACME".to_owned(), - iss: "mini-bank-IDP".to_owned(), - aud: "org.acme.Resource_Server".to_string(), - // added a very long expiry time - exp: 10000000000, - // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. - scopes: [ - ].join(", ") - } + // In this example code all available Scopes are added, so the current Bearer Token gets fully authorization. + Claims { + sub: "tester@acme.com".to_owned(), + company: "ACME".to_owned(), + iss: "mini-bank-IDP".to_owned(), + aud: "org.acme.Resource_Server".to_string(), + // added a very long expiry time + exp: 10000000000, + scopes: + "".to_owned() + } } -/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. +/// Extract the data from a Bearer token using the provided Key (secret) and using the HS512-algorithm in this example. fn extract_token_data(token: &str, key: &[u8]) -> Result, JwtError::Error> { - + // Ensure that you set the correct algorithm and correct key. // See https://github.com/Keats/jsonwebtoken for more information. let header = decode_header(token)?; @@ -63,8 +63,8 @@ fn build_authorization(claims: Claims) -> Authorization { let scopes = swagger::auth::Scopes::Some(scopes); Authorization{ - subject: claims.sub, - scopes, + subject: claims.sub, + scopes, issuer: Some(claims.iss)} } @@ -87,7 +87,7 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn bearer_authorization(&self, bearer: &Bearer) -> Result { debug!("\tAuthorizationApi: Received Bearer-token, {bearer:#?}"); - match extract_token_data(&bearer.token, b"secret") { + match extract_token_data(&bearer.token(), b"secret") { Ok(auth_data) => { debug!("\tUnpack auth_data as: {auth_data:#?}"); let authorization = build_authorization(auth_data.claims); @@ -105,23 +105,22 @@ impl AuthenticationApi for Server where C: Has + Send + Syn fn apikey_authorization(&self, api_key: &str) -> Result { debug!("\tAuthorizationApi: Received api-key, {api_key:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } - + /// Implementation of the method to map a basic authentication (username and password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result { debug!("\tAuthorizationApi: Received Basic-token, {basic:#?}"); - // TODO: insert the logic to map received apikey to the set of claims + // TODO: insert the logic to map received apikey to the set of claims let claims = full_permission_claim(); // and build an authorization out of it Ok(build_authorization(claims)) } -} - +} diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/auth.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/auth.rs index cbaba3dca7c6..a6a39f79450f 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/auth.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/auth.rs @@ -1,8 +1,7 @@ use std::collections::BTreeSet; -use crate::server::Authorization; use serde::{Deserialize, Serialize}; -use swagger::{ApiError, auth::{Basic, Bearer}}; - +use swagger::{ApiError, auth::Authorization}; +use headers::authorization::{Basic, Bearer}; #[derive(Debug, Serialize, Deserialize)] pub struct Claims { pub sub: String, @@ -24,7 +23,7 @@ pub trait AuthenticationApi { /// Method should be implemented (see example-code) to map Basic (Username:password) to an Authorization fn basic_authorization(&self, basic: &Basic) -> Result; -} +} // Implement it for AllowAllAuthenticator (dummy is needed, but should not used as we have Bearer authorization) use swagger::auth::{AllowAllAuthenticator, RcBound, Scopes}; @@ -34,7 +33,7 @@ fn dummy_authorization() -> Authorization { // However, if you want to use it anyway this can not be unimplemented, so dummy implementation added. // unimplemented!() Authorization{ - subject: "Dummmy".to_owned(), + subject: "Dummy".to_owned(), scopes: Scopes::Some(BTreeSet::new()), // create an empty scope, as this should not be used issuer: None } diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/client/mod.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/client/mod.rs index dcda90cd4a9d..98b1550118b0 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/client/mod.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/client/mod.rs @@ -1,10 +1,12 @@ use async_trait::async_trait; +use bytes::Bytes; use futures::{Stream, future, future::BoxFuture, stream, future::TryFutureExt, future::FutureExt, stream::StreamExt}; +use http_body_util::{combinators::BoxBody, Full}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; -use hyper::{Body, Request, Response, service::Service, Uri}; +use hyper::{body::{Body, Incoming}, Request, Response, service::Service, Uri}; use percent_encoding::{utf8_percent_encode, AsciiSet}; use std::borrow::Cow; -use std::convert::TryInto; +use std::convert::{TryInto, Infallible}; use std::io::{ErrorKind, Read}; use std::error::Error; use std::future::Future; @@ -18,6 +20,7 @@ use std::string::ToString; use std::task::{Context, Poll}; use swagger::{ApiError, AuthData, BodyExt, Connector, DropContextService, Has, XSpanIdString}; use url::form_urlencoded; +use tower_service::Service as _; use crate::models; @@ -62,15 +65,14 @@ fn into_base_path(input: impl TryInto, } let host = uri.host().ok_or(ClientInitError::MissingHost)?; - let port = uri.port_u16().map(|x| format!(":{}", x)).unwrap_or_default(); - Ok(format!("{}://{}{}{}", scheme, host, port, uri.path().trim_end_matches('/'))) + let port = uri.port_u16().map(|x| format!(":{x}")).unwrap_or_default(); + Ok(format!("{scheme}://{host}{port}{}", uri.path().trim_end_matches('/'))) } /// A client that implements the API by making HTTP calls out to a server. pub struct Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -87,8 +89,7 @@ pub struct Client where impl fmt::Debug for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -100,8 +101,7 @@ impl fmt::Debug for Client where impl Clone for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -115,8 +115,19 @@ impl Clone for Client where } } -impl Client, C>, C> where - Connector: hyper::client::connect::Connect + Clone + Send + Sync + 'static, +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + Connector, + BoxBody + > + >, + C + >, + C +> where + Connector: hyper_util::client::legacy::connect::Connect + Clone + Send + Sync + 'static, C: Clone + Send + Sync + 'static, { /// Create a client with a custom implementation of hyper::client::Connect. @@ -130,7 +141,7 @@ impl Client" /// * `protocol` - Which protocol to use when constructing the request url, e.g. `Some("http")` /// * `connector` - Implementation of `hyper::client::Connect` to use for the client pub fn try_new_with_connector( @@ -139,8 +150,8 @@ impl Client Result { - let client_service = hyper::client::Client::builder().build(connector); - let client_service = DropContextService::new(client_service); + let client_service = hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector); + let client_service = DropContextService::new(hyper_util::service::TowerToHyperService::new(client_service)); Ok(Self { client_service, @@ -150,28 +161,29 @@ impl Client; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HyperHttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + #[derive(Debug, Clone)] pub enum HyperClient { - Http(hyper::client::Client), - Https(hyper::client::Client), + Http(hyper_util::client::legacy::Client>), + #[cfg(feature = "client-tls")] + Https(hyper_util::client::legacy::Client>), } -impl Service> for HyperClient { - type Response = Response; - type Error = hyper::Error; - type Future = hyper::client::ResponseFuture; - - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - match self { - HyperClient::Http(client) => client.poll_ready(cx), - HyperClient::Https(client) => client.poll_ready(cx), - } - } +impl Service>> for HyperClient { + type Response = Response; + type Error = hyper_util::client::legacy::Error; + type Future = hyper_util::client::legacy::ResponseFuture; - fn call(&mut self, req: Request) -> Self::Future { + fn call(&self, req: Request>) -> Self::Future { match self { - HyperClient::Http(client) => client.call(req), - HyperClient::Https(client) => client.call(req) + HyperClient::Http(client) => client.request(req), + #[cfg(feature = "client-tls")] + HyperClient::Https(client) => client.request(req), } } } @@ -182,7 +194,7 @@ impl Client, C> where /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new( base_path: &str, ) -> Result { @@ -195,13 +207,19 @@ impl Client, C> where let client_service = match scheme.as_str() { "http" => { - HyperClient::Http(hyper::client::Client::builder().build(connector.build())) + HyperClient::Http(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(connector.build())) }, + #[cfg(feature = "client-tls")] "https" => { - let connector = connector.https() - .build() - .map_err(ClientInitError::SslError)?; - HyperClient::Https(hyper::client::Client::builder().build(connector)) + let https_connector = connector + .https() + .build() + .map_err(ClientInitError::SslError)?; + HyperClient::Https(hyper_util::client::legacy::Client::builder(hyper_util::rt::TokioExecutor::new()).build(https_connector)) + }, + #[cfg(not(feature = "client-tls"))] + "https" => { + return Err(ClientInitError::TlsNotEnabled); }, _ => { return Err(ClientInitError::InvalidScheme); @@ -218,13 +236,24 @@ impl Client, C> where } } -impl Client, C>, C> where +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + hyper_util::client::legacy::connect::HttpConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { /// Create an HTTP client. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "http://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" pub fn try_new_http( base_path: &str, ) -> Result { @@ -234,19 +263,46 @@ impl Client; - -#[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] -type HttpsConnector = hyper_openssl::HttpsConnector; - -impl Client, C>, C> where +#[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] +type HttpsConnector = hyper_tls::HttpsConnector; + +#[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] +type HttpsConnector = hyper_openssl::client::legacy::HttpsConnector; + +#[cfg(feature = "client-tls")] +impl Client< + DropContextService< + hyper_util::service::TowerToHyperService< + hyper_util::client::legacy::Client< + HttpsConnector, + BoxBody + > + >, + C + >, + C +> where C: Clone + Send + Sync + 'static { - /// Create a client with a TLS connection to the server + /// Create a client with a TLS connection to the server. + /// + /// # Arguments + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + pub fn try_new_https(base_path: &str) -> Result + { + let https_connector = Connector::builder() + .https() + .build() + .map_err(ClientInitError::SslError)?; + Self::try_new_with_connector(base_path, Some("https"), https_connector) + } + + /// Create a client with a TLS connection to the server using OpenSSL via swagger. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" + #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn try_new_https(base_path: &str) -> Result { let https_connector = Connector::builder() @@ -256,10 +312,10 @@ impl Client, C Self::try_new_with_connector(base_path, Some("https"), https_connector) } - /// Create a client with a TLS connection to the server using a pinned certificate + /// Create a client with a TLS connection to the server using a pinned certificate. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] pub fn try_new_https_pinned( @@ -280,7 +336,7 @@ impl Client, C /// Create a client with a mutually authenticated TLS connection to the server. /// /// # Arguments - /// * `base_path` - base path of the client API, i.e. "https://www.my-api-implementation.com" + /// * `base_path` - base path of the client API, i.e. "" /// * `ca_certificate` - Path to CA certificate used to authenticate the server /// * `client_key` - Path to the client private key /// * `client_certificate` - Path to the client's public certificate associated with the private key @@ -308,8 +364,7 @@ impl Client, C impl Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C)> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Clone + Send + Sync + 'static @@ -343,12 +398,15 @@ pub enum ClientInitError { /// Missing Hostname MissingHost, + /// HTTPS requested but TLS features not enabled + TlsNotEnabled, + /// SSL Connection Error - #[cfg(any(target_os = "macos", target_os = "windows", target_os = "ios"))] + #[cfg(all(feature = "client-tls", any(target_os = "macos", target_os = "windows", target_os = "ios")))] SslError(native_tls::Error), /// SSL Connection Error - #[cfg(not(any(target_os = "macos", target_os = "windows", target_os = "ios")))] + #[cfg(all(feature = "client-tls", not(any(target_os = "macos", target_os = "windows", target_os = "ios"))))] SslError(openssl::error::ErrorStack), } @@ -371,28 +429,31 @@ impl Error for ClientInitError { } } +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + #[async_trait] -impl Api for Client where +impl Api for Client where S: Service< - (Request, C), - Response=Response> + Clone + Sync + Send + 'static, + (Request>, C), + Response=Response> + Clone + Sync + Send + 'static, S::Future: Send + 'static, S::Error: Into + fmt::Display, C: Has + Clone + Send + Sync + 'static, + B: hyper::body::Body + Send + 'static + Unpin, + B::Data: Send, + B::Error: Into>, { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - match self.client_service.clone().poll_ready(cx) { - Poll::Ready(Err(e)) => Poll::Ready(Err(e.into())), - Poll::Ready(Ok(o)) => Poll::Ready(Ok(o)), - Poll::Pending => Poll::Pending, - } - } + #[allow(clippy::vec_init_then_push)] async fn all_of_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/allOf", self.base_path @@ -410,66 +471,69 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(AllOfGetResponse::OK (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn dummy_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/dummy", self.base_path @@ -487,25 +551,25 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -515,30 +579,30 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn dummy_put( &self, param_nested_response: models::DummyPutRequest, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/dummy", self.base_path @@ -556,33 +620,33 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("PUT") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body + // Body parameter let body = serde_json::to_string(¶m_nested_response).expect("impossible to fail to serialize"); - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { @@ -592,29 +656,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn file_response_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/file_response", self.base_path @@ -632,66 +696,69 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(FileResponseGetResponse::Success (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn get_structured_yaml( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/get-structured-yaml", self.base_path @@ -709,65 +776,69 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; let body = body.to_string(); + + Ok(GetStructuredYamlResponse::OK (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn html_post( &self, param_body: String, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/html", self.base_path @@ -785,73 +856,77 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body + // Body parameter let body = param_body; - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "text/html"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; let body = body.to_string(); + + Ok(HtmlPostResponse::Success (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn post_yaml( &self, param_value: String, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/post-yaml", self.base_path @@ -869,33 +944,33 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body + // Body parameter let body = param_value; - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/yaml"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); + let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 204 => { @@ -905,29 +980,29 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn raw_json_get( &self, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/raw_json", self.base_path @@ -945,67 +1020,70 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("GET") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 200 => { let body = response.into_body(); - let body = body - .into_raw() - .map_err(|e| ApiError(format!("Failed to read response: {}", e))).await?; + let body = http_body_util::BodyExt::collect(body) + .await + .map(|f| f.to_bytes().to_vec()) + .map_err(|e| ApiError(format!("Failed to read response: {}", e.into())))?; + let body = str::from_utf8(&body) - .map_err(|e| ApiError(format!("Response was not valid UTF8: {}", e)))?; - let body = serde_json::from_str::(body).map_err(|e| { - ApiError(format!("Response body did not match the schema: {}", e)) - })?; + .map_err(|e| ApiError(format!("Response was not valid UTF8: {e}")))?; + let body = serde_json::from_str::(body) + .map_err(|e| ApiError(format!("Response body did not match the schema: {e}")))?; + + Ok(RawJsonGetResponse::Success (body) ) } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } } } + #[allow(clippy::vec_init_then_push)] async fn solo_object_post( &self, param_value: serde_json::Value, context: &C) -> Result { let mut client_service = self.client_service.clone(); + #[allow(clippy::uninlined_format_args)] let mut uri = format!( "{}/solo-object", self.base_path @@ -1023,35 +1101,33 @@ impl Api for Client where let uri = match Uri::from_str(&uri) { Ok(uri) => uri, - Err(err) => return Err(ApiError(format!("Unable to build URI: {}", err))), + Err(err) => return Err(ApiError(format!("Unable to build URI: {err}"))), }; let mut request = match Request::builder() .method("POST") .uri(uri) - .body(Body::empty()) { + .body(BoxBody::new(http_body_util::Empty::new())) { Ok(req) => req, - Err(e) => return Err(ApiError(format!("Unable to create request: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create request: {e}"))) }; + // Consumes basic body + // Body parameter let body = serde_json::to_string(¶m_value).expect("impossible to fail to serialize"); - - *request.body_mut() = Body::from(body); + *request.body_mut() = body_from_string(body); let header = "application/json"; - request.headers_mut().insert(CONTENT_TYPE, match HeaderValue::from_str(header) { - Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create header: {} - {}", header, e))) - }); + request.headers_mut().insert(CONTENT_TYPE, HeaderValue::from_static(header)); let header = HeaderValue::from_str(Has::::get(context).0.as_str()); request.headers_mut().insert(HeaderName::from_static("x-span-id"), match header { Ok(h) => h, - Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {}", e))) + Err(e) => return Err(ApiError(format!("Unable to create X-Span ID header value: {e}"))) }); let response = client_service.call((request, context.clone())) - .map_err(|e| ApiError(format!("No response received: {}", e))).await?; + .map_err(|e| ApiError(format!("No response received: {e}"))).await?; match response.status().as_u16() { 204 => { @@ -1061,18 +1137,16 @@ impl Api for Client where } code => { let headers = response.headers().clone(); - let body = response.into_body() - .take(100) - .into_raw().await; - Err(ApiError(format!("Unexpected response code {}:\n{:?}\n\n{}", - code, - headers, + let body = http_body_util::BodyExt::collect(response.into_body()) + .await + .map(|f| f.to_bytes().to_vec()); + Err(ApiError(format!("Unexpected response code {code}:\n{headers:?}\n\n{}", match body { Ok(body) => match String::from_utf8(body) { Ok(body) => body, - Err(e) => format!("", e), + Err(e) => format!(""), }, - Err(e) => format!("", e), + Err(e) => format!("", Into::::into(e)), } ))) } diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/context.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/context.rs index ee8e118587bb..45180a543112 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/context.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/context.rs @@ -6,9 +6,9 @@ use std::default::Default; use std::io; use std::marker::PhantomData; use std::task::{Poll, Context}; -use swagger::auth::{AuthData, Authorization, Bearer, Scopes}; +use swagger::auth::{AuthData, Authorization, Scopes}; use swagger::{EmptyContext, Has, Pop, Push, XSpanIdString}; -use crate::{Api, AuthenticationApi}; +use crate::Api; use log::error; pub struct MakeAddContext { @@ -16,11 +16,11 @@ pub struct MakeAddContext { marker: PhantomData, } -impl MakeAddContext +impl MakeAddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, + C: Send + 'static, { pub fn new(inner: T) -> MakeAddContext { MakeAddContext { @@ -30,27 +30,34 @@ where } } +impl Clone for MakeAddContext +where + T: Clone, +{ + fn clone(&self) -> Self { + Self { + inner: self.inner.clone(), + marker: PhantomData, + } + } +} + // Make a service that adds context. -impl Service for +impl Service for MakeAddContext where Target: Send, A: Default + Push + Send, B: Push, Result = C>, - C: Push, Result = D>, - D: Send + 'static, + C: Send + 'static, T: Service + Send, T::Future: Send + 'static { type Error = T::Error; - type Response = AddContext; + type Response = AddContext; type Future = BoxFuture<'static, Result>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - fn call(&mut self, target: Target) -> Self::Future { + fn call(&self, target: Target) -> Self::Future { let service = self.inner.call(target); Box::pin(async move { @@ -60,21 +67,17 @@ where } /// Middleware to add context data from the request -pub struct AddContext -where - A: Default + Push, - B: Push, Result = C>, - C: Push, Result = D> +#[derive(Debug, Clone)] +pub struct AddContext { inner: T, marker: PhantomData, } -impl AddContext +impl AddContext where A: Default + Push, B: Push, Result = C>, - C: Push, Result = D>, { pub fn new(inner: T) -> Self { AddContext { @@ -84,30 +87,23 @@ where } } -impl Service> for AddContext +impl Service> for AddContext where A: Default + Push, B: Push, Result=C>, - C: Push, Result=D>, - D: Send + 'static, - T: Service<(Request, D)> + AuthenticationApi + C: Send + 'static, + T: Service<(Request, C)> { type Error = T::Error; type Future = T::Future; type Response = T::Response; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - self.inner.poll_ready(cx) - } - - - fn call(&mut self, request: Request) -> Self::Future { + fn call(&self, request: Request) -> Self::Future { let context = A::default().push(XSpanIdString::get_or_generate(&request)); let headers = request.headers(); let context = context.push(None::); - let context = context.push(None::); self.inner.call((request, context)) } diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/header.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/header.rs index 5bc6ebe929b9..823d2779b31f 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/header.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/header.rs @@ -31,11 +31,9 @@ macro_rules! ihv_generate { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse::<$t>() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse {} as a string: {}", - stringify!($t), e)), + Err(e) => Err(format!("Unable to parse {} as a string: {e}", stringify!($t))), }, - Err(e) => Err(format!("Unable to parse header {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header {hdr_value:?} as a string - {e}")), } } } @@ -76,8 +74,7 @@ impl TryFrom for IntoHeaderValue> { y => Some(y.to_string()), }) .collect())), - Err(e) => Err(format!("Unable to parse header: {:?} as a string - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse header: {hdr_value:?} as a string - {e}")), } } } @@ -88,8 +85,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(&hdr_value.0.join(", ")) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} into a header - {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} into a header - {e}")) } } } @@ -102,8 +98,7 @@ impl TryFrom for IntoHeaderValue { fn try_from(hdr_value: HeaderValue) -> Result { match hdr_value.to_str() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value.to_string())), - Err(e) => Err(format!("Unable to convert header {:?} to {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to {e}")), } } } @@ -114,8 +109,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")) } } } @@ -128,11 +122,9 @@ impl TryFrom for IntoHeaderValue { match hdr_value.to_str() { Ok(hdr_value) => match hdr_value.parse() { Ok(hdr_value) => Ok(IntoHeaderValue(hdr_value)), - Err(e) => Err(format!("Unable to parse bool from {} - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse bool from {hdr_value} - {e}")), }, - Err(e) => Err(format!("Unable to convert {:?} from a header {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} from a header {e}")), } } } @@ -143,8 +135,7 @@ impl TryFrom> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue) -> Result { match HeaderValue::from_str(&hdr_value.0.to_string()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert: {:?} into a header: {}", - hdr_value, e)) + Err(e) => Err(format!("Unable to convert: {hdr_value:?} into a header: {e}")) } } } @@ -158,11 +149,9 @@ impl TryFrom for IntoHeaderValue> { match hdr_value.to_str() { Ok(hdr_value) => match DateTime::parse_from_rfc3339(hdr_value) { Ok(date) => Ok(IntoHeaderValue(date.with_timezone(&Utc))), - Err(e) => Err(format!("Unable to parse: {} as date - {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to parse: {hdr_value} as date - {e}")), }, - Err(e) => Err(format!("Unable to convert header {:?} to string {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert header {hdr_value:?} to string {e}")), } } } @@ -173,8 +162,7 @@ impl TryFrom>> for HeaderValue { fn try_from(hdr_value: IntoHeaderValue>) -> Result { match HeaderValue::from_str(hdr_value.0.to_rfc3339().as_str()) { Ok(hdr_value) => Ok(hdr_value), - Err(e) => Err(format!("Unable to convert {:?} to a header: {}", - hdr_value, e)), + Err(e) => Err(format!("Unable to convert {hdr_value:?} to a header: {e}")), } } } diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/lib.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/lib.rs index 3adabd148d80..5b9072a59bd1 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/lib.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/lib.rs @@ -3,14 +3,15 @@ use async_trait::async_trait; use futures::Stream; +#[cfg(feature = "mock")] +use mockall::automock; use std::error::Error; use std::collections::BTreeSet; use std::task::{Poll, Context}; -use swagger::{ApiError, ContextWrapper}; +use swagger::{ApiError, ContextWrapper, auth::Authorization}; use serde::{Serialize, Deserialize}; -use crate::server::Authorization; - +#[cfg(any(feature = "client", feature = "server"))] type ServiceError = Box; pub const BASE_PATH: &str = ""; @@ -80,13 +81,10 @@ pub enum SoloObjectPostResponse { } /// API +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait Api { - fn poll_ready(&self, _cx: &mut Context) -> Poll>> { - Poll::Ready(Ok(())) - } - async fn all_of_get( &self, context: &C) -> Result; @@ -135,11 +133,14 @@ pub trait Api { } /// API where `Context` isn't passed on every API call +#[cfg_attr(feature = "mock", automock)] #[async_trait] #[allow(clippy::too_many_arguments, clippy::ptr_arg)] pub trait ApiNoContext { - - fn poll_ready(&self, _cx: &mut Context) -> Poll>>; + // The std::task::Context struct houses a reference to std::task::Waker with the lifetime <'a>. + // Adding an anonymous lifetime `'a` to allow mockall to create a mock object with the right lifetimes. + // This is needed because the compiler is unable to determine the lifetimes on F's trait bound + // where F is the closure created by mockall. We use higher-rank trait bounds here to get around this. fn context(&self) -> &C; @@ -205,10 +206,6 @@ impl + Send + Sync, C: Clone + Send + Sync> ContextWrapperExt for T #[async_trait] impl + Send + Sync, C: Clone + Send + Sync> ApiNoContext for ContextWrapper { - fn poll_ready(&self, cx: &mut Context) -> Poll> { - self.api().poll_ready(cx) - } - fn context(&self) -> &C { ContextWrapper::context(self) } diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/models.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/models.rs index 0915bf515e28..f6d6e0deee48 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/models.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/models.rs @@ -1,25 +1,49 @@ #![allow(unused_qualifications)] - +#[cfg(not(feature = "validate"))] use validator::Validate; use crate::models; #[cfg(any(feature = "client", feature = "server"))] use crate::header; +#[cfg(feature = "validate")] +use serde_valid::Validate; -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct ANullableContainer { #[serde(rename = "NullableThing")] #[serde(deserialize_with = "swagger::nullable_format::deserialize_optional_nullable")] #[serde(default = "swagger::nullable_format::default_optional_nullable")] + #[serde(skip_serializing_if="Option::is_none")] pub nullable_thing: Option>, #[serde(rename = "RequiredNullableThing")] + pub required_nullable_thing: swagger::Nullable, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for ANullableContainer { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for ANullableContainer { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl ANullableContainer { #[allow(clippy::new_without_default)] @@ -32,31 +56,27 @@ impl ANullableContainer { } /// Converts the ANullableContainer value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for ANullableContainer { - fn to_string(&self) -> String { +impl std::fmt::Display for ANullableContainer { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.nullable_thing.as_ref().map(|nullable_thing| { [ "NullableThing".to_string(), nullable_thing.as_ref().map_or("null".to_string(), |x| x.to_string()), ].join(",") }), - - Some("RequiredNullableThing".to_string()), Some(self.required_nullable_thing.as_ref().map_or("null".to_string(), |x| x.to_string())), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a ANullableContainer value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for ANullableContainer { type Err = String; @@ -66,8 +86,8 @@ impl std::str::FromStr for ANullableContainer { #[derive(Default)] #[allow(dead_code)] struct IntermediateRep { - pub nullable_thing: Vec, - pub required_nullable_thing: Vec, + pub nullable_thing: Vec>, + pub required_nullable_thing: Vec>, } let mut intermediate_rep = IntermediateRep::default(); @@ -114,8 +134,7 @@ impl std::convert::TryFrom> for hype match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for ANullableContainer - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for ANullableContainer - value: {hdr_value} is invalid {e}")) } } } @@ -130,22 +149,65 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into ANullableContainer - {}", - value, err)) + format!("Unable to convert header value '{value}' into ANullableContainer - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ANullableContainer - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} /// An additionalPropertiesObject #[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +#[cfg_attr(feature = "validate", derive(Validate))] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] -pub struct AdditionalPropertiesObject(std::collections::HashMap); +pub struct AdditionalPropertiesObject( + std::collections::HashMap +); impl std::convert::From> for AdditionalPropertiesObject { fn from(x: std::collections::HashMap) -> Self { @@ -172,38 +234,157 @@ impl std::ops::DerefMut for AdditionalPropertiesObject { } } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for AdditionalPropertiesObject { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for AdditionalPropertiesObject { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} /// Converts the AdditionalPropertiesObject value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl ::std::string::ToString for AdditionalPropertiesObject { - fn to_string(&self) -> String { - // Skipping additionalProperties in query parameter serialization - "".to_string() +impl std::fmt::Display for AdditionalPropertiesObject { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Display for this model is not supported + write!(f, "") } } /// Converts Query Parameters representation (style=form, explode=false) to a AdditionalPropertiesObject value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl ::std::str::FromStr for AdditionalPropertiesObject { type Err = &'static str; fn from_str(s: &str) -> std::result::Result { - std::result::Result::Err("Parsing additionalProperties for AdditionalPropertiesObject is not supported") + std::result::Result::Err("Parsing AdditionalPropertiesObject is not supported") + } +} + +// Methods for converting between header::IntoHeaderValue and hyper::header::HeaderValue + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_value: header::IntoHeaderValue) -> std::result::Result { + let hdr_value = hdr_value.to_string(); + match hyper::header::HeaderValue::from_str(&hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(e) => std::result::Result::Err( + format!("Invalid header value for AdditionalPropertiesObject - value: {hdr_value} is invalid {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue { + type Error = String; + + fn try_from(hdr_value: hyper::header::HeaderValue) -> std::result::Result { + match hdr_value.to_str() { + std::result::Result::Ok(value) => { + match ::from_str(value) { + std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{value}' into AdditionalPropertiesObject - {err}")) + } + }, + std::result::Result::Err(e) => std::result::Result::Err( + format!("Unable to convert header: {hdr_value:?} to string: {e}")) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into AdditionalPropertiesObject - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } } } -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct AllOfObject { + #[serde(rename = "sampleBaseProperty")] + + #[serde(skip_serializing_if="Option::is_none")] + pub sample_base_property: Option, + #[serde(rename = "sampleProperty")] + #[serde(skip_serializing_if="Option::is_none")] pub sample_property: Option, - #[serde(rename = "sampleBaseProperty")] - #[serde(skip_serializing_if="Option::is_none")] - pub sample_base_property: Option, +} +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for AllOfObject { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for AllOfObject { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } } @@ -211,42 +392,38 @@ impl AllOfObject { #[allow(clippy::new_without_default)] pub fn new() -> AllOfObject { AllOfObject { - sample_property: None, sample_base_property: None, + sample_property: None, } } } /// Converts the AllOfObject value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for AllOfObject { - fn to_string(&self) -> String { +impl std::fmt::Display for AllOfObject { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - - self.sample_property.as_ref().map(|sample_property| { - [ - "sampleProperty".to_string(), - sample_property.to_string(), - ].join(",") - }), - - self.sample_base_property.as_ref().map(|sample_base_property| { [ "sampleBaseProperty".to_string(), sample_base_property.to_string(), ].join(",") }), - + self.sample_property.as_ref().map(|sample_property| { + [ + "sampleProperty".to_string(), + sample_property.to_string(), + ].join(",") + }), ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a AllOfObject value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for AllOfObject { type Err = String; @@ -256,8 +433,8 @@ impl std::str::FromStr for AllOfObject { #[derive(Default)] #[allow(dead_code)] struct IntermediateRep { - pub sample_property: Vec, pub sample_base_property: Vec, + pub sample_property: Vec, } let mut intermediate_rep = IntermediateRep::default(); @@ -275,10 +452,10 @@ impl std::str::FromStr for AllOfObject { if let Some(key) = key_result { #[allow(clippy::match_single_binding)] match key { - #[allow(clippy::redundant_clone)] - "sampleProperty" => intermediate_rep.sample_property.push(::from_str(val).map_err(|x| x.to_string())?), #[allow(clippy::redundant_clone)] "sampleBaseProperty" => intermediate_rep.sample_base_property.push(::from_str(val).map_err(|x| x.to_string())?), + #[allow(clippy::redundant_clone)] + "sampleProperty" => intermediate_rep.sample_property.push(::from_str(val).map_err(|x| x.to_string())?), _ => return std::result::Result::Err("Unexpected key while parsing AllOfObject".to_string()) } } @@ -289,8 +466,8 @@ impl std::str::FromStr for AllOfObject { // Use the intermediate representation to return the struct std::result::Result::Ok(AllOfObject { - sample_property: intermediate_rep.sample_property.into_iter().next(), sample_base_property: intermediate_rep.sample_base_property.into_iter().next(), + sample_property: intermediate_rep.sample_property.into_iter().next(), }) } } @@ -306,8 +483,7 @@ impl std::convert::TryFrom> for hyper::head match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for AllOfObject - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for AllOfObject - value: {hdr_value} is invalid {e}")) } } } @@ -322,27 +498,88 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into AllOfObject - {}", - value, err)) + format!("Unable to convert header value '{value}' into AllOfObject - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into AllOfObject - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct BaseAllOf { #[serde(rename = "sampleBaseProperty")] + #[serde(skip_serializing_if="Option::is_none")] pub sample_base_property: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for BaseAllOf { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for BaseAllOf { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl BaseAllOf { #[allow(clippy::new_without_default)] @@ -354,27 +591,25 @@ impl BaseAllOf { } /// Converts the BaseAllOf value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for BaseAllOf { - fn to_string(&self) -> String { +impl std::fmt::Display for BaseAllOf { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.sample_base_property.as_ref().map(|sample_base_property| { [ "sampleBaseProperty".to_string(), sample_base_property.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a BaseAllOf value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for BaseAllOf { type Err = String; @@ -430,8 +665,7 @@ impl std::convert::TryFrom> for hyper::header match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for BaseAllOf - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for BaseAllOf - value: {hdr_value} is invalid {e}")) } } } @@ -446,30 +680,92 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into BaseAllOf - {}", - value, err)) + format!("Unable to convert header value '{value}' into BaseAllOf - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into BaseAllOf - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} + +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct DummyPutRequest { #[serde(rename = "id")] + pub id: String, #[serde(rename = "password")] + #[serde(skip_serializing_if="Option::is_none")] pub password: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for DummyPutRequest { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for DummyPutRequest { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl DummyPutRequest { #[allow(clippy::new_without_default)] @@ -482,31 +778,27 @@ impl DummyPutRequest { } /// Converts the DummyPutRequest value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for DummyPutRequest { - fn to_string(&self) -> String { +impl std::fmt::Display for DummyPutRequest { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - Some("id".to_string()), Some(self.id.to_string()), - - self.password.as_ref().map(|password| { [ "password".to_string(), password.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a DummyPutRequest value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for DummyPutRequest { type Err = String; @@ -566,8 +858,7 @@ impl std::convert::TryFrom> for hyper:: match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for DummyPutRequest - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for DummyPutRequest - value: {hdr_value} is invalid {e}")) } } } @@ -582,29 +873,90 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into DummyPutRequest - {}", - value, err)) + format!("Unable to convert header value '{value}' into DummyPutRequest - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into DummyPutRequest - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} /// structured response -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct GetYamlResponse { /// Inner string #[serde(rename = "value")] + #[serde(skip_serializing_if="Option::is_none")] pub value: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for GetYamlResponse { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for GetYamlResponse { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl GetYamlResponse { #[allow(clippy::new_without_default)] @@ -616,27 +968,25 @@ impl GetYamlResponse { } /// Converts the GetYamlResponse value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for GetYamlResponse { - fn to_string(&self) -> String { +impl std::fmt::Display for GetYamlResponse { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - self.value.as_ref().map(|value| { [ "value".to_string(), value.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a GetYamlResponse value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for GetYamlResponse { type Err = String; @@ -692,8 +1042,7 @@ impl std::convert::TryFrom> for hyper:: match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for GetYamlResponse - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for GetYamlResponse - value: {hdr_value} is invalid {e}")) } } } @@ -708,28 +1057,90 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into GetYamlResponse - {}", - value, err)) + format!("Unable to convert header value '{value}' into GetYamlResponse - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into GetYamlResponse - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} /// An object of objects -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct ObjectOfObjects { #[serde(rename = "inner")] + + #[cfg_attr(feature = "validate", validate)] #[serde(skip_serializing_if="Option::is_none")] pub inner: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for ObjectOfObjects { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for ObjectOfObjects { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl ObjectOfObjects { #[allow(clippy::new_without_default)] @@ -741,21 +1152,20 @@ impl ObjectOfObjects { } /// Converts the ObjectOfObjects value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for ObjectOfObjects { - fn to_string(&self) -> String { +impl std::fmt::Display for ObjectOfObjects { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - // Skipping inner in query parameter serialization - + // Skipping non-primitive type inner in query parameter serialization ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a ObjectOfObjects value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for ObjectOfObjects { type Err = String; @@ -811,8 +1221,7 @@ impl std::convert::TryFrom> for hyper:: match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for ObjectOfObjects - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for ObjectOfObjects - value: {hdr_value} is invalid {e}")) } } } @@ -827,30 +1236,92 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into ObjectOfObjects - {}", - value, err)) + format!("Unable to convert header value '{value}' into ObjectOfObjects - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ObjectOfObjects - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} -#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize, validator::Validate)] +#[derive(Debug, Clone, PartialEq, Validate, serde::Serialize, serde::Deserialize)] #[cfg_attr(feature = "conversion", derive(frunk::LabelledGeneric))] pub struct ObjectOfObjectsInner { #[serde(rename = "required_thing")] + pub required_thing: String, #[serde(rename = "optional_thing")] + #[serde(skip_serializing_if="Option::is_none")] pub optional_thing: Option, } +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMinLength for ObjectOfObjectsInner { + fn validate_composited_min_length( + &self, + _min_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + +#[cfg(feature = "validate")] +impl serde_valid::validation::ValidateCompositedMaxLength for ObjectOfObjectsInner { + fn validate_composited_max_length( + &self, + _max_length: usize, + ) -> Result<(), serde_valid::validation::Composited> { + Ok(()) + } +} + impl ObjectOfObjectsInner { #[allow(clippy::new_without_default)] @@ -863,31 +1334,27 @@ impl ObjectOfObjectsInner { } /// Converts the ObjectOfObjectsInner value to the Query Parameters representation (style=form, explode=false) -/// specified in https://swagger.io/docs/specification/serialization/ +/// specified in /// Should be implemented in a serde serializer -impl std::string::ToString for ObjectOfObjectsInner { - fn to_string(&self) -> String { +impl std::fmt::Display for ObjectOfObjectsInner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let params: Vec> = vec![ - Some("required_thing".to_string()), Some(self.required_thing.to_string()), - - self.optional_thing.as_ref().map(|optional_thing| { [ "optional_thing".to_string(), optional_thing.to_string(), ].join(",") }), - ]; - params.into_iter().flatten().collect::>().join(",") + write!(f, "{}", params.into_iter().flatten().collect::>().join(",")) } } /// Converts Query Parameters representation (style=form, explode=false) to a ObjectOfObjectsInner value -/// as specified in https://swagger.io/docs/specification/serialization/ +/// as specified in /// Should be implemented in a serde deserializer impl std::str::FromStr for ObjectOfObjectsInner { type Err = String; @@ -947,8 +1414,7 @@ impl std::convert::TryFrom> for hy match hyper::header::HeaderValue::from_str(&hdr_value) { std::result::Result::Ok(value) => std::result::Result::Ok(value), std::result::Result::Err(e) => std::result::Result::Err( - format!("Invalid header value for ObjectOfObjectsInner - value: {} is invalid {}", - hdr_value, e)) + format!("Invalid header value for ObjectOfObjectsInner - value: {hdr_value} is invalid {e}")) } } } @@ -963,14 +1429,54 @@ impl std::convert::TryFrom for header::IntoHeaderVal match ::from_str(value) { std::result::Result::Ok(value) => std::result::Result::Ok(header::IntoHeaderValue(value)), std::result::Result::Err(err) => std::result::Result::Err( - format!("Unable to convert header value '{}' into ObjectOfObjectsInner - {}", - value, err)) + format!("Unable to convert header value '{value}' into ObjectOfObjectsInner - {err}")) } }, std::result::Result::Err(e) => std::result::Result::Err( - format!("Unable to convert header: {:?} to string: {}", - hdr_value, e)) + format!("Unable to convert header: {hdr_value:?} to string: {e}")) } } } +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom>> for hyper::header::HeaderValue { + type Error = String; + + fn try_from(hdr_values: header::IntoHeaderValue>) -> std::result::Result { + let hdr_values : Vec = hdr_values.0.into_iter().map(|hdr_value| { + hdr_value.to_string() + }).collect(); + + match hyper::header::HeaderValue::from_str(&hdr_values.join(", ")) { + std::result::Result::Ok(hdr_value) => std::result::Result::Ok(hdr_value), + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to convert {hdr_values:?} into a header - {e}",)) + } + } +} + +#[cfg(any(feature = "client", feature = "server"))] +impl std::convert::TryFrom for header::IntoHeaderValue> { + type Error = String; + + fn try_from(hdr_values: hyper::header::HeaderValue) -> std::result::Result { + match hdr_values.to_str() { + std::result::Result::Ok(hdr_values) => { + let hdr_values : std::vec::Vec = hdr_values + .split(',') + .filter_map(|hdr_value| match hdr_value.trim() { + "" => std::option::Option::None, + hdr_value => std::option::Option::Some({ + match ::from_str(hdr_value) { + std::result::Result::Ok(value) => std::result::Result::Ok(value), + std::result::Result::Err(err) => std::result::Result::Err( + format!("Unable to convert header value '{hdr_value}' into ObjectOfObjectsInner - {err}")) + } + }) + }).collect::, String>>()?; + + std::result::Result::Ok(header::IntoHeaderValue(hdr_values)) + }, + std::result::Result::Err(e) => std::result::Result::Err(format!("Unable to parse header: {hdr_values:?} as a string - {e}")), + } + } +} diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/server/mod.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/server/mod.rs index 69527ec5cf89..29c4795d608e 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/server/mod.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/server/mod.rs @@ -1,10 +1,14 @@ +use bytes::Bytes; use futures::{future, future::BoxFuture, Stream, stream, future::FutureExt, stream::TryStreamExt}; -use hyper::{Request, Response, StatusCode, Body, HeaderMap}; +use http_body_util::{combinators::BoxBody, Full}; +use hyper::{body::{Body, Incoming}, HeaderMap, Request, Response, StatusCode}; use hyper::header::{HeaderName, HeaderValue, CONTENT_TYPE}; use log::warn; +#[cfg(feature = "validate")] +use serde_valid::Validate; #[allow(unused_imports)] use std::convert::{TryFrom, TryInto}; -use std::error::Error; +use std::{convert::Infallible, error::Error}; use std::future::Future; use std::marker::PhantomData; use std::task::{Context, Poll}; @@ -18,7 +22,7 @@ use crate::{models, header, AuthenticationApi}; pub use crate::context; -type ServiceFuture = BoxFuture<'static, Result, crate::ServiceError>>; +type ServiceFuture = BoxFuture<'static, Result>, crate::ServiceError>>; use crate::{Api, AllOfGetResponse, @@ -61,28 +65,52 @@ mod paths { } -pub struct MakeService where +pub struct MakeService +where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { api_impl: T, marker: PhantomData, + validation: bool } -impl MakeService where +impl MakeService +where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { pub fn new(api_impl: T) -> Self { MakeService { api_impl, - marker: PhantomData + marker: PhantomData, + validation: false } } + + // Turn on/off validation for the service being made. + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation; + } } +impl Clone for MakeService +where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static +{ + fn clone(&self) -> Self { + Self { + api_impl: self.api_impl.clone(), + marker: PhantomData, + validation: self.validation + } + } +} -impl hyper::service::Service for MakeService where +impl hyper::service::Service for MakeService +where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { @@ -90,43 +118,72 @@ impl hyper::service::Service for MakeService where type Error = crate::ServiceError; type Future = future::Ready>; - fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll> { - Poll::Ready(Ok(())) - } + fn call(&self, target: Target) -> Self::Future { + let service = Service::new(self.api_impl.clone(), self.validation); - fn call(&mut self, target: Target) -> Self::Future { - future::ok(Service::new( - self.api_impl.clone(), - )) + future::ok(service) } } -fn method_not_allowed() -> Result, crate::ServiceError> { +fn method_not_allowed() -> Result>, crate::ServiceError> { Ok( Response::builder().status(StatusCode::METHOD_NOT_ALLOWED) - .body(Body::empty()) + .body(BoxBody::new(http_body_util::Empty::new())) .expect("Unable to create Method Not Allowed response") ) } +#[allow(unused_macros)] +#[cfg(not(feature = "validate"))] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => (); +} + +#[allow(unused_macros)] +#[cfg(feature = "validate")] +macro_rules! run_validation { + ($parameter:tt, $base_name:tt, $validation:tt) => { + let $parameter = if $validation { + match $parameter.validate() { + Ok(()) => $parameter, + Err(e) => return Ok(Response::builder() + .status(StatusCode::BAD_REQUEST) + .header(CONTENT_TYPE, mime::TEXT_PLAIN.as_ref()) + .body(BoxBody::new(format!("Invalid value in body parameter {}: {}", $base_name, e))) + .expect(&format!("Unable to create Bad Request response for invalid value in body parameter {}", $base_name))), + } + } else { + $parameter + }; + } +} + pub struct Service where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { api_impl: T, marker: PhantomData, + // Enable regex pattern validation of received JSON models + validation: bool, } impl Service where T: Api + Clone + Send + 'static, C: Has + Send + Sync + 'static { - pub fn new(api_impl: T) -> Self { + pub fn new(api_impl: T, validation: bool) -> Self { Service { api_impl, - marker: PhantomData + marker: PhantomData, + validation, } } + #[cfg(feature = "validate")] + pub fn set_validation(&mut self, validation: bool) { + self.validation = validation + } + } impl Clone for Service where @@ -137,39 +194,57 @@ impl Clone for Service where Service { api_impl: self.api_impl.clone(), marker: self.marker, + validation: self.validation, } } } -impl hyper::service::Service<(Request, C)> for Service where +#[allow(dead_code)] +fn body_from_string(s: String) -> BoxBody { + BoxBody::new(Full::new(Bytes::from(s))) +} + +fn body_from_str(s: &str) -> BoxBody { + BoxBody::new(Full::new(Bytes::copy_from_slice(s.as_bytes()))) +} + +impl hyper::service::Service<(Request, C)> for Service where T: Api + Clone + Send + Sync + 'static, - C: Has + Send + Sync + 'static + C: Has + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, { - type Response = Response; + type Response = Response>; type Error = crate::ServiceError; type Future = ServiceFuture; - fn poll_ready(&mut self, cx: &mut Context) -> Poll> { - self.api_impl.poll_ready(cx) - } - - fn call(&mut self, req: (Request, C)) -> Self::Future { async fn run(mut api_impl: T, req: (Request, C)) -> Result, crate::ServiceError> where - T: Api + Clone + Send + 'static, - C: Has + Send + Sync + 'static - { - let (request, context) = req; - let (parts, body) = request.into_parts(); - let (method, uri, headers) = (parts.method, parts.uri, parts.headers); - let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); - - match method { + fn call(&self, req: (Request, C)) -> Self::Future { + async fn run( + mut api_impl: T, + req: (Request, C), + validation: bool, + ) -> Result>, crate::ServiceError> + where + T: Api + Clone + Send + 'static, + C: Has + Send + Sync + 'static, + ReqBody: Body + Send + 'static, + ReqBody::Error: Into> + Send, + ReqBody::Data: Send, + { + let (request, context) = req; + let (parts, body) = request.into_parts(); + let (method, uri, headers) = (parts.method, parts.uri, parts.headers); + let path = paths::GLOBAL_REGEX_SET.matches(uri.path()); + + match method { // AllOfGet - GET /allOf hyper::Method::GET if path.matched(paths::ID_ALLOF) => { let result = api_impl.all_of_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -183,17 +258,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("*/*") - .expect("Unable to create Content-Type header for ALL_OF_GET_OK")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("*/*")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -205,7 +281,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.dummy_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -216,13 +292,14 @@ impl hyper::service::Service<(Request, C)> for Service where DummyGetResponse::Success => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -231,25 +308,26 @@ impl hyper::service::Service<(Request, C)> for Service where // DummyPut - PUT /dummy hyper::Method::PUT if path.matched(paths::ID_DUMMY) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_nested_response: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); + warn!("Ignoring unknown field in body: {path}"); unused_elements.push(path.to_string()); }) { Ok(param_nested_response) => param_nested_response, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter nested_response - doesn't match schema: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter nested_response - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter nested_response due to schema")), } + } else { None }; @@ -257,15 +335,18 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_nested_response) => param_nested_response, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter nested_response")) + .body(BoxBody::new("Missing required body parameter nested_response".to_string())) .expect("Unable to create Bad Request response for missing body parameter nested_response")), }; + #[cfg(not(feature = "validate"))] + run_validation!(param_nested_response, "nested_response", validation); + let result = api_impl.dummy_put( param_nested_response, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -274,22 +355,22 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { DummyPutResponse::Success => { *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -297,8 +378,8 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter nested_response: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter nested_response")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, @@ -307,7 +388,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.file_response_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -321,17 +402,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/json") - .expect("Unable to create Content-Type header for FILE_RESPONSE_GET_SUCCESS")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/json")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -343,7 +425,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.get_structured_yaml( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -357,17 +439,17 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("application/yaml") - .expect("Unable to create Content-Type header for GET_STRUCTURED_YAML_OK")); - let body_content = body; - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("application/yaml")); + // Plain text Body + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -376,18 +458,18 @@ impl hyper::service::Service<(Request, C)> for Service where // HtmlPost - POST /html hyper::Method::POST if path.matched(paths::ID_HTML) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { + Ok(body) => { let param_body: Option = if !body.is_empty() { match String::from_utf8(body.to_vec()) { Ok(param_body) => Some(param_body), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter body - not valid UTF-8: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter body - not valid UTF-8: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter body due to UTF-8")), } } else { @@ -397,15 +479,16 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_body) => param_body, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter body")) + .body(BoxBody::new("Missing required body parameter body".to_string())) .expect("Unable to create Bad Request response for missing body parameter body")), }; + let result = api_impl.html_post( param_body, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -419,17 +502,17 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("text/html") - .expect("Unable to create Content-Type header for HTML_POST_SUCCESS")); - let body_content = body; - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("text/html")); + // Plain text Body + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -437,25 +520,25 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter body: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter body")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, // PostYaml - POST /post-yaml hyper::Method::POST if path.matched(paths::ID_POST_YAML) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { + Ok(body) => { let param_value: Option = if !body.is_empty() { match String::from_utf8(body.to_vec()) { Ok(param_value) => Some(param_value), Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter value - not valid UTF-8: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter value - not valid UTF-8: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter value due to UTF-8")), } } else { @@ -465,15 +548,16 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_value) => param_value, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter value")) + .body(BoxBody::new("Missing required body parameter value".to_string())) .expect("Unable to create Bad Request response for missing body parameter value")), }; + let result = api_impl.post_yaml( param_value, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -484,13 +568,14 @@ impl hyper::service::Service<(Request, C)> for Service where PostYamlResponse::OK => { *response.status_mut() = StatusCode::from_u16(204).expect("Unable to turn 204 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -498,8 +583,8 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter value: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter value")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, @@ -508,7 +593,7 @@ impl hyper::service::Service<(Request, C)> for Service where let result = api_impl.raw_json_get( &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -522,17 +607,18 @@ impl hyper::service::Service<(Request, C)> for Service where *response.status_mut() = StatusCode::from_u16(200).expect("Unable to turn 200 into a StatusCode"); response.headers_mut().insert( CONTENT_TYPE, - HeaderValue::from_str("*/*") - .expect("Unable to create Content-Type header for RAW_JSON_GET_SUCCESS")); - let body_content = serde_json::to_string(&body).expect("impossible to fail to serialize"); - *response.body_mut() = Body::from(body_content); + HeaderValue::from_static("*/*")); + // JSON Body + let body = serde_json::to_string(&body).expect("impossible to fail to serialize"); + *response.body_mut() = body_from_string(body); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -541,25 +627,26 @@ impl hyper::service::Service<(Request, C)> for Service where // SoloObjectPost - POST /solo-object hyper::Method::POST if path.matched(paths::ID_SOLO_OBJECT) => { - // Body parameters (note that non-required body parameters will ignore garbage + // Handle body parameters (note that non-required body parameters will ignore garbage // values, rather than causing a 400 response). Produce warning header and logs for // any unused fields. - let result = body.into_raw().await; + let result = http_body_util::BodyExt::collect(body).await.map(|f| f.to_bytes().to_vec()); match result { - Ok(body) => { - let mut unused_elements = Vec::new(); + Ok(body) => { + let mut unused_elements : Vec = vec![]; let param_value: Option = if !body.is_empty() { let deserializer = &mut serde_json::Deserializer::from_slice(&body); match serde_ignored::deserialize(deserializer, |path| { - warn!("Ignoring unknown field in body: {}", path); + warn!("Ignoring unknown field in body: {path}"); unused_elements.push(path.to_string()); }) { Ok(param_value) => param_value, Err(e) => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't parse body parameter value - doesn't match schema: {}", e))) + .body(BoxBody::new(format!("Couldn't parse body parameter value - doesn't match schema: {e}"))) .expect("Unable to create Bad Request response for invalid body parameter value due to schema")), } + } else { None }; @@ -567,15 +654,16 @@ impl hyper::service::Service<(Request, C)> for Service where Some(param_value) => param_value, None => return Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from("Missing required body parameter value")) + .body(BoxBody::new("Missing required body parameter value".to_string())) .expect("Unable to create Bad Request response for missing body parameter value")), }; + let result = api_impl.solo_object_post( param_value, &context ).await; - let mut response = Response::new(Body::empty()); + let mut response = Response::new(BoxBody::new(http_body_util::Empty::new())); response.headers_mut().insert( HeaderName::from_static("x-span-id"), HeaderValue::from_str((&context as &dyn Has).get().0.clone().as_str()) @@ -584,22 +672,22 @@ impl hyper::service::Service<(Request, C)> for Service where if !unused_elements.is_empty() { response.headers_mut().insert( HeaderName::from_static("warning"), - HeaderValue::from_str(format!("Ignoring unknown fields in body: {:?}", unused_elements).as_str()) + HeaderValue::from_str(format!("Ignoring unknown fields in body: {unused_elements:?}").as_str()) .expect("Unable to create Warning header value")); } - match result { Ok(rsp) => match rsp { SoloObjectPostResponse::OK => { *response.status_mut() = StatusCode::from_u16(204).expect("Unable to turn 204 into a StatusCode"); + }, }, Err(_) => { // Application code returned an error. This should not happen, as the implementation should // return a valid response. *response.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - *response.body_mut() = Body::from("An internal error occurred"); + *response.body_mut() = body_from_str("An internal error occurred"); }, } @@ -607,8 +695,8 @@ impl hyper::service::Service<(Request, C)> for Service where }, Err(e) => Ok(Response::builder() .status(StatusCode::BAD_REQUEST) - .body(Body::from(format!("Couldn't read body parameter value: {}", e))) - .expect("Unable to create Bad Request response due to unable to read body parameter value")), + .body(body_from_string(format!("Unable to read body: {}", e.into()))) + .expect("Unable to create Bad Request response due to unable to read body")), } }, @@ -620,11 +708,17 @@ impl hyper::service::Service<(Request, C)> for Service where _ if path.matched(paths::ID_POST_YAML) => method_not_allowed(), _ if path.matched(paths::ID_RAW_JSON) => method_not_allowed(), _ if path.matched(paths::ID_SOLO_OBJECT) => method_not_allowed(), - _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) - .body(Body::empty()) - .expect("Unable to create Not Found response")) + _ => Ok(Response::builder().status(StatusCode::NOT_FOUND) + .body(BoxBody::new(http_body_util::Empty::new())) + .expect("Unable to create Not Found response")) + } } - } Box::pin(run(self.api_impl.clone(), req)) } + Box::pin(run( + self.api_impl.clone(), + req, + self.validation + )) + } } /// Request parser for `Api`. diff --git a/samples/server/petstore/rust-server/output/rust-server-test/src/server/server_auth.rs b/samples/server/petstore/rust-server/output/rust-server-test/src/server/server_auth.rs index ba78eb2f3f5d..21b1d7babd03 100644 --- a/samples/server/petstore/rust-server/output/rust-server-test/src/server/server_auth.rs +++ b/samples/server/petstore/rust-server/output/rust-server-test/src/server/server_auth.rs @@ -1,11 +1,12 @@ use super::Service; use crate::{Api, AuthenticationApi}; +use headers::authorization::{Basic, Bearer}; use swagger::{ ApiError, - Authorization, - auth::{Basic, Bearer}, - Has, - XSpanIdString}; + Authorization, + Has, + XSpanIdString +}; impl AuthenticationApi for Service where T: Api + Clone + Send + 'static + AuthenticationApi,