Compare commits

...

62 Commits

Author SHA1 Message Date
William Cheng
2199534829 fix 2026-01-27 12:57:03 +08:00
William Cheng
ea4d07da11 trigger build 2026-01-27 12:45:52 +08:00
William Cheng
dbba72842f update python server workflow to use v3.10 2026-01-27 12:40:02 +08:00
William Cheng
73a486a726 Update python-multipart to newer version (#22821)
* update python mltipart to newer version

* update python version in workflow

* update

* update version

* update
2026-01-27 12:38:38 +08:00
Adrian Boczkowski
ad948aa093 [Rust] Update reqwest to 0.13 and reqwest-middleware to 0.5 (#22816)
* [Rust] Update reqwest dependency to 0.13 with query and form features

Update the Rust client generator template to use reqwest 0.13 instead
of 0.12, as requested in issue #22621.

In reqwest 0.13, the `query()` and `form()` methods have been moved
behind feature flags and are disabled by default. Since the generated
Rust clients extensively use both methods, these features must be
explicitly enabled.

Changes:
- Updated all reqwest dependencies from ^0.12 to ^0.13
- Added "query" and "form" to reqwest feature flags for all variants:
  - Blocking client configuration
  - Async client with file stream support
  - Async client without file stream
  - Reqwest-trait variant
- Updated reqwest-middleware features for consistency

This maintains full backward compatibility as only the dependency
version and features change. The API surface of generated code
remains identical.

Fixes #22621

* [Rust] Updated samples

* [Rust] Rename rustls-tls feature to rustls to match reqwest 0.13

In reqwest 0.13, the rustls-tls feature was renamed to rustls.
This updates the Cargo.mustache template and all generated samples
to use the new feature name, fixing CI build failures when using
--all-features flag.

* [Rust] Upgrade reqwest-middleware to 0.5 for reqwest 0.13 compatibility

The previous reqwest-middleware 0.4 depends on reqwest 0.12, which caused
type conflicts when upgrading to reqwest 0.13:
- reqwest::Error (from reqwest 0.13)
- reqwest_middleware::reqwest::Error (from reqwest 0.12 via middleware)

These are different types from different versions of reqwest.

reqwest-middleware 0.5 is compatible with reqwest 0.13, resolving the
version conflict. With both using the same reqwest version, the re-exported
types are now correctly aligned.

* [Rust] Use query and form features from reqwest-middleware

It adds "query" and "form" features for reqwest-middleware crate in petstore-async-middleware example and Cargo.mustache template.

---------

Co-authored-by: Emil Bonne Kristiansen <emilbonnek@gmail.com>
2026-01-27 12:15:21 +08:00
dependabot[bot]
047ea41087 build(deps-dev): bump org.assertj:assertj-core (#22818)
Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.23.1 to 3.27.7.
- [Release notes](https://github.com/assertj/assertj/releases)
- [Commits](https://github.com/assertj/assertj/compare/assertj-core-3.23.1...assertj-build-3.27.7)

---
updated-dependencies:
- dependency-name: org.assertj:assertj-core
  dependency-version: 3.27.7
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-27 12:01:59 +08:00
William Cheng
39a3bfa181 update c# samples 2026-01-27 00:25:40 +08:00
devhl-labs
8cd3ea2457 added xml comments and restrict some access (#22796) 2026-01-26 23:58:31 +08:00
Martin Tomašovič
a4985cad28 [csharp][generichost] Add HTTP client name to fix client duplicity (#22118)
* Add HTTP client name to fix client duplicity

* Fix samples
2026-01-26 23:57:32 +08:00
azertyalex
422e30a3d9 Generate request config typescript fetch v2 (#22815)
* Add create requestOpts method to {{classname}}Interface #21708 (#21709)

* feat(types): Add request configuration method to {{classname}}Interface

* update docs and samples

* refactor: change naming to better mirror openapi context

* docs: update typescript-fetch

* feat(types): Add request configuration method to {{classname}}Interface
2026-01-26 23:53:33 +08:00
Esteban Gehring
67cbfb3cad Revert "Add create requestOpts method to {{classname}}Interface #21708 (#21709)" (#22814)
This reverts commit 51d5310dae.
2026-01-26 14:55:24 +01:00
William Cheng
0d10a5b8ff update TS samples 2026-01-26 21:49:03 +08:00
Bruno Coelho
43b15fbc25 [swift6][client] Remove unnecessary Combine checks (#22810) 2026-01-26 12:22:49 +00:00
Libor Nenadál
695f7076bf [BUG][typescript-angular] apiKeys cause service compilation errors (#22775)
* [BUG][typescript-angular] apiKeys cause service compilation errors

Updated TypeScript Angular `configuration.mustache` to properly handle
apiKeys in query parameters by using `OpenApiHttpParams` instead of
`HttpHeaders` to avoid compilation errors.

Fixes #22774

* add generated samples
2026-01-26 11:51:31 +01:00
azertyalex
51d5310dae Add create requestOpts method to {{classname}}Interface #21708 (#21709)
* feat(types): Add request configuration method to {{classname}}Interface

* update docs and samples

* refactor: change naming to better mirror openapi context

* docs: update typescript-fetch
2026-01-26 11:50:10 +01:00
dependabot[bot]
2d81b01737 build(deps): bump lodash (#22804)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-26 18:29:42 +08:00
Bruno Coelho
a0dc0e2eb8 [swift6] fix Vapor build, disable swift 5 tests on CI and enable more swift 6 tests on CI (#22805) 2026-01-25 17:45:12 +00:00
Bruno Coelho
d19f0cd348 [swift6][client] Increase minimum supported SDK to accommodate swift concurrency (#22802)
* [swift6][client] Increase minimum supported SDK to accommodate swift concurrency

* [swift6][client] Increase minimum supported SDK to accommodate swift concurrency
2026-01-25 10:21:52 +00:00
Bruno Coelho
17b77909d9 [dotnet] update samples (#22803) 2026-01-25 09:40:22 +00:00
Bruno Coelho
852a6075b2 [swift6][client] Add new hooks to OpenAPIInterceptor (#22800) 2026-01-25 00:18:38 +00:00
Bruno Coelho
1f4017a33f [swift6][client] improve swift 6 thread safety (#22801) 2026-01-24 23:58:39 +00:00
Bruno Coelho
2d53488404 [swift6][client] make api calls concurrent (#22790)
* [swift6][client] make api calls concurrent

* [swift6][client] improve swift 6 thread safety

* [swift6][client] improve swift 6 thread safety
2026-01-24 22:03:35 +00:00
Roman Doboni
5926c3175e Fix isRelativeUrl incorrectly detecting URLs containing @, -, ~, . as not relative. (#22768) 2026-01-25 00:40:23 +08:00
Artur Wolf
761cb777f6 Repaired partial_header include for generator csharp (#22442) 2026-01-24 23:56:36 +08:00
madsvonqualen
e868637587 [BUG] [HTML] Fix html array types (#22795)
* Fix HTML generator to display array types for body parameters

The HTML generator (htmlDocs) was not properly displaying array types
for request body parameters. When an endpoint accepted an array of
objects as input, only the base type was shown (e.g., "User") instead
of the full array type (e.g., "array[User]").

This fix updates the bodyParam.mustache template to include container
type information (array, map, etc.) when present, matching the format
already used for return types.

Before: User
After: array[User]

The fix wraps the baseType with containerType[...] when isContainer
is true, ensuring consistent type display across both input and output
types in the generated HTML documentation.

* Add html.yaml config and document testing requirements

Due to network limitations in the automated build environment, the
following steps could not be completed but are required per
contribution guidelines:

1. Build project: ./mvnw clean install -DskipTests
2. Regenerate samples: ./bin/generate-samples.sh bin/configs/html.yaml
3. Commit updated samples: git add samples/documentation/html/

Added:
- bin/configs/html.yaml: Configuration for html generator samples
- TESTING_STEPS.md: Detailed instructions for completing the PR

The template fix in bodyParam.mustache is complete and correct.
Sample regeneration is needed to verify the fix visually in the
generated HTML documentation.

* Add concrete example showing the bug location in current HTML sample

* Update HTML samples to verify array type fix

Regenerated samples/documentation/html/index.html to verify the array
type fix in bodyParam.mustache is working correctly.

Verified fix:
- Before: <div class="param">User <a href="#User">User</a> (required)</div>
- After:  <div class="param">User array[<a href="#User">User</a>] (required)</div>

The createUsersWithArrayInput endpoint (and all array body parameters)
now correctly displays "array[Type]" instead of just "Type".

Also removed TESTING_STEPS.md as testing is now complete.

* Update VERSION to 7.20.0-SNAPSHOT to match project version

The samples were regenerated using npm's openapi-generator-cli (v7.4.0),
but the CI expects the VERSION to match the current development version
(7.20.0-SNAPSHOT). Updated to prevent CI failures.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-01-24 23:27:16 +08:00
Bruno Coelho
ea6f4c8780 [swift6][client] mark PromiseKit as deprecated (#22792)
* [swift6][client] make PromiseKit as deprecated

* [swift6][client] make PromiseKit as deprecated

* [swift6][client] make PromiseKit as deprecated
2026-01-23 17:02:26 +00:00
dependabot[bot]
ab42a1bef2 build(deps-dev): bump tar (#22793)
Bumps [tar](https://github.com/isaacs/node-tar) from 7.5.3 to 7.5.6.
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v7.5.3...v7.5.6)

---
updated-dependencies:
- dependency-name: tar
  dependency-version: 7.5.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-24 00:51:29 +08:00
dependabot[bot]
943b80bbb4 build(deps-dev): bump tar (#22785)
Bumps [tar](https://github.com/isaacs/node-tar) from 7.5.3 to 7.5.6.
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v7.5.3...v7.5.6)

---
updated-dependencies:
- dependency-name: tar
  dependency-version: 7.5.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-23 23:52:46 +08:00
dependabot[bot]
6ad16aaf7b build(deps-dev): bump tar (#22786)
Bumps [tar](https://github.com/isaacs/node-tar) from 7.5.3 to 7.5.6.
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v7.5.3...v7.5.6)

---
updated-dependencies:
- dependency-name: tar
  dependency-version: 7.5.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-23 23:52:29 +08:00
Bruno Coelho
db7d39f622 [swift5][client] soft deprecate Swift 5 generator (#22789)
* [swift5][client] deprecate Swift 5 generator

* [swift5][client] deprecate Swift 5 generator
2026-01-23 15:50:46 +00:00
dependabot[bot]
acb80bac95 build(deps-dev): bump lodash (#22783)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-23 16:28:07 +08:00
dependabot[bot]
b15636e3e9 build(deps): bump lodash (#22782)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-23 16:27:59 +08:00
William Cheng
8a3507cfa7 update logback to newer version (#22781) 2026-01-23 15:55:16 +08:00
Bruno Coelho
2707e5101c [swift6][client] mark some closures as sendable (#22776) 2026-01-22 16:29:48 +00:00
William Cheng
cc045ab53c Fix output of bin/generate-samples.sh in tmux (#22772)
* bin/generate-samples: Remove warning about sleep

The sleep itself has been commented out for a long time (commit
04fa53b692 from September 2023, to be specific).

Signed-off-by: Stephen Finucane <stephen@that.guru>

* bin/generate-samples: Fix output on tmux

Commit 23dae2bcd8 reworked this script to start capturing exceptions
but the mechanism used was crude and broke output on tmux, since
`/dev/pts/0` is hardcoded to a specific pseudo-terminal but each tmux
pane gets its own pts. Rework this to use files instead.

Signed-off-by: Stephen Finucane <stephen@that.guru>

* update error message, trigger build failur

* trigger build failure

* Revert "trigger build failure"

This reverts commit 29536fab8a.

* add back null check

---------

Signed-off-by: Stephen Finucane <stephen@that.guru>
Co-authored-by: Stephen Finucane <stephen@that.guru>
2026-01-22 19:01:42 +08:00
Erwin de Haan
29befb95d2 Make TokenProvider not contain state so subclassing actually works correctly with JIT requested tokens (for long lived ApiClients) (#22233) 2026-01-22 18:44:38 +08:00
Erwin de Haan
3f9465edcb Support multi targetting (#22234) 2026-01-22 18:41:07 +08:00
William Cheng
2c463d9167 update C# samples 2026-01-22 17:15:29 +08:00
Erwin de Haan
5cffc45428 C# GenericHost support multiple accept headers and allow access to HttpContentHeaders on response (#22232)
* Add support for other Accept header values or full arrays when multiple options are present.

* Expose ContentHeaders on ApiResponse, to access ContentDisposition for example with file downloads.

* Update samples and documentation

* Fix build warning in samples
2026-01-22 16:48:03 +08:00
William Cheng
6fc64e2115 add docstring to cpp-qt methods (#22770) 2026-01-22 16:46:13 +08:00
Martin Delille
a1c948df9f [cpp=qt] Add global server index setter for all operations (#22760) 2026-01-22 16:28:17 +08:00
dependabot[bot]
bf5ced7354 build(deps): bump lodash (#22769)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-22 13:34:22 +08:00
dependabot[bot]
a045531ca7 build(deps): bump lodash (#22766)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-22 13:31:40 +08:00
dependabot[bot]
b66c93a864 build(deps): bump lodash (#22765)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-22 13:31:27 +08:00
dependabot[bot]
ea0504b17e build(deps): bump lodash (#22764)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-22 13:31:14 +08:00
dependabot[bot]
f2a49b1c27 build(deps): bump lodash (#22763)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-22 13:31:01 +08:00
dependabot[bot]
c189e5c263 build(deps-dev): bump lodash (#22762)
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.21 to 4.17.23.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.21...4.17.23)

---
updated-dependencies:
- dependency-name: lodash
  dependency-version: 4.17.23
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-22 13:30:43 +08:00
William Cheng
0f23c4ff17 update java undertow to newer version (#22759) 2026-01-22 12:21:55 +08:00
dependabot[bot]
342febde58 build(deps): bump @angular/core (#22654)
Bumps [@angular/core](https://github.com/angular/angular/tree/HEAD/packages/core) from 19.0.1 to 19.2.18.
- [Release notes](https://github.com/angular/angular/releases)
- [Changelog](https://github.com/angular/angular/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular/commits/v19.2.18/packages/core)

---
updated-dependencies:
- dependency-name: "@angular/core"
  dependency-version: 19.2.18
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-21 17:12:34 +08:00
dependabot[bot]
4034201640 build(deps): bump diff and mocha (#22745)
Bumps [diff](https://github.com/kpdecker/jsdiff) to 4.0.4 and updates ancestor dependency [mocha](https://github.com/mochajs/mocha). These dependencies need to be updated together.


Updates `diff` from 4.0.2 to 4.0.4
- [Changelog](https://github.com/kpdecker/jsdiff/blob/master/release-notes.md)
- [Commits](https://github.com/kpdecker/jsdiff/compare/v4.0.2...v4.0.4)

Updates `mocha` from 10.2.0 to 10.8.2
- [Release notes](https://github.com/mochajs/mocha/releases)
- [Changelog](https://github.com/mochajs/mocha/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mochajs/mocha/compare/v10.2.0...v10.8.2)

---
updated-dependencies:
- dependency-name: diff
  dependency-version: 4.0.4
  dependency-type: indirect
- dependency-name: mocha
  dependency-version: 10.8.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-21 16:28:51 +08:00
dependabot[bot]
4a61a4ca74 build(deps): bump diff and ts-node (#22746)
Bumps [diff](https://github.com/kpdecker/jsdiff) to 4.0.4 and updates ancestor dependency [ts-node](https://github.com/TypeStrong/ts-node). These dependencies need to be updated together.


Updates `diff` from 3.5.0 to 4.0.4
- [Changelog](https://github.com/kpdecker/jsdiff/blob/master/release-notes.md)
- [Commits](https://github.com/kpdecker/jsdiff/compare/v3.5.0...v4.0.4)

Updates `ts-node` from 3.3.0 to 10.9.2
- [Release notes](https://github.com/TypeStrong/ts-node/releases)
- [Changelog](https://github.com/TypeStrong/ts-node/blob/main/development-docs/release-template.md)
- [Commits](https://github.com/TypeStrong/ts-node/compare/v3.3.0...v10.9.2)

---
updated-dependencies:
- dependency-name: diff
  dependency-version: 4.0.4
  dependency-type: indirect
- dependency-name: ts-node
  dependency-version: 10.9.2
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-21 16:28:41 +08:00
dependabot[bot]
b862290aec build(deps): bump actions/cache from 4 to 5 (#22749)
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-21 16:26:40 +08:00
dependabot[bot]
52d910be41 build(deps): bump tar and @angular/cli (#22750)
Bumps [tar](https://github.com/isaacs/node-tar) to 7.5.5 and updates ancestor dependency [@angular/cli](https://github.com/angular/angular-cli). These dependencies need to be updated together.


Updates `tar` from 7.5.1 to 7.5.5
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v7.5.1...v7.5.5)

Updates `@angular/cli` from 20.3.13 to 21.1.0
- [Release notes](https://github.com/angular/angular-cli/releases)
- [Changelog](https://github.com/angular/angular-cli/blob/main/CHANGELOG.md)
- [Commits](https://github.com/angular/angular-cli/compare/20.3.13...v21.1.0)

---
updated-dependencies:
- dependency-name: tar
  dependency-version: 7.5.5
  dependency-type: indirect
- dependency-name: "@angular/cli"
  dependency-version: 21.1.0
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-21 16:26:28 +08:00
dependabot[bot]
3a670a697a build(deps-dev): bump tar (#22752)
Bumps [tar](https://github.com/isaacs/node-tar) from 7.5.3 to 7.5.6.
- [Release notes](https://github.com/isaacs/node-tar/releases)
- [Changelog](https://github.com/isaacs/node-tar/blob/main/CHANGELOG.md)
- [Commits](https://github.com/isaacs/node-tar/compare/v7.5.3...v7.5.6)

---
updated-dependencies:
- dependency-name: tar
  dependency-version: 7.5.6
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-21 16:26:18 +08:00
dependabot[bot]
0f136af41d build(deps): bump qs, body-parser and express (#22684)
Bumps [qs](https://github.com/ljharb/qs), [body-parser](https://github.com/expressjs/body-parser) and [express](https://github.com/expressjs/express). These dependencies needed to be updated together.

Updates `qs` from 6.13.0 to 6.14.1
- [Changelog](https://github.com/ljharb/qs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ljharb/qs/compare/v6.13.0...v6.14.1)

Updates `body-parser` from 1.20.3 to 1.20.4
- [Release notes](https://github.com/expressjs/body-parser/releases)
- [Changelog](https://github.com/expressjs/body-parser/blob/master/HISTORY.md)
- [Commits](https://github.com/expressjs/body-parser/compare/1.20.3...1.20.4)

Updates `express` from 4.21.1 to 4.22.1
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/v4.22.1/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.21.1...v4.22.1)

---
updated-dependencies:
- dependency-name: qs
  dependency-version: 6.14.1
  dependency-type: indirect
- dependency-name: body-parser
  dependency-version: 1.20.4
  dependency-type: indirect
- dependency-name: express
  dependency-version: 4.22.1
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-01-21 14:37:57 +08:00
Marc Schlegel
32d4085105 Mill plugin (#22739)
* Revert "remove mill plugin (#22736)"

This reverts commit 084a0a46b4.

* Add workaround for scaladoc generation in Scala 3 & additional update after revert
2026-01-21 03:48:12 +08:00
Masanori ITOH
3be911d0e6 [Normalizer] add type information to an error message and fix #22743 (#22742) 2026-01-21 02:44:35 +08:00
dsteeley
c34d593d8f fix: Fix rust-server model generation following serde_valid upgrade (#22737) 2026-01-20 14:30:00 +08:00
Matt Pollock
9a0d711cf6 [R] optionally skip parsing responses to R6 objects (#22705)
* optionally skip parsing responses to R6 objects

* parse -> .parse

* scope .parse to endpoints that return data

* move handling of .parsed so that it applies to both primitive and non-primitive return types

* try, try, again
2026-01-20 12:44:39 +08:00
William Cheng
9adfe986a3 Prepare v7.20.0 release (#22738)
* Revert "v7.19.0 release (#22732)"

This reverts commit ff400e9a31.

* prepare v7.20.0 release

* update samples

* update doc
2026-01-20 03:13:58 +08:00
William Cheng
084a0a46b4 remove mill plugin (#22736) 2026-01-20 01:23:24 +08:00
Marc Schlegel
a62ed1dd2a Add doc goal for scala-maven-plugin (#22734) 2026-01-19 23:49:23 +08:00
9518 changed files with 26183 additions and 17649 deletions

View File

@@ -21,7 +21,7 @@ jobs:
distribution: 'temurin' distribution: 'temurin'
- name: Restore cache (read-only) - name: Restore cache (read-only)
# only use restore keys, no save key because we need to clear the cache before running the examples # only use restore keys, no save key because we need to clear the cache before running the examples
uses: actions/cache/restore@v4 uses: actions/cache/restore@v5
with: with:
path: | path: |
~/.m2/repository ~/.m2/repository

View File

@@ -21,7 +21,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- uses: actions/setup-python@v6 - uses: actions/setup-python@v6
with: with:
python-version: '3.9' python-version: '3.10'
- name: Install dependencies - name: Install dependencies
working-directory: ${{ matrix.sample }} working-directory: ${{ matrix.sample }}
run: | run: |

View File

@@ -21,7 +21,7 @@ jobs:
- uses: actions/checkout@v5 - uses: actions/checkout@v5
- uses: actions/setup-python@v6 - uses: actions/setup-python@v6
with: with:
python-version: '3.9' python-version: '3.10'
- name: Test - name: Test
working-directory: ${{ matrix.sample }} working-directory: ${{ matrix.sample }}
run: make test-all run: make test-all

View File

@@ -15,7 +15,7 @@
<div align="center"> <div align="center">
[Master](https://github.com/OpenAPITools/openapi-generator/tree/master) (`7.19.0`): [Master](https://github.com/OpenAPITools/openapi-generator/tree/master) (`7.20.0`):
[![Integration Test2](https://circleci.com/gh/OpenAPITools/openapi-generator.svg?style=shield)](https://circleci.com/gh/OpenAPITools/openapi-generator) [![Integration Test2](https://circleci.com/gh/OpenAPITools/openapi-generator.svg?style=shield)](https://circleci.com/gh/OpenAPITools/openapi-generator)
[![Bitrise](https://img.shields.io/bitrise/4a2b10a819d12b67/master?label=bitrise%3A%20Swift+4,5&token=859FMDR8QHwabCzwvZK6vQ)](https://app.bitrise.io/app/4a2b10a819d12b67) [![Bitrise](https://img.shields.io/bitrise/4a2b10a819d12b67/master?label=bitrise%3A%20Swift+4,5&token=859FMDR8QHwabCzwvZK6vQ)](https://app.bitrise.io/app/4a2b10a819d12b67)
@@ -148,8 +148,8 @@ The OpenAPI Specification has undergone 3 revisions since initial creation in 20
| OpenAPI Generator Version | Release Date | Notes | | OpenAPI Generator Version | Release Date | Notes |
| --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ------------------------------------------------- | | --------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------ | ------------------------------------------------- |
| 7.19.0 (upcoming minor release) [SNAPSHOT](https://github.com/OpenAPITools/openapi-generator/wiki/FAQ#how-to-test-with-the-latest-master-of-openapi-generator) | 22.01.2026 | Minor release with breaking changes (with fallback) | | 7.20.0 (upcoming minor release) [SNAPSHOT](https://github.com/OpenAPITools/openapi-generator/wiki/FAQ#how-to-test-with-the-latest-master-of-openapi-generator) | 20.02.2026 | Minor release with breaking changes (with fallback) |
| [7.18.0](https://github.com/OpenAPITools/openapi-generator/releases/tag/v7.18.0) (latest stable release) | 22.12.2025 | Minor release with breaking changes (with fallback) | | [7.19.0](https://github.com/OpenAPITools/openapi-generator/releases/tag/v7.19.0) (latest stable release) | 20.01.2026 | Minor release with breaking changes (with fallback) |
| [6.6.0](https://github.com/OpenAPITools/openapi-generator/releases/tag/v6.6.0) | 11.05.2023 | Minor release with breaking changes (with fallback) | | [6.6.0](https://github.com/OpenAPITools/openapi-generator/releases/tag/v6.6.0) | 11.05.2023 | Minor release with breaking changes (with fallback) |
| [5.4.0](https://github.com/OpenAPITools/openapi-generator/releases/tag/v5.4.0) | 31.01.2022 | Minor release with breaking changes (with fallback) | | [5.4.0](https://github.com/OpenAPITools/openapi-generator/releases/tag/v5.4.0) | 31.01.2022 | Minor release with breaking changes (with fallback) |
| [4.3.1](https://github.com/OpenAPITools/openapi-generator/releases/tag/v4.3.1) | 06.05.2020 | Patch release (enhancements, bug fixes, etc) | | [4.3.1](https://github.com/OpenAPITools/openapi-generator/releases/tag/v4.3.1) | 06.05.2020 | Patch release (enhancements, bug fixes, etc) |
@@ -212,16 +212,16 @@ See the different versions of the [openapi-generator-cli](https://search.maven.o
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
If you're looking for the latest stable version, you can grab it directly from Maven.org (Java 11 runtime at a minimum): If you're looking for the latest stable version, you can grab it directly from Maven.org (Java 11 runtime at a minimum):
JAR location: `https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.18.0/openapi-generator-cli-7.18.0.jar` JAR location: `https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.19.0/openapi-generator-cli-7.19.0.jar`
For **Mac/Linux** users: For **Mac/Linux** users:
```sh ```sh
wget https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.18.0/openapi-generator-cli-7.18.0.jar -O openapi-generator-cli.jar wget https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.19.0/openapi-generator-cli-7.19.0.jar -O openapi-generator-cli.jar
``` ```
For **Windows** users, you will need to install [wget](http://gnuwin32.sourceforge.net/packages/wget.htm) or you can use Invoke-WebRequest in PowerShell (3.0+), e.g. For **Windows** users, you will need to install [wget](http://gnuwin32.sourceforge.net/packages/wget.htm) or you can use Invoke-WebRequest in PowerShell (3.0+), e.g.
``` ```
Invoke-WebRequest -OutFile openapi-generator-cli.jar https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.18.0/openapi-generator-cli-7.18.0.jar Invoke-WebRequest -OutFile openapi-generator-cli.jar https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.19.0/openapi-generator-cli-7.19.0.jar
``` ```
After downloading the JAR, run `java -jar openapi-generator-cli.jar help` to show the usage. After downloading the JAR, run `java -jar openapi-generator-cli.jar help` to show the usage.
@@ -456,7 +456,7 @@ openapi-generator-cli version
To use a specific version of "openapi-generator-cli" To use a specific version of "openapi-generator-cli"
```sh ```sh
openapi-generator-cli version-manager set 7.18.0 openapi-generator-cli version-manager set 7.19.0
``` ```
Or install it as dev-dependency: Or install it as dev-dependency:
@@ -480,7 +480,7 @@ pip install openapi-generator-cli
To install a specific version To install a specific version
``` ```
pip install openapi-generator-cli==7.18.0 pip install openapi-generator-cli==7.19.0
``` ```
You can also install with [jdk4py](https://github.com/activeviam/jdk4py) instead of java binary. (python>=3.10 is required) You can also install with [jdk4py](https://github.com/activeviam/jdk4py) instead of java binary. (python>=3.10 is required)
@@ -506,7 +506,7 @@ java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar generat
(if you're on Windows, replace the last command with `java -jar modules\openapi-generator-cli\target\openapi-generator-cli.jar generate -i https://raw.githubusercontent.com/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/3_0/petstore.yaml -g php -o c:\temp\php_api_client`) (if you're on Windows, replace the last command with `java -jar modules\openapi-generator-cli\target\openapi-generator-cli.jar generate -i https://raw.githubusercontent.com/openapitools/openapi-generator/master/modules/openapi-generator/src/test/resources/3_0/petstore.yaml -g php -o c:\temp\php_api_client`)
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
You can also download the JAR (latest release) directly from [maven.org](https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.18.0/openapi-generator-cli-7.18.0.jar) You can also download the JAR (latest release) directly from [maven.org](https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.19.0/openapi-generator-cli-7.19.0.jar)
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
To get a list of **general** options available, please run `java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar help generate` To get a list of **general** options available, please run `java -jar modules/openapi-generator-cli/target/openapi-generator-cli.jar help generate`

6
bin/configs/html.yaml Normal file
View File

@@ -0,0 +1,6 @@
generatorName: html
outputDir: samples/documentation/html
inputSpec: modules/openapi-generator/src/test/resources/3_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/htmlDocs
additionalProperties:
hideGenerationTimestamp: "true"

View File

@@ -7,6 +7,6 @@ generateAliasAsModel: true
additionalProperties: additionalProperties:
projectName: PetstoreClient projectName: PetstoreClient
useSPMFileStructure: true useSPMFileStructure: true
useClasses: true useClasses: false
useBacktickEscapes: true useBacktickEscapes: true
mapFileBinaryToData: true mapFileBinaryToData: true

View File

@@ -47,26 +47,26 @@ For example:
echo "$header" echo "$header"
if [[ ${#files[@]} -eq 1 && "${files[0]}" != *'*'* ]]; then tmpfile=$(mktemp)
# shellcheck disable=SC2086 trap "rm -f $tmpfile" EXIT
# shellcheck disable=SC2068
java ${JAVA_OPTS} -jar "$executable" generate -c ${files[0]} ${args[@]}
else
echo "Please press CTRL+C to stop or the script will continue in 5 seconds."
#sleep 5
if [ ${#files[@]} -eq 0 ]; then
files=("${root}"/bin/configs/*.yaml)
fi
# shellcheck disable=SC2086 if [[ ${#files[@]} -eq 1 && "${files[0]}" != *'*'* ]]; then
# shellcheck disable=SC2068 # shellcheck disable=SC2086
if java ${JAVA_OPTS} -jar "$executable" batch ${BATCH_OPTS} --includes-base-dir "${root}" --fail-fast -- ${files[@]} 2>&1 | tee /dev/pts/0 | grep -q -i "exception"; then # shellcheck disable=SC2068
echo "Found exception(s) when running the generator(s) to update the samples." java ${JAVA_OPTS} -jar "$executable" generate -c ${files[0]} ${args[@]} 2>&1 | tee "$tmpfile"
export GENERATE_ERROR=1 retcode=${PIPESTATUS[0]}
fi else
if [ ${#files[@]} -eq 0 ]; then
files=("${root}"/bin/configs/*.yaml)
fi
# shellcheck disable=SC2086
# shellcheck disable=SC2068
java ${JAVA_OPTS} -jar "$executable" batch ${BATCH_OPTS} --includes-base-dir "${root}" --fail-fast -- ${files[@]} 2>&1 | tee "$tmpfile"
retcode=${PIPESTATUS[0]}
fi fi
if [[ -n "$GENERATE_ERROR" ]]; then if [[ $retcode -ne 0 ]] || grep -q -i "at org.openapitools" "$tmpfile"; then
echo "Found exception(s) when running the generator(s) to update the samples." echo "Found exception(s) when running the generator(s) to update the samples."
exit 1 exit 1
fi fi

View File

@@ -27,15 +27,6 @@ workflows:
set -e set -e
./samples/client/petstore/swift6/swift6_test_all.sh ./samples/client/petstore/swift6/swift6_test_all.sh
- script@1.2.0:
title: Run Swift5 tests
inputs:
- content: |
#!/usr/bin/env bash
set -e
./samples/client/petstore/swift5/swift5_test_all.sh
- script@1.2.0: - script@1.2.0:
title: Run swift-combine tests title: Run swift-combine tests
inputs: inputs:

View File

@@ -68,7 +68,7 @@ The following generators are available:
* [scala-sttp4-jsoniter (beta)](generators/scala-sttp4-jsoniter.md) * [scala-sttp4-jsoniter (beta)](generators/scala-sttp4-jsoniter.md)
* [scalaz](generators/scalaz.md) * [scalaz](generators/scalaz.md)
* [swift-combine](generators/swift-combine.md) * [swift-combine](generators/swift-combine.md)
* [swift5](generators/swift5.md) * [swift5 (deprecated)](generators/swift5.md)
* [swift6](generators/swift6.md) * [swift6](generators/swift6.md)
* [typescript (experimental)](generators/typescript.md) * [typescript (experimental)](generators/typescript.md)
* [typescript-angular](generators/typescript-angular.md) * [typescript-angular](generators/typescript-angular.md)

View File

@@ -7,7 +7,7 @@ title: Documentation for the swift5 Generator
| Property | Value | Notes | | Property | Value | Notes |
| -------- | ----- | ----- | | -------- | ----- | ----- |
| generator name | swift5 | pass this to the generate command after -g | | generator name | swift5 | pass this to the generate command after -g |
| generator stability | STABLE | | | generator stability | DEPRECATED | |
| generator type | CLIENT | | | generator type | CLIENT | |
| generator language | Swift | | | generator language | Swift | |
| generator default templating engine | mustache | | | generator default templating engine | mustache | |

View File

@@ -22,7 +22,7 @@ npm install @openapitools/openapi-generator-cli -g
To install a specific version of the tool, pass the version during installation: To install a specific version of the tool, pass the version during installation:
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
```bash ```bash
openapi-generator-cli version-manager set 7.17.0 openapi-generator-cli version-manager set 7.19.0
``` ```
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
To install the tool as a dev dependency in your current project: To install the tool as a dev dependency in your current project:
@@ -119,18 +119,18 @@ docker run --rm \
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
If you're looking for the latest stable version, you can grab it directly from Maven.org (Java 11 runtime at a minimum): If you're looking for the latest stable version, you can grab it directly from Maven.org (Java 11 runtime at a minimum):
JAR location: `https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.17.0/openapi-generator-cli-7.17.0.jar` JAR location: `https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.19.0/openapi-generator-cli-7.19.0.jar`
For **Mac/Linux** users: For **Mac/Linux** users:
```bash ```bash
wget https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.17.0/openapi-generator-cli-7.17.0.jar -O openapi-generator-cli.jar wget https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.19.0/openapi-generator-cli-7.19.0.jar -O openapi-generator-cli.jar
``` ```
For **Windows** users, you will need to install [wget](http://gnuwin32.sourceforge.net/packages/wget.htm) or you can use Invoke-WebRequest in PowerShell (3.0+), e.g. For **Windows** users, you will need to install [wget](http://gnuwin32.sourceforge.net/packages/wget.htm) or you can use Invoke-WebRequest in PowerShell (3.0+), e.g.
```powershell ```powershell
Invoke-WebRequest -OutFile openapi-generator-cli.jar https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.17.0/openapi-generator-cli-7.17.0.jar Invoke-WebRequest -OutFile openapi-generator-cli.jar https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.19.0/openapi-generator-cli-7.19.0.jar
``` ```
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->

View File

@@ -16,7 +16,7 @@ Add to your `build->plugins` section (default phase is `generate-sources` phase)
<plugin> <plugin>
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId> <artifactId>openapi-generator-maven-plugin</artifactId>
<version>7.17.0</version> <version>7.19.0</version>
<executions> <executions>
<execution> <execution>
<goals> <goals>
@@ -130,7 +130,7 @@ This Mill library provides a Mill module that can be used to generate code from
```scala ```scala
//| mill-version: 1.0.6 //| mill-version: 1.0.6
//| mvnDeps: //| mvnDeps:
//| - org.openapitools:openapi-generator-mill-plugin:7.19.0 # 1. //| - org.openapitools:openapi-generator-mill-plugin:7.20.0 # 1.
import mill.* import mill.*

View File

@@ -4,7 +4,7 @@
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId> <artifactId>openapi-generator-project</artifactId>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.19.0</version> <version>7.20.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>

View File

@@ -6,7 +6,7 @@
<artifactId>openapi-generator-project</artifactId> <artifactId>openapi-generator-project</artifactId>
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.19.0</version> <version>7.20.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>

View File

@@ -97,7 +97,7 @@ task validateGoodSpec(type: org.openapitools.generator.gradle.plugin.tasks.Valid
[source,group] [source,group]
---- ----
plugins { plugins {
id "org.openapi.generator" version "7.17.0" id "org.openapi.generator" version "7.19.0"
} }
---- ----
@@ -113,7 +113,7 @@ buildscript {
// url "https://plugins.gradle.org/m2/" // url "https://plugins.gradle.org/m2/"
} }
dependencies { dependencies {
classpath "org.openapitools:openapi-generator-gradle-plugin:7.17.0" classpath "org.openapitools:openapi-generator-gradle-plugin:7.19.0"
} }
} }
@@ -759,7 +759,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.2.1' classpath 'com.android.tools.build:gradle:3.2.1'
classpath('org.openapitools:openapi-generator-gradle-plugin:7.17.0') { classpath('org.openapitools:openapi-generator-gradle-plugin:7.19.0') {
exclude group: 'com.google.guava' exclude group: 'com.google.guava'
} }
} }

View File

@@ -1,5 +1,5 @@
# RELEASE_VERSION # RELEASE_VERSION
openApiGeneratorVersion=7.19.0 openApiGeneratorVersion=7.20.0-SNAPSHOT
# /RELEASE_VERSION # /RELEASE_VERSION
# BEGIN placeholders # BEGIN placeholders

View File

@@ -4,7 +4,7 @@
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId> <artifactId>openapi-generator-project</artifactId>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.19.0</version> <version>7.20.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>

View File

@@ -1,3 +1,3 @@
# RELEASE_VERSION # RELEASE_VERSION
openApiGeneratorVersion=7.19.0 openApiGeneratorVersion=7.20.0-SNAPSHOT
# /RELEASE_VERSION # /RELEASE_VERSION

View File

@@ -12,7 +12,7 @@ Add to your `build->plugins` section (default phase is `generate-sources` phase)
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId> <artifactId>openapi-generator-maven-plugin</artifactId>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.17.0</version> <version>7.19.0</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<executions> <executions>
<execution> <execution>

View File

@@ -13,7 +13,7 @@
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId> <artifactId>openapi-generator-maven-plugin</artifactId>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.19.0</version> <version>7.20.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<executions> <executions>
<execution> <execution>

View File

@@ -15,7 +15,7 @@
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId> <artifactId>openapi-generator-maven-plugin</artifactId>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.19.0</version> <version>7.20.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<executions> <executions>
<execution> <execution>

View File

@@ -19,7 +19,7 @@
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId> <artifactId>openapi-generator-maven-plugin</artifactId>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.19.0</version> <version>7.20.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<dependencies> <dependencies>
<dependency> <dependency>

View File

@@ -13,7 +13,7 @@
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId> <artifactId>openapi-generator-maven-plugin</artifactId>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.19.0</version> <version>7.20.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<executions> <executions>
<execution> <execution>

View File

@@ -13,7 +13,7 @@
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId> <artifactId>openapi-generator-maven-plugin</artifactId>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.19.0</version> <version>7.20.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<executions> <executions>
<execution> <execution>

View File

@@ -20,7 +20,7 @@
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId> <artifactId>openapi-generator-maven-plugin</artifactId>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.19.0</version> <version>7.20.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<executions> <executions>
<execution> <execution>

View File

@@ -5,7 +5,7 @@
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId> <artifactId>openapi-generator-project</artifactId>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.19.0</version> <version>7.20.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>

View File

@@ -1,3 +1,3 @@
# RELEASE_VERSION # RELEASE_VERSION
openApiGeneratorVersion=7.19.0 openApiGeneratorVersion=7.20.0-SNAPSHOT
# /RELEASE_VERSION # /RELEASE_VERSION

View File

@@ -4,7 +4,7 @@
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId> <artifactId>openapi-generator-project</artifactId>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.19.0</version> <version>7.20.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
@@ -139,6 +139,28 @@
<goal>testCompile</goal> <goal>testCompile</goal>
</goals> </goals>
</execution> </execution>
<execution>
<!-- see https://github.com/davidB/scala-maven-plugin/issues/604 why a workaround is needed -->
<id>attach-javadocs</id>
<goals>
<goal>doc-jar</goal>
</goals>
<configuration>
<scaladocClassName>dotty.tools.scaladoc.Main</scaladocClassName>
<sourceDir>${project.build.outputDirectory}</sourceDir>
<args>-nobootcp</args>
<includes>
<include>**/*.tasty</include>
</includes>
<dependencies>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scaladoc_3</artifactId>
<version>3.7.4</version>
</dependency>
</dependencies>
</configuration>
</execution>
</executions> </executions>
</plugin> </plugin>
<plugin> <plugin>

View File

@@ -4,7 +4,7 @@
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId> <artifactId>openapi-generator-project</artifactId>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.19.0</version> <version>7.20.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>

View File

@@ -4,7 +4,7 @@
<groupId>org.openapitools</groupId> <groupId>org.openapitools</groupId>
<artifactId>openapi-generator-project</artifactId> <artifactId>openapi-generator-project</artifactId>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.19.0</version> <version>7.20.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<relativePath>../../pom.xml</relativePath> <relativePath>../../pom.xml</relativePath>
</parent> </parent>
@@ -488,7 +488,7 @@
<dependency> <dependency>
<groupId>org.assertj</groupId> <groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId> <artifactId>assertj-core</artifactId>
<version>3.23.1</version> <version>3.27.7</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency> <dependency>

View File

@@ -1854,7 +1854,7 @@ public class OpenAPINormalizer {
schema.addAnyOfItem(new BooleanSchema()); schema.addAnyOfItem(new BooleanSchema());
break; break;
default: default:
LOGGER.error("Type {} not yet supported in openapi-normalizer to process OpenAPI 3.1 spec with multiple types."); LOGGER.error("Type {} not yet supported in openapi-normalizer to process OpenAPI 3.1 spec with multiple types.", String.valueOf(type));
LOGGER.error("Please report the issue via https://github.com/OpenAPITools/openapi-generator/issues/new/."); LOGGER.error("Please report the issue via https://github.com/OpenAPITools/openapi-generator/issues/new/.");
} }
} }

View File

@@ -134,7 +134,7 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
this.useOneOfInterfaces = true; this.useOneOfInterfaces = true;
generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata) generatorMetadata = GeneratorMetadata.newBuilder(generatorMetadata)
.stability(Stability.STABLE) .stability(Stability.DEPRECATED)
.build(); .build();
outputFolder = "generated-code" + File.separator + "swift"; outputFolder = "generated-code" + File.separator + "swift";
@@ -430,6 +430,8 @@ public class Swift5ClientCodegen extends DefaultCodegen implements CodegenConfig
public void processOpts() { public void processOpts() {
super.processOpts(); super.processOpts();
LOGGER.warn("IMPORTANT: This generator has been deprecated. Please use `swift6` instead");
if (StringUtils.isEmpty(System.getenv("SWIFT_POST_PROCESS_FILE"))) { if (StringUtils.isEmpty(System.getenv("SWIFT_POST_PROCESS_FILE"))) {
LOGGER.info("Environment variable SWIFT_POST_PROCESS_FILE not defined so the Swift code may not be properly formatted. To define it, try 'export SWIFT_POST_PROCESS_FILE=/usr/local/bin/swiftformat' (Linux/Mac)"); LOGGER.info("Environment variable SWIFT_POST_PROCESS_FILE not defined so the Swift code may not be properly formatted. To define it, try 'export SWIFT_POST_PROCESS_FILE=/usr/local/bin/swiftformat' (Linux/Mac)");
LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI)."); LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI).");

View File

@@ -491,6 +491,9 @@ public class Swift6ClientCodegen extends DefaultCodegen implements CodegenConfig
additionalProperties.put(RESPONSE_AS, responseAs); additionalProperties.put(RESPONSE_AS, responseAs);
if (ArrayUtils.contains(responseAs, RESPONSE_LIBRARY_PROMISE_KIT)) { if (ArrayUtils.contains(responseAs, RESPONSE_LIBRARY_PROMISE_KIT)) {
additionalProperties.put("usePromiseKit", true); additionalProperties.put("usePromiseKit", true);
LOGGER.warn("NOTICE: We are considering deprecating PromiseKit support in the Swift 6 generator. " +
"If you are still using it, please share your use case here: " +
"https://github.com/OpenAPITools/openapi-generator/issues/22791");
} }
if (ArrayUtils.contains(responseAs, RESPONSE_LIBRARY_RX_SWIFT)) { if (ArrayUtils.contains(responseAs, RESPONSE_LIBRARY_RX_SWIFT)) {
additionalProperties.put("useRxSwift", true); additionalProperties.put("useRxSwift", true);

View File

@@ -235,7 +235,7 @@ public class URLPathUtils {
public static boolean isRelativeUrl(List<Server> servers) { public static boolean isRelativeUrl(List<Server> servers) {
if (servers != null && servers.size() > 0) { if (servers != null && servers.size() > 0) {
final Server firstServer = servers.get(0); final Server firstServer = servers.get(0);
return Pattern.matches("^(\\/[\\w\\d]+)+", firstServer.getUrl()); return Pattern.matches("^(\\/[\\w\\d.~@-]+)+", firstServer.getUrl());
} }
return false; return false;
} }

View File

@@ -220,7 +220,7 @@ for this project used jakarta.validation-api -->
<swagger-core-version>1.5.22</swagger-core-version> <swagger-core-version>1.5.22</swagger-core-version>
<jetty-version>9.2.9.v20150224</jetty-version> <jetty-version>9.2.9.v20150224</jetty-version>
<junit-version>4.13.2</junit-version> <junit-version>4.13.2</junit-version>
<logback-version>1.5.19</logback-version> <logback-version>1.5.25</logback-version>
{{#useBeanValidation}} {{#useBeanValidation}}
<beanvalidation-version>2.0.2</beanvalidation-version> <beanvalidation-version>2.0.2</beanvalidation-version>
{{/useBeanValidation}} {{/useBeanValidation}}

View File

@@ -342,7 +342,7 @@ for this project used jakarta.validation-api -->
{{/generateSpringApplication}} {{/generateSpringApplication}}
{{^generateSpringBootApplication}} {{^generateSpringBootApplication}}
<junit-version>4.13.2</junit-version> <junit-version>4.13.2</junit-version>
<logback-version>1.5.19</logback-version> <logback-version>1.5.25</logback-version>
{{/generateSpringBootApplication}} {{/generateSpringBootApplication}}
<cxf-version>3.5.9</cxf-version> <cxf-version>3.5.9</cxf-version>
<jackson-jaxrs-version>2.17.1</jackson-jaxrs-version> <jackson-jaxrs-version>2.17.1</jackson-jaxrs-version>

View File

@@ -255,7 +255,7 @@ for this project used jakarta.validation-api -->
{{/swagger2AnnotationLibrary}} {{/swagger2AnnotationLibrary}}
<jetty-version>9.2.9.v20150224</jetty-version> <jetty-version>9.2.9.v20150224</jetty-version>
<junit-version>4.13.2</junit-version> <junit-version>4.13.2</junit-version>
<logback-version>1.5.19</logback-version> <logback-version>1.5.25</logback-version>
{{#useBeanValidation}} {{#useBeanValidation}}
<beanvalidation-version>2.0.2</beanvalidation-version> <beanvalidation-version>2.0.2</beanvalidation-version>
{{/useBeanValidation}} {{/useBeanValidation}}

View File

@@ -311,7 +311,7 @@ for this project used jakarta.validation-api -->
{{/swagger2AnnotationLibrary}} {{/swagger2AnnotationLibrary}}
<jetty-version>9.2.9.v20150224</jetty-version> <jetty-version>9.2.9.v20150224</jetty-version>
<junit-version>4.13.2</junit-version> <junit-version>4.13.2</junit-version>
<logback-version>1.5.19</logback-version> <logback-version>1.5.25</logback-version>
{{#useBeanValidation}} {{#useBeanValidation}}
<beanvalidation-version>2.0.2</beanvalidation-version> <beanvalidation-version>2.0.2</beanvalidation-version>
{{/useBeanValidation}} {{/useBeanValidation}}

View File

@@ -222,7 +222,7 @@
<jersey3-version>3.1.3</jersey3-version> <jersey3-version>3.1.3</jersey3-version>
<jackson-version>2.17.1</jackson-version> <jackson-version>2.17.1</jackson-version>
<junit-version>4.13.2</junit-version> <junit-version>4.13.2</junit-version>
<logback-version>1.5.19</logback-version> <logback-version>1.5.25</logback-version>
<servlet-api-version>5.0.0</servlet-api-version> <servlet-api-version>5.0.0</servlet-api-version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>

View File

@@ -222,7 +222,7 @@ for this project used jakarta.validation-api -->
<jersey2-version>2.35</jersey2-version> <jersey2-version>2.35</jersey2-version>
<jackson-version>2.17.1</jackson-version> <jackson-version>2.17.1</jackson-version>
<junit-version>4.13.2</junit-version> <junit-version>4.13.2</junit-version>
<logback-version>1.5.19</logback-version> <logback-version>1.5.25</logback-version>
<servlet-api-version>4.0.4</servlet-api-version> <servlet-api-version>4.0.4</servlet-api-version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties> </properties>

View File

@@ -133,6 +133,13 @@ If your endpoint has multiple server objects in the servers array, you can set t
void setServerIndex(const QString &operation, int serverIndex); void setServerIndex(const QString &operation, int serverIndex);
``` ```
Parameter "operation" should be your operationid. "serverIndex" is the index you want to set as your default server. The function will check if there is a server with your index. Parameter "operation" should be your operationid. "serverIndex" is the index you want to set as your default server. The function will check if there is a server with your index.
Alternatively, to set the server index globally for all operations:
```c++
void setServerIndex(int serverIndex);
```
This will apply the specified server index to all operations in the API.
Here is an example of multiple servers in the servers array. The first server will have index 0 and the second will have index 1. Here is an example of multiple servers in the servers array. The first server will have index 0 and the second will have index 1.
```yaml ```yaml
servers: servers:

View File

@@ -57,9 +57,9 @@ void {{classname}}::initializeServerConfigs() {
} }
/** /**
* returns 0 on success and -1, -2 or -3 on failure. * returns 0 on success and -1, -2 or -3 on failure.
* -1 when the variable does not exist and -2 if the value is not defined in the enum and -3 if the operation or server index is not found * -1 when the variable does not exist and -2 if the value is not defined in the enum and -3 if the operation or server index is not found
*/ */
int {{classname}}::setDefaultServerValue(int serverIndex, const QString &operation, const QString &variable, const QString &value) { int {{classname}}::setDefaultServerValue(int serverIndex, const QString &operation, const QString &variable, const QString &value) {
auto it = _serverConfigs.find(operation); auto it = _serverConfigs.find(operation);
if (it != _serverConfigs.end() && serverIndex < it.value().size()) { if (it != _serverConfigs.end() && serverIndex < it.value().size()) {
@@ -67,12 +67,24 @@ int {{classname}}::setDefaultServerValue(int serverIndex, const QString &operati
} }
return -3; return -3;
} }
/**
* Sets the server index.
* @param operation The id to the target operation.
* @param serverIndex The server index.
*/
void {{classname}}::setServerIndex(const QString &operation, int serverIndex) { void {{classname}}::setServerIndex(const QString &operation, int serverIndex) {
if (_serverIndices.contains(operation) && serverIndex < _serverConfigs.find(operation).value().size()) { if (_serverIndices.contains(operation) && serverIndex < _serverConfigs.find(operation).value().size()) {
_serverIndices[operation] = serverIndex; _serverIndices[operation] = serverIndex;
} }
} }
void {{classname}}::setServerIndex(int serverIndex) {
for (auto keyIt = _serverIndices.keyBegin(); keyIt != _serverIndices.keyEnd(); keyIt++) {
setServerIndex(*keyIt, serverIndex);
}
}
void {{classname}}::setApiKey(const QString &apiKeyName, const QString &apiKey) { void {{classname}}::setApiKey(const QString &apiKeyName, const QString &apiKey) {
_apiKeys.insert(apiKeyName, apiKey); _apiKeys.insert(apiKeyName, apiKey);
} }
@@ -103,13 +115,13 @@ void {{classname}}::setNetworkAccessManager(QNetworkAccessManager* manager) {
} }
/** /**
* Appends a new ServerConfiguration to the config map for a specific operation. * Appends a new ServerConfiguration to the config map for a specific operation.
* @param operation The id to the target operation. * @param operation The id to the target operation.
* @param url A string that contains the URL of the server * @param url A string that contains the URL of the server
* @param description A String that describes the server * @param description A String that describes the server
* @param variables A map between a variable name and its value. The value is used for substitution in the server's URL template. * @param variables A map between a variable name and its value. The value is used for substitution in the server's URL template.
* returns the index of the new server config on success and -1 if the operation is not found * returns the index of the new server config on success and -1 if the operation is not found
*/ */
int {{classname}}::addServerConfiguration(const QString &operation, const QUrl &url, const QString &description, const QMap<QString, {{prefix}}ServerVariable> &variables) { int {{classname}}::addServerConfiguration(const QString &operation, const QUrl &url, const QString &description, const QMap<QString, {{prefix}}ServerVariable> &variables) {
if (_serverConfigs.contains(operation)) { if (_serverConfigs.contains(operation)) {
_serverConfigs[operation].append({{prefix}}ServerConfiguration( _serverConfigs[operation].append({{prefix}}ServerConfiguration(
@@ -123,11 +135,11 @@ int {{classname}}::addServerConfiguration(const QString &operation, const QUrl &
} }
/** /**
* Appends a new ServerConfiguration to the config map for a all operations and sets the index to that server. * Appends a new ServerConfiguration to the config map for a all operations and sets the index to that server.
* @param url A string that contains the URL of the server * @param url A string that contains the URL of the server
* @param description A String that describes the server * @param description A String that describes the server
* @param variables A map between a variable name and its value. The value is used for substitution in the server's URL template. * @param variables A map between a variable name and its value. The value is used for substitution in the server's URL template.
*/ */
void {{classname}}::setNewServerForAllOperations(const QUrl &url, const QString &description, const QMap<QString, {{prefix}}ServerVariable> &variables) { void {{classname}}::setNewServerForAllOperations(const QUrl &url, const QString &description, const QMap<QString, {{prefix}}ServerVariable> &variables) {
for (auto keyIt = _serverIndices.keyBegin(); keyIt != _serverIndices.keyEnd(); keyIt++) { for (auto keyIt = _serverIndices.keyBegin(); keyIt != _serverIndices.keyEnd(); keyIt++) {
setServerIndex(*keyIt, addServerConfiguration(*keyIt, url, description, variables)); setServerIndex(*keyIt, addServerConfiguration(*keyIt, url, description, variables));
@@ -135,11 +147,11 @@ void {{classname}}::setNewServerForAllOperations(const QUrl &url, const QString
} }
/** /**
* Appends a new ServerConfiguration to the config map for an operations and sets the index to that server. * Appends a new ServerConfiguration to the config map for an operations and sets the index to that server.
* @param URL A string that contains the URL of the server * @param URL A string that contains the URL of the server
* @param description A String that describes the server * @param description A String that describes the server
* @param variables A map between a variable name and its value. The value is used for substitution in the server's URL template. * @param variables A map between a variable name and its value. The value is used for substitution in the server's URL template.
*/ */
void {{classname}}::setNewServer(const QString &operation, const QUrl &url, const QString &description, const QMap<QString, {{prefix}}ServerVariable> &variables) { void {{classname}}::setNewServer(const QString &operation, const QUrl &url, const QString &description, const QMap<QString, {{prefix}}ServerVariable> &variables) {
setServerIndex(operation, addServerConfiguration(operation, url, description, variables)); setServerIndex(operation, addServerConfiguration(operation, url, description, variables));
} }

View File

@@ -30,6 +30,7 @@ public:
void initializeServerConfigs(); void initializeServerConfigs();
int setDefaultServerValue(int serverIndex,const QString &operation, const QString &variable,const QString &val); int setDefaultServerValue(int serverIndex,const QString &operation, const QString &variable,const QString &val);
void setServerIndex(const QString &operation, int serverIndex); void setServerIndex(const QString &operation, int serverIndex);
void setServerIndex(int serverIndex);
void setApiKey(const QString &apiKeyName, const QString &apiKey); void setApiKey(const QString &apiKeyName, const QString &apiKey);
void setBearerToken(const QString &token); void setBearerToken(const QString &token);
void setUsername(const QString &username); void setUsername(const QString &username);

View File

@@ -1,3 +1,4 @@
{{>partial_header}}
using System.Reflection; using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;

View File

@@ -1,3 +1,4 @@
{{>partial_header}}
using System; using System;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using {{packageName}}.{{apiPackage}}; using {{packageName}}.{{apiPackage}};

View File

@@ -1,5 +1,6 @@
// <auto-generated> // <auto-generated>
{{partial_header}} {{>partial_header}}
{{#nrt}} {{#nrt}}
#nullable enable #nullable enable

View File

@@ -1,3 +1,4 @@
{{>partial_header}}
using System; using System;
namespace {{packageName}}.{{clientPackage}} namespace {{packageName}}.{{clientPackage}}

View File

@@ -49,6 +49,11 @@ namespace {{packageName}}.{{clientPackage}}
/// </summary> /// </summary>
System.Net.Http.Headers.HttpResponseHeaders Headers { get; } System.Net.Http.Headers.HttpResponseHeaders Headers { get; }
/// <summary>
/// The headers contained in the api response related to the content
/// </summary>
System.Net.Http.Headers.HttpContentHeaders ContentHeaders { get; }
/// <summary> /// <summary>
/// The path used when making the request. /// The path used when making the request.
/// </summary> /// </summary>
@@ -106,6 +111,11 @@ namespace {{packageName}}.{{clientPackage}}
/// </summary> /// </summary>
public System.Net.Http.Headers.HttpResponseHeaders Headers { get; } public System.Net.Http.Headers.HttpResponseHeaders Headers { get; }
/// <summary>
/// The headers contained in the api response related to the content
/// </summary>
public System.Net.Http.Headers.HttpContentHeaders ContentHeaders { get; }
/// <summary> /// <summary>
/// The DateTime when the request was retrieved. /// The DateTime when the request was retrieved.
/// </summary> /// </summary>
@@ -144,6 +154,7 @@ namespace {{packageName}}.{{clientPackage}}
{ {
StatusCode = httpResponseMessage.StatusCode; StatusCode = httpResponseMessage.StatusCode;
Headers = httpResponseMessage.Headers; Headers = httpResponseMessage.Headers;
ContentHeaders = httpResponseMessage.Content.Headers;
IsSuccessStatusCode = httpResponseMessage.IsSuccessStatusCode; IsSuccessStatusCode = httpResponseMessage.IsSuccessStatusCode;
ReasonPhrase = httpResponseMessage.ReasonPhrase; ReasonPhrase = httpResponseMessage.ReasonPhrase;
RawContent = rawContent; RawContent = rawContent;
@@ -167,6 +178,7 @@ namespace {{packageName}}.{{clientPackage}}
{ {
StatusCode = httpResponseMessage.StatusCode; StatusCode = httpResponseMessage.StatusCode;
Headers = httpResponseMessage.Headers; Headers = httpResponseMessage.Headers;
ContentHeaders = httpResponseMessage.Content.Headers;
IsSuccessStatusCode = httpResponseMessage.IsSuccessStatusCode; IsSuccessStatusCode = httpResponseMessage.IsSuccessStatusCode;
ReasonPhrase = httpResponseMessage.ReasonPhrase; ReasonPhrase = httpResponseMessage.ReasonPhrase;
ContentStream = contentStream; ContentStream = contentStream;
@@ -178,6 +190,7 @@ namespace {{packageName}}.{{clientPackage}}
OnCreated(httpRequestMessage, httpResponseMessage); OnCreated(httpRequestMessage, httpResponseMessage);
} }
partial void OnCreated(global::System.Net.Http.HttpRequestMessage httpRequestMessage, System.Net.Http.HttpResponseMessage httpResponseMessage); partial void OnCreated(global::System.Net.Http.HttpRequestMessage httpRequestMessage, System.Net.Http.HttpResponseMessage httpResponseMessage);
} }
{{#x-http-statuses-with-return}} {{#x-http-statuses-with-return}}

View File

@@ -1,5 +1,6 @@
// <auto-generated> // <auto-generated>
{{partial_header}} {{>partial_header}}
{{#nrt}} {{#nrt}}
#nullable enable #nullable enable

View File

@@ -1,5 +1,6 @@
// <auto-generated> // <auto-generated>
{{partial_header}} {{>partial_header}}
{{#nrt}} {{#nrt}}
#nullable enable #nullable enable

View File

@@ -18,6 +18,7 @@ using {{packageName}}.{{modelPackage}};
{{/-first}} {{/-first}}
{{/models}} {{/models}}
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Net.Http.Headers;
{{>Assembly}}namespace {{packageName}}.{{clientPackage}} {{>Assembly}}namespace {{packageName}}.{{clientPackage}}
{ {
@@ -311,6 +312,36 @@ using System.Runtime.CompilerServices;
return string.Join(",", accepts); return string.Join(",", accepts);
} }
/// <summary>
/// Select the Accept header's value from the given accepts array:
/// if JSON exists in the given array, use it;
/// otherwise use all of them.
/// </summary>
/// <param name="accepts">The accepts array to select from.</param>
/// <returns>The Accept header values to use.</returns>
public static IEnumerable<MediaTypeWithQualityHeaderValue> SelectHeaderAcceptArray(string[] accepts)
{
if (accepts.Length == 0)
{{#net80OrLater}}
return [];
{{/net80OrLater}}
{{^net80OrLater}}
return Enumerable.Empty<MediaTypeWithQualityHeaderValue>();
{{/net80OrLater}}
if (accepts.Contains("application/json", StringComparer.OrdinalIgnoreCase))
{{#net80OrLater}}
return [MediaTypeWithQualityHeaderValue.Parse("application/json")];
{{/net80OrLater}}
{{^net80OrLater}}
return new [] { MediaTypeWithQualityHeaderValue.Parse("application/json") };
{{/net80OrLater}}
return accepts.Select(MediaTypeWithQualityHeaderValue.Parse);
}
/// <summary> /// <summary>
/// Provides a case-insensitive check that a provided content type is a known JSON-like content type. /// Provides a case-insensitive check that a provided content type is a known JSON-like content type.
/// </summary> /// </summary>

View File

@@ -1,5 +1,6 @@
// <auto-generated> // <auto-generated>
{{partial_header}} {{>partial_header}}
{{#nrt}} {{#nrt}}
#nullable enable #nullable enable

View File

@@ -1,3 +1,4 @@
{{>partial_header}}
using System; using System;
namespace {{packageName}}.{{clientPackage}} namespace {{packageName}}.{{clientPackage}}

View File

@@ -98,7 +98,7 @@ namespace {{packageName}}.{{clientPackage}}
List<IHttpClientBuilder> builders = new List<IHttpClientBuilder>(); List<IHttpClientBuilder> builders = new List<IHttpClientBuilder>();
{{#apiInfo}}{{#apis}}builders.Add(_services.AddHttpClient<{{interfacePrefix}}{{classname}}, {{classname}}>(client)); {{#apiInfo}}{{#apis}}builders.Add(_services.AddHttpClient<{{interfacePrefix}}{{classname}}, {{classname}}>("{{packageName}}.{{apiPackage}}.{{interfacePrefix}}{{classname}}", client));
{{/apis}}{{/apiInfo}} {{/apis}}{{/apiInfo}}
if (builder != null) if (builder != null)
foreach (IHttpClientBuilder instance in builders) foreach (IHttpClientBuilder instance in builders)

View File

@@ -1,5 +1,6 @@
// <auto-generated> // <auto-generated>
{{partial_header}} {{>partial_header}}
{{#nrt}} {{#nrt}}
#nullable enable #nullable enable

View File

@@ -1,3 +1,4 @@
{{>partial_header}}
using System.Net.Http; using System.Net.Http;
namespace {{packageName}}.{{apiPackage}} namespace {{packageName}}.{{apiPackage}}

View File

@@ -1,5 +1,6 @@
// <auto-generated> // <auto-generated>
{{partial_header}} {{>partial_header}}
{{#nrt}} {{#nrt}}
#nullable enable #nullable enable

View File

@@ -1,5 +1,6 @@
// <auto-generated> // <auto-generated>
{{partial_header}} {{>partial_header}}
{{#nrt}} {{#nrt}}
#nullable enable #nullable enable

View File

@@ -1,6 +1,5 @@
// <auto-generated> // <auto-generated>
{{>partial_header}} {{>partial_header}}
{{#nrt}} {{#nrt}}
#nullable enable #nullable enable
@@ -17,21 +16,25 @@ namespace {{packageName}}.{{clientPackage}}
/// <typeparam name="TTokenBase"></typeparam> /// <typeparam name="TTokenBase"></typeparam>
{{>visibility}} class RateLimitProvider<TTokenBase> : TokenProvider<TTokenBase> where TTokenBase : TokenBase {{>visibility}} class RateLimitProvider<TTokenBase> : TokenProvider<TTokenBase> where TTokenBase : TokenBase
{ {
internal Dictionary<string, global::System.Threading.Channels.Channel<TTokenBase>> AvailableTokens { get; } = new{{^net70OrLater}} Dictionary<string, global::System.Threading.Channels.Channel<TTokenBase>>{{/net70OrLater}}(); /// <summary>
/// Dictionary mapping header names to channels of available tokens for rate limiting.
/// Each channel buffers tokens that have become available and are ready for use.
/// </summary>
protected internal Dictionary<string, global::System.Threading.Channels.Channel<TTokenBase>> AvailableTokens { get; } = new{{^net70OrLater}} Dictionary<string, global::System.Threading.Channels.Channel<TTokenBase>>{{/net70OrLater}}();
/// <summary> /// <summary>
/// Instantiates a ThrottledTokenProvider. Your tokens will be rate limited based on the token's timeout. /// Instantiates a ThrottledTokenProvider. Your tokens will be rate limited based on the token's timeout.
/// </summary> /// </summary>
/// <param name="container"></param> /// <param name="container"></param>
public RateLimitProvider(TokenContainer<TTokenBase> container) : base(container.Tokens) public RateLimitProvider(TokenContainer<TTokenBase> container) : base()
{ {
foreach(TTokenBase token in _tokens) foreach(TTokenBase token in container.Tokens)
token.StartTimer(token.Timeout ?? TimeSpan.FromMilliseconds(40)); token.StartTimer(token.Timeout ?? TimeSpan.FromMilliseconds(40));
{{#lambda.copy}} {{#lambda.copy}}
global::System.Threading.Channels.BoundedChannelOptions options = new global::System.Threading.Channels.BoundedChannelOptions(_tokens.Length) global::System.Threading.Channels.BoundedChannelOptions options = new global::System.Threading.Channels.BoundedChannelOptions(container.Tokens.Count)
{ {
FullMode = global::System.Threading.Channels.BoundedChannelFullMode.DropWrite FullMode = global::System.Threading.Channels.BoundedChannelFullMode.DropOldest
}; };
AvailableTokens.Add(string.Empty, global::System.Threading.Channels.Channel.CreateBounded<TTokenBase>(options)); AvailableTokens.Add(string.Empty, global::System.Threading.Channels.Channel.CreateBounded<TTokenBase>(options));
@@ -45,7 +48,7 @@ namespace {{packageName}}.{{clientPackage}}
{ {
global::System.Threading.Channels.BoundedChannelOptions options = new global::System.Threading.Channels.BoundedChannelOptions(apiKeyTokenContainer.Tokens.Count(t => ClientUtils.ApiKeyHeaderToString(t.Header).Equals(header))) global::System.Threading.Channels.BoundedChannelOptions options = new global::System.Threading.Channels.BoundedChannelOptions(apiKeyTokenContainer.Tokens.Count(t => ClientUtils.ApiKeyHeaderToString(t.Header).Equals(header)))
{ {
FullMode = global::System.Threading.Channels.BoundedChannelFullMode.DropWrite FullMode = global::System.Threading.Channels.BoundedChannelFullMode.DropOldest
}; };
AvailableTokens.Add(header, global::System.Threading.Channels.Channel.CreateBounded<TTokenBase>(options)); AvailableTokens.Add(header, global::System.Threading.Channels.Channel.CreateBounded<TTokenBase>(options));
@@ -65,7 +68,7 @@ namespace {{packageName}}.{{clientPackage}}
{{/hasApiKeyMethods}} {{/hasApiKeyMethods}}
foreach (var availableToken in AvailableTokens) foreach (var availableToken in AvailableTokens)
foreach(TTokenBase token in _tokens) foreach(TTokenBase token in container.Tokens)
{ {
{{#hasApiKeyMethods}} {{#hasApiKeyMethods}}
if (token is ApiKeyToken apiKeyToken) if (token is ApiKeyToken apiKeyToken)

View File

@@ -1,5 +1,6 @@
// <auto-generated> // <auto-generated>
{{partial_header}} {{>partial_header}}
{{#nrt}} {{#nrt}}
#nullable enable #nullable enable
@@ -17,11 +18,18 @@ namespace {{packageName}}.{{clientPackage}}
private object _nextAvailableLock = new object(); private object _nextAvailableLock = new object();
private readonly System.Timers.Timer _timer = new System.Timers.Timer(); private readonly System.Timers.Timer _timer = new System.Timers.Timer();
internal TimeSpan? Timeout { get; set; } internal TimeSpan? Timeout { get; set; }
internal delegate void TokenBecameAvailableEventHandler(object sender);
internal event TokenBecameAvailableEventHandler{{nrt?}} TokenBecameAvailable;
/// <summary>
/// Delegate for token availability notification events.
/// </summary>
/// <param name="sender">The token that became available.</param>
public delegate void TokenBecameAvailableEventHandler(object sender);
/// <summary>
/// Event raised when a rate-limited token becomes available for use.
/// </summary>
public event TokenBecameAvailableEventHandler{{nrt?}} TokenBecameAvailable;
/// <summary> /// <summary>
/// Initialize a TokenBase object. /// Initialize a TokenBase object.
@@ -35,7 +43,6 @@ namespace {{packageName}}.{{clientPackage}}
StartTimer(Timeout.Value); StartTimer(Timeout.Value);
} }
/// <summary> /// <summary>
/// Starts the token's timer /// Starts the token's timer
/// </summary> /// </summary>

View File

@@ -1,5 +1,6 @@
// <auto-generated> // <auto-generated>
{{partial_header}} {{>partial_header}}
{{#nrt}} {{#nrt}}
#nullable enable #nullable enable

View File

@@ -1,6 +1,5 @@
// <auto-generated> // <auto-generated>
{{>partial_header}} {{>partial_header}}
{{#nrt}} {{#nrt}}
#nullable enable #nullable enable
@@ -18,24 +17,11 @@ namespace {{packageName}}
{{>visibility}} abstract class TokenProvider<TTokenBase> where TTokenBase : TokenBase {{>visibility}} abstract class TokenProvider<TTokenBase> where TTokenBase : TokenBase
{ {
/// <summary> /// <summary>
/// The array of tokens. /// Gets a token asynchronously for the specified header.
/// </summary> /// </summary>
protected TTokenBase[] _tokens; /// <param name="header">The header name to retrieve a token for. Empty string for non-API-key authentication schemes.</param>
/// <param name="cancellation">Cancellation token for the asynchronous operation.</param>
/// <summary> /// <returns>A task that returns the requested token.</returns>
/// Gets an authentication token to be used in request authorization.
/// </summary>
/// <param name="header"></param>
/// <param name="cancellation"></param>
protected internal abstract System.Threading.Tasks.ValueTask<TTokenBase> GetAsync(string header = "", System.Threading.CancellationToken cancellation = default{{^netstandard20OrLater}}(global::System.Threading.CancellationToken){{/netstandard20OrLater}}); protected internal abstract System.Threading.Tasks.ValueTask<TTokenBase> GetAsync(string header = "", System.Threading.CancellationToken cancellation = default{{^netstandard20OrLater}}(global::System.Threading.CancellationToken){{/netstandard20OrLater}});
/// <summary>
/// Instantiates a TokenProvider.
/// </summary>
/// <param name="tokens"></param>
public TokenProvider(IEnumerable<TTokenBase> tokens)
{
_tokens = tokens.ToArray();
}
} }
} }

View File

@@ -8,6 +8,7 @@
{{/nrt}} {{/nrt}}
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
{{#net80OrLater}} {{#net80OrLater}}
{{#lambda.uniqueLines}} {{#lambda.uniqueLines}}
{{#operations}} {{#operations}}
@@ -20,6 +21,7 @@ using System.Linq;
{{/lambda.uniqueLines}} {{/lambda.uniqueLines}}
{{/net80OrLater}} {{/net80OrLater}}
using System.Net; using System.Net;
using System.IO;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using System.Net.Http; using System.Net.Http;
@@ -605,10 +607,10 @@ namespace {{packageName}}.{{apiPackage}}
{{#produces}} {{#produces}}
{{#-first}} {{#-first}}
string{{nrt?}} acceptLocalVar = ClientUtils.SelectHeaderAccept(acceptLocalVars); IEnumerable<MediaTypeWithQualityHeaderValue> acceptHeaderValuesLocalVar = ClientUtils.SelectHeaderAcceptArray(acceptLocalVars);
if (acceptLocalVar != null) foreach (var acceptLocalVar in acceptHeaderValuesLocalVar)
httpRequestMessageLocalVar.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue(acceptLocalVar)); httpRequestMessageLocalVar.Headers.Accept.Add(acceptLocalVar);
{{/-first}} {{/-first}}
{{/produces}} {{/produces}}
{{#net60OrLater}} {{#net60OrLater}}

View File

@@ -36,13 +36,74 @@
<PackageReference Include="RestSharp" Version="112.0.0" /> <PackageReference Include="RestSharp" Version="112.0.0" />
{{/useRestSharp}} {{/useRestSharp}}
{{#useGenericHost}} {{#useGenericHost}}
<PackageReference Include="Microsoft.Extensions.Http" Version="{{#lambda.first}}{{#netStandard}}5.0.0 {{/netStandard}}{{#net47}}7.0.0 {{/net47}}{{#net48}}7.0.0 {{/net48}}{{#net6.0}}6.0.0 {{/net6.0}}{{#net7.0}}7.0.0 {{/net7.0}}{{#net8.0}}8.0.1 {{/net8.0}}{{#net9.0}}9.0.5 {{/net9.0}}{{#net10.0}}10.0.1 {{/net10.0}}{{/lambda.first}}" /> {{#netStandard}}
<PackageReference Include="Microsoft.Extensions.Hosting" Version="{{#lambda.first}}{{#netStandard}}5.0.0 {{/netStandard}}{{#net47}}7.0.0 {{/net47}}{{#net48}}7.0.0 {{/net48}}{{#net6.0}}6.0.1 {{/net6.0}}{{#net7.0}}7.0.1 {{/net7.0}}{{#net8.0}}8.0.1 {{/net8.0}}{{#net9.0}}9.0.5 {{/net9.0}}{{#net10.0}}10.0.1 {{/net10.0}}{{/lambda.first}}" /> <PackageReference Include="Microsoft.Extensions.Http" Condition="'$(TargetFramework)' == 'netstandard1.3' or '$(TargetFramework)' == 'netstandard1.4' or '$(TargetFramework)' == 'netstandard1.5' or '$(TargetFramework)' == 'netstandard1.6' or '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1'" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Condition="'$(TargetFramework)' == 'netstandard1.3' or '$(TargetFramework)' == 'netstandard1.4' or '$(TargetFramework)' == 'netstandard1.5' or '$(TargetFramework)' == 'netstandard1.6' or '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1'" Version="6.0.1" />
{{/netStandard}}
{{#net47}}
<PackageReference Include="Microsoft.Extensions.Http" Condition="'$(TargetFramework)' == 'net47' or '$(TargetFramework)' == 'net471' or '$(TargetFramework)' == 'net472'" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Condition="'$(TargetFramework)' == 'net47' or '$(TargetFramework)' == 'net471' or '$(TargetFramework)' == 'net472'" Version="7.0.0" />
{{/net47}}
{{#net48}}
<PackageReference Include="Microsoft.Extensions.Http" Condition="'$(TargetFramework)' == 'net48' or '$(TargetFramework)' == 'net481'" Version="7.0.0" />
<PackageReference Include="Microsoft.Extensions.Hosting" Condition="'$(TargetFramework)' == 'net48' or '$(TargetFramework)' == 'net481'" Version="7.0.0" />
{{/net48}}
{{#net6.0}}
<PackageReference Include="Microsoft.Extensions.Http" Condition="'$(TargetFramework)' == 'net6.0'" Version="6.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Condition="'$(TargetFramework)' == 'net6.0'" Version="6.0.1" />
{{/net6.0}}
{{#net7.0}}
<PackageReference Include="Microsoft.Extensions.Http" Condition="'$(TargetFramework)' == 'net7.0'" Version=7.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Condition="'$(TargetFramework)' == 'net7.0'" Version="7.0.1" />
{{/net7.0}}
{{#net8.0}}
<PackageReference Include="Microsoft.Extensions.Http" Condition="'$(TargetFramework)' == 'net8.0'" Version="8.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Condition="'$(TargetFramework)' == 'net8.0'" Version="8.0.1" />
{{/net8.0}}
{{#net9.0}}
<PackageReference Include="Microsoft.Extensions.Http" Condition="'$(TargetFramework)' == 'net9.0'" Version="9.0.6" />
<PackageReference Include="Microsoft.Extensions.Hosting" Condition="'$(TargetFramework)' == 'net9.0'" Version="9.0.6" />
{{/net9.0}}
{{#net10.0}}
<PackageReference Include="Microsoft.Extensions.Http" Condition="'$(TargetFramework)' == 'net10.0'" Version="10.0.1" />
<PackageReference Include="Microsoft.Extensions.Hosting" Condition="'$(TargetFramework)' == 'net10.0'" Version="10.0.1" />
{{/net10.0}}
{{#supportsRetry}} {{#supportsRetry}}
<PackageReference Include="Microsoft.Extensions.Http.Polly" Version="{{#lambda.first}}{{#netStandard}}5.0.1 {{/netStandard}}{{#net47}}7.0.0 {{/net47}}{{#net48}}7.0.0 {{/net48}}{{#net6.0}}6.0.19 {{/net6.0}}{{#net7.0}}7.0.11 {{/net7.0}}{{#net8.0}}8.0.8 {{/net8.0}}{{#net9.0}}9.0.5 {{/net9.0}}{{#net10.0}}10.0.1 {{/net10.0}}{{/lambda.first}}" /> {{#netStandard}}
<PackageReference Include="Microsoft.Extensions.Http.Polly" Condition="'$(TargetFramework)' == 'netstandard1.3' or '$(TargetFramework)' == 'netstandard1.4' or '$(TargetFramework)' == 'netstandard1.5' or '$(TargetFramework)' == 'netstandard1.6' or '$(TargetFramework)' == 'netstandard2.0' or '$(TargetFramework)' == 'netstandard2.1'" Version="5.0.1" />
{{/netStandard}}
{{#net47}}
<PackageReference Include="Microsoft.Extensions.Http.Polly" Condition="'$(TargetFramework)' == 'net47' or '$(TargetFramework)' == 'net471' or '$(TargetFramework)' == 'net472'" Version="7.0.0" />
{{/net47}}
{{#net48}}
<PackageReference Include="Microsoft.Extensions.Http.Polly" Condition="'$(TargetFramework)' == 'net48' or '$(TargetFramework)' == 'net481'" Version="7.0.0" />
{{/net48}}
{{#net6.0}}
<PackageReference Include="Microsoft.Extensions.Http.Polly" Condition="'$(TargetFramework)' == 'net6.0'" Version="6.0.36" />
{{/net6.0}}
{{#net7.0}}
<PackageReference Include="Microsoft.Extensions.Http.Polly" Condition="'$(TargetFramework)' == 'net7.0'" Version="7.0.20" />
{{/net7.0}}
{{#net8.0}}
<PackageReference Include="Microsoft.Extensions.Http.Polly" Condition="'$(TargetFramework)' == 'net8.0'" Version="8.0.20" />
{{/net8.0}}
{{#net9.0}}
<PackageReference Include="Microsoft.Extensions.Http.Polly" Condition="'$(TargetFramework)' == 'net9.0'" Version="9.0.6" />
{{/net9.0}}
{{#net10.0}}
<PackageReference Include="Microsoft.Extensions.Http.Polly" Condition="'$(TargetFramework)' == 'net10.0'" Version="10.0.1" />
{{/net10.0}}
{{/supportsRetry}} {{/supportsRetry}}
{{#net80OrLater}} {{#net80OrLater}}
<PackageReference Include="Microsoft.Net.Http.Headers" Version="{{#lambda.first}}{{#net8.0}}8.0.8 {{/net8.0}}{{#net9.0}}9.0.5 {{/net9.0}}{{#net10.0}}10.0.1 {{/net10.0}}{{/lambda.first}}" /> {{#net8.0}}
<PackageReference Include="Microsoft.Net.Http.Headers" Condition="'$(TargetFramework)' == 'net8.0'" Version="8.0.17" />
{{/net8.0}}
{{#net9.0}}
<PackageReference Include="Microsoft.Net.Http.Headers" Condition="'$(TargetFramework)' == 'net9.0'" Version="9.0.6" />
{{/net9.0}}
{{#net10.0}}
<PackageReference Include="Microsoft.Net.Http.Headers" Condition="'$(TargetFramework)' == 'net10.0'" Version="10.0.1" />
{{/net10.0}}
{{/net80OrLater}} {{/net80OrLater}}
{{^net60OrLater}} {{^net60OrLater}}
<PackageReference Include="System.Threading.Channels" Version="8.0.0" /> <PackageReference Include="System.Threading.Channels" Version="8.0.0" />

View File

@@ -1,3 +1,3 @@
{{#isBodyParam}}<div class="param">{{baseName}} {{#baseType}}<a href="#{{baseType}}">{{baseType}}</a>{{/baseType}} {{^required}}(optional){{/required}}{{#required}}(required){{/required}}</div> {{#isBodyParam}}<div class="param">{{baseName}} {{#isContainer}}{{containerType}}[{{/isContainer}}{{#baseType}}<a href="#{{baseType}}">{{baseType}}</a>{{/baseType}}{{#isContainer}}]{{/isContainer}} {{^required}}(optional){{/required}}{{#required}}(required){{/required}}</div>
<div class="param-desc"><span class="param-type">Body Parameter</span> &mdash; {{unescapedDescription}} {{#defaultValue}}default: {{{.}}}{{/defaultValue}}</div>{{/isBodyParam}} <div class="param-desc"><span class="param-type">Body Parameter</span> &mdash; {{unescapedDescription}} {{#defaultValue}}default: {{{.}}}{{/defaultValue}}</div>{{/isBodyParam}}

View File

@@ -29,7 +29,7 @@
<version.logback>1.5.19</version.logback> <version.logback>1.5.19</version.logback>
<version.junit>4.13.2</version.junit> <version.junit>4.13.2</version.junit>
<version.mockito>2.1.0-beta.124</version.mockito> <version.mockito>2.1.0-beta.124</version.mockito>
<version.undertow>2.3.20.Final</version.undertow> <version.undertow>2.3.21.Final</version.undertow>
<version.jsonpath>2.2.0</version.jsonpath> <version.jsonpath>2.2.0</version.jsonpath>
<version.httpclient>4.5.13</version.httpclient> <version.httpclient>4.5.13</version.httpclient>
<version.httpasyncclient>4.1.2</version.httpasyncclient> <version.httpasyncclient>4.1.2</version.httpasyncclient>

View File

@@ -22,7 +22,7 @@ orjson==3.9.15
promise==2.3 promise==2.3
pydantic>=2 pydantic>=2
python-dotenv==0.17.1 python-dotenv==0.17.1
python-multipart==0.0.18 python-multipart==0.0.22
PyYAML>=5.4.1,<6.1.0 PyYAML>=5.4.1,<6.1.0
requests==2.32.4 requests==2.32.4
Rx==1.6.1 Rx==1.6.1

View File

@@ -142,10 +142,13 @@
#' @param data_file (optional) name of the data file to save the result #' @param data_file (optional) name of the data file to save the result
{{/returnType}} {{/returnType}}
#' @param ... Other optional arguments #' @param ... Other optional arguments
{{#returnType}}
#' @param .parse Logical. If \code{TRUE} then the response will be parsed to a generated type. If \code{FALSE} the response will be returned as unparsed text.
{{/returnType}}
#' #'
#' @return {{{returnType}}}{{^returnType}}void{{/returnType}} #' @return {{{returnType}}}{{^returnType}}void{{/returnType}}
{{{operationId}}} = function({{#requiredParams}}{{paramName}}, {{/requiredParams}}{{#optionalParams}}{{paramName}} = {{^defaultValue}}NULL{{/defaultValue}}{{{defaultValue}}}, {{/optionalParams}}{{#vendorExtensions.x-streaming}}stream_callback = NULL, {{/vendorExtensions.x-streaming}}{{#returnType}}data_file = NULL, {{/returnType}}...) { {{{operationId}}} = function({{#requiredParams}}{{paramName}}, {{/requiredParams}}{{#optionalParams}}{{paramName}} = {{^defaultValue}}NULL{{/defaultValue}}{{{defaultValue}}}, {{/optionalParams}}{{#vendorExtensions.x-streaming}}stream_callback = NULL, {{/vendorExtensions.x-streaming}}{{#returnType}}data_file = NULL, {{/returnType}}...{{#returnType}}, .parse = TRUE{{/returnType}}) {
local_var_response <- self${{{operationId}}}{{WithHttpInfo}}({{#allParams}}{{paramName}}, {{/allParams}}{{#vendorExtensions.x-streaming}}stream_callback = stream_callback, {{/vendorExtensions.x-streaming}}{{#returnType}}data_file = data_file, {{/returnType}}...) local_var_response <- self${{{operationId}}}{{WithHttpInfo}}({{#allParams}}{{paramName}}, {{/allParams}}{{#vendorExtensions.x-streaming}}stream_callback = stream_callback, {{/vendorExtensions.x-streaming}}{{#returnType}}data_file = data_file, {{/returnType}}...{{#returnType}}, .parse = .parse{{/returnType}})
{{#vendorExtensions.x-streaming}} {{#vendorExtensions.x-streaming}}
if (typeof(stream_callback) == "closure") { # return void if streaming is enabled if (typeof(stream_callback) == "closure") { # return void if streaming is enabled
return(invisible(NULL)) return(invisible(NULL))
@@ -178,9 +181,12 @@
#' @param data_file (optional) name of the data file to save the result #' @param data_file (optional) name of the data file to save the result
{{/returnType}} {{/returnType}}
#' @param ... Other optional arguments #' @param ... Other optional arguments
{{#returnType}}
#' @param .parse Logical. If \code{TRUE} then the response will be parsed to a generated type. If \code{FALSE} the response will be returned as unparsed text.
{{/returnType}}
#' #'
#' @return API response ({{{returnType}}}{{^returnType}}void{{/returnType}}) with additional information such as HTTP status code, headers #' @return API response ({{{returnType}}}{{^returnType}}void{{/returnType}}) with additional information such as HTTP status code, headers
{{{operationId}}}{{WithHttpInfo}} = function({{#requiredParams}}{{paramName}}, {{/requiredParams}}{{#optionalParams}}{{paramName}} = {{^defaultValue}}NULL{{/defaultValue}}{{{defaultValue}}}, {{/optionalParams}}{{#vendorExtensions.x-streaming}}stream_callback = NULL, {{/vendorExtensions.x-streaming}}{{#returnType}}data_file = NULL, {{/returnType}}...) { {{{operationId}}}{{WithHttpInfo}} = function({{#requiredParams}}{{paramName}}, {{/requiredParams}}{{#optionalParams}}{{paramName}} = {{^defaultValue}}NULL{{/defaultValue}}{{{defaultValue}}}, {{/optionalParams}}{{#vendorExtensions.x-streaming}}stream_callback = NULL, {{/vendorExtensions.x-streaming}}{{#returnType}}data_file = NULL, {{/returnType}}...{{#returnType}}, .parse = TRUE{{/returnType}}) {
args <- list(...) args <- list(...)
query_params <- list() query_params <- list()
header_params <- c() header_params <- c()
@@ -559,6 +565,10 @@
if (!is.null(data_file)) { if (!is.null(data_file)) {
self$api_client$WriteFile(local_var_resp, data_file) self$api_client$WriteFile(local_var_resp, data_file)
} }
if (!.parse) {
local_var_resp$content <- local_var_resp$response_as_text()
return(local_var_resp)
}
ApiResponse$new(content = content, response = resp, status_code = local_var_resp$status_code) ApiResponse$new(content = content, response = resp, status_code = local_var_resp$status_code)
{{/isPrimitiveType}} {{/isPrimitiveType}}
@@ -567,6 +577,10 @@
if (!is.null(data_file)) { if (!is.null(data_file)) {
self$api_client$WriteFile(local_var_resp, data_file) self$api_client$WriteFile(local_var_resp, data_file)
} }
if (!.parse) {
local_var_resp$content <- local_var_resp$response_as_text()
return(local_var_resp)
}
deserialized_resp_obj <- tryCatch( deserialized_resp_obj <- tryCatch(
self$api_client$DeserializeResponse(local_var_resp, "{{returnType}}"), self$api_client$DeserializeResponse(local_var_resp, "{{returnType}}"),

View File

@@ -106,6 +106,17 @@ impl std::ops::DerefMut for {{{classname}}} {
} }
} }
{{^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<serde_valid::validation::error::MinLengthError>> {
Ok(())
}
}
{{/hasConflictingModelNames}}
{{#exts.x-to-string-support}} {{#exts.x-to-string-support}}
{{#exts.x-is-string}} {{#exts.x-is-string}}
impl std::fmt::Display for {{{classname}}} { impl std::fmt::Display for {{{classname}}} {
@@ -364,13 +375,13 @@ pub struct {{{classname}}} {
)] )]
{{/hasConflictingModelNames}} {{/hasConflictingModelNames}}
{{/hasValidation}} {{/hasValidation}}
{{#required}}
{{^hasConflictingModelNames}}{{>validate}}{{/hasConflictingModelNames}} {{^hasConflictingModelNames}}{{>validate}}{{/hasConflictingModelNames}}
{{^hasConflictingModelNames}} {{^hasConflictingModelNames}}
{{#exts.x-needs-nested-validation}} {{#exts.x-needs-nested-validation}}
#[cfg_attr(feature = "validate", validate)] {{^minLength}}{{^maxLength}}{{^minItems}}{{^maxItems}}#[cfg_attr(feature = "validate", validate)]{{/maxItems}}{{/minItems}}{{/maxLength}}{{/minLength}}
{{/exts.x-needs-nested-validation}} {{/exts.x-needs-nested-validation}}
{{/hasConflictingModelNames}} {{/hasConflictingModelNames}}
{{#required}}
pub {{{name}}}: {{{dataType}}}, pub {{{name}}}: {{{dataType}}},
{{/required}} {{/required}}
{{^required}} {{^required}}
@@ -378,9 +389,10 @@ pub struct {{{classname}}} {
#[serde(deserialize_with = "swagger::nullable_format::deserialize_optional_nullable")] #[serde(deserialize_with = "swagger::nullable_format::deserialize_optional_nullable")]
#[serde(default = "swagger::nullable_format::default_optional_nullable")] #[serde(default = "swagger::nullable_format::default_optional_nullable")]
{{/isNullable}} {{/isNullable}}
{{^hasConflictingModelNames}}{{>validate}}{{/hasConflictingModelNames}}
{{^hasConflictingModelNames}} {{^hasConflictingModelNames}}
{{#exts.x-needs-nested-validation}} {{#exts.x-needs-nested-validation}}
#[cfg_attr(feature = "validate", validate)] {{^minLength}}{{^maxLength}}{{^minItems}}{{^maxItems}}#[cfg_attr(feature = "validate", validate)]{{/maxItems}}{{/minItems}}{{/maxLength}}{{/minLength}}
{{/exts.x-needs-nested-validation}} {{/exts.x-needs-nested-validation}}
{{/hasConflictingModelNames}} {{/hasConflictingModelNames}}
#[serde(skip_serializing_if="Option::is_none")] #[serde(skip_serializing_if="Option::is_none")]

View File

@@ -66,22 +66,22 @@ secrecy = "0.8.0"
{{/withAWSV4Signature}} {{/withAWSV4Signature}}
{{#reqwest}} {{#reqwest}}
{{^supportAsync}} {{^supportAsync}}
reqwest = { version = "^0.12", default-features = false, features = ["json", "blocking", "multipart"] } reqwest = { version = "^0.13", default-features = false, features = ["json", "blocking", "multipart", "query", "form"] }
{{#supportMiddleware}} {{#supportMiddleware}}
reqwest-middleware = { version = "^0.4", features = ["json", "blocking", "multipart"] } reqwest-middleware = { version = "^0.5", features = ["json", "multipart", "query", "form"] }
{{/supportMiddleware}} {{/supportMiddleware}}
{{/supportAsync}} {{/supportAsync}}
{{#supportAsync}} {{#supportAsync}}
{{#useAsyncFileStream}} {{#useAsyncFileStream}}
tokio = { version = "^1.46.0", features = ["fs"] } tokio = { version = "^1.46.0", features = ["fs"] }
tokio-util = { version = "^0.7", features = ["codec"] } tokio-util = { version = "^0.7", features = ["codec"] }
reqwest = { version = "^0.12", default-features = false, features = ["json", "multipart", "stream"] } reqwest = { version = "^0.13", default-features = false, features = ["json", "multipart", "stream", "query", "form"] }
{{/useAsyncFileStream}} {{/useAsyncFileStream}}
{{^useAsyncFileStream}} {{^useAsyncFileStream}}
reqwest = { version = "^0.12", default-features = false, features = ["json", "multipart"] } reqwest = { version = "^0.13", default-features = false, features = ["json", "multipart", "query", "form"] }
{{/useAsyncFileStream}} {{/useAsyncFileStream}}
{{#supportMiddleware}} {{#supportMiddleware}}
reqwest-middleware = { version = "^0.4", features = ["json", "multipart"] } reqwest-middleware = { version = "^0.5", features = ["json", "multipart", "query", "form"] }
{{/supportMiddleware}} {{/supportMiddleware}}
{{#supportTokenSource}} {{#supportTokenSource}}
async-trait = "^0.1" async-trait = "^0.1"
@@ -93,13 +93,13 @@ google-cloud-token = "^0.1"
[features] [features]
default = [{{#reqwestDefaultFeatures}}"{{.}}"{{^-last}}, {{/-last}}{{/reqwestDefaultFeatures}}] default = [{{#reqwestDefaultFeatures}}"{{.}}"{{^-last}}, {{/-last}}{{/reqwestDefaultFeatures}}]
native-tls = ["reqwest/native-tls"] native-tls = ["reqwest/native-tls"]
rustls-tls = ["reqwest/rustls-tls"] rustls = ["reqwest/rustls"]
{{/reqwest}} {{/reqwest}}
{{#reqwestTrait}} {{#reqwestTrait}}
async-trait = "^0.1" async-trait = "^0.1"
reqwest = { version = "^0.12", default-features = false, features = ["json", "multipart", "stream"] } reqwest = { version = "^0.13", default-features = false, features = ["json", "multipart", "stream", "query", "form"] }
{{#supportMiddleware}} {{#supportMiddleware}}
reqwest-middleware = { version = "^0.4", features = ["json", "multipart"] } reqwest-middleware = { version = "^0.5", features = ["json", "multipart", "query", "form"] }
{{/supportMiddleware}} {{/supportMiddleware}}
{{#supportTokenSource}} {{#supportTokenSource}}
# TODO: propose to Yoshidan to externalize this as non google related crate, so that it can easily be extended for other cloud providers. # TODO: propose to Yoshidan to externalize this as non google related crate, so that it can easily be extended for other cloud providers.
@@ -114,7 +114,7 @@ bon = { version = "2.3", optional = true }
[features] [features]
default = [{{#reqwestDefaultFeatures}}"{{.}}"{{^-last}}, {{/-last}}{{/reqwestDefaultFeatures}}] default = [{{#reqwestDefaultFeatures}}"{{.}}"{{^-last}}, {{/-last}}{{/reqwestDefaultFeatures}}]
native-tls = ["reqwest/native-tls"] native-tls = ["reqwest/native-tls"]
rustls-tls = ["reqwest/rustls-tls"] rustls = ["reqwest/rustls"]
{{#mockall}} {{#mockall}}
mockall = ["dep:mockall"] mockall = ["dep:mockall"]
{{/mockall}} {{/mockall}}

View File

@@ -7,7 +7,7 @@
import Foundation{{#useVapor}} import Foundation{{#useVapor}}
import Vapor{{/useVapor}} import Vapor{{/useVapor}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct APIHelper { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct APIHelper: Sendable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static func rejectNil(_ source: [String: (any Sendable)?]) -> [String: any Sendable]? { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static func rejectNil(_ source: [String: (any Sendable)?]) -> [String: any Sendable]? {
let destination = source.reduce(into: [String: any Sendable]()) { result, item in let destination = source.reduce(into: [String: any Sendable]()) { result, item in
if let value = item.value { if let value = item.value {

View File

@@ -19,8 +19,8 @@ import Alamofire{{/useAlamofire}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var basePath: String{{#useVapor}} {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var basePath: String{{#useVapor}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var customHeaders: HTTPHeaders {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var customHeaders: HTTPHeaders
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var apiClient: Vapor.Client? {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var apiClient: Vapor.Client?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var apiWrapper: (inout Vapor.ClientRequest) throws -> () {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var apiWrapper: @Sendable (inout Vapor.ClientRequest) throws -> ()
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var contentConfiguration{{/useVapor}}{{^useVapor}} {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var contentConfiguration: ContentConfiguration{{/useVapor}}{{^useVapor}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var customHeaders: [String: String] {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var customHeaders: [String: String]
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var credential: URLCredential? {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var credential: URLCredential?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var requestBuilderFactory: RequestBuilderFactory {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var requestBuilderFactory: RequestBuilderFactory
@@ -49,8 +49,8 @@ import Alamofire{{/useAlamofire}}
basePath: String = "{{{basePath}}}",{{#useVapor}} basePath: String = "{{{basePath}}}",{{#useVapor}}
customHeaders: HTTPHeaders = [:], customHeaders: HTTPHeaders = [:],
apiClient: Vapor.Client? = nil, apiClient: Vapor.Client? = nil,
apiWrapper: (inout Vapor.ClientRequest) throws -> () = { _ in }, apiWrapper: @escaping @Sendable (inout Vapor.ClientRequest) throws -> () = { _ in },
contentConfiguration = ContentConfiguration.default(){{/useVapor}}{{^useVapor}} contentConfiguration: ContentConfiguration = ContentConfiguration.default(){{/useVapor}}{{^useVapor}}
customHeaders: [String: String] = [:], customHeaders: [String: String] = [:],
credential: URLCredential? = nil, credential: URLCredential? = nil,
requestBuilderFactory: RequestBuilderFactory = {{#useAlamofire}}AlamofireRequestBuilderFactory(){{/useAlamofire}}{{#useURLSession}}URLSessionRequestBuilderFactory(){{/useURLSession}}, requestBuilderFactory: RequestBuilderFactory = {{#useAlamofire}}AlamofireRequestBuilderFactory(){{/useAlamofire}}{{#useURLSession}}URLSessionRequestBuilderFactory(){{/useURLSession}},
@@ -63,10 +63,10 @@ import Alamofire{{/useAlamofire}}
stringResponseSerializer: AnyResponseSerializer<String> = AnyResponseSerializer(StringResponseSerializer()){{/useAlamofire}}{{/useVapor}} stringResponseSerializer: AnyResponseSerializer<String> = AnyResponseSerializer(StringResponseSerializer()){{/useAlamofire}}{{/useVapor}}
) { ) {
self.basePath = basePath{{#useVapor}} self.basePath = basePath{{#useVapor}}
customHeaders = customHeaders self.customHeaders = customHeaders
apiClient = apiClient self.apiClient = apiClient
apiWrapper = apiWrapper self.apiWrapper = apiWrapper
contentConfiguration = contentConfiguration{{/useVapor}}{{^useVapor}} self.contentConfiguration = contentConfiguration{{/useVapor}}{{^useVapor}}
self.customHeaders = customHeaders self.customHeaders = customHeaders
self.credential = credential self.credential = credential
self.requestBuilderFactory = requestBuilderFactory self.requestBuilderFactory = requestBuilderFactory
@@ -82,7 +82,7 @@ import Alamofire{{/useAlamofire}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static let shared = {{projectName}}APIConfiguration() {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} static let shared = {{projectName}}APIConfiguration()
}{{^useVapor}} }{{^useVapor}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class RequestBuilder<T>: @unchecked Sendable, Identifiable { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class RequestBuilder<T: Sendable>: @unchecked Sendable, Identifiable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var credential: URLCredential? {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var credential: URLCredential?
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var headers: [String: String] {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var headers: [String: String]
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let parameters: [String: any Sendable]? {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} let parameters: [String: any Sendable]?
@@ -119,9 +119,21 @@ import Alamofire{{/useAlamofire}}
} }
{{#useAsyncAwait}} {{#useAsyncAwait}}
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *) #if compiler(>=6.2)
@concurrent
@discardableResult @discardableResult
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func execute() async throws(ErrorResponse) -> Response<T> { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func execute() async throws(ErrorResponse) -> Response<T> {
try await _execute()
}
#else
@discardableResult
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} func execute() async throws(ErrorResponse) -> Response<T> {
try await _execute()
}
#endif
@discardableResult
private func _execute() async throws(ErrorResponse) -> Response<T> {
do { do {
let requestTask = self.requestTask let requestTask = self.requestTask
return try await withTaskCancellationHandler { return try await withTaskCancellationHandler {
@@ -135,7 +147,6 @@ import Alamofire{{/useAlamofire}}
self.execute { result in self.execute { result in
switch result { switch result {
case let .success(response): case let .success(response):
nonisolated(unsafe) let response = response
continuation.resume(returning: response) continuation.resume(returning: response)
case let .failure(error): case let .failure(error):
continuation.resume(throwing: error) continuation.resume(throwing: error)
@@ -167,7 +178,7 @@ import Alamofire{{/useAlamofire}}
} }
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} protocol RequestBuilderFactory { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} protocol RequestBuilderFactory: Sendable {
func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type
func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type func getBuilder<T: Decodable>() -> RequestBuilder<T>.Type
}{{/useVapor}} }{{/useVapor}}

View File

@@ -236,13 +236,11 @@ extension RequestBuilder {
} }
}{{/usePromiseKit}}{{#useVapor}} }{{/usePromiseKit}}{{#useVapor}}
extension UUID: Content { } extension UUID: @retroactive Content { }
extension URL: Content { } extension URL: @retroactive Content { }
extension Bool: Content { } extension Set: @retroactive ResponseEncodable where Element: Content {
extension Set: ResponseEncodable where Element: Content {
public func encodeResponse(for request: Vapor.Request) -> EventLoopFuture<Vapor.Response> { public func encodeResponse(for request: Vapor.Request) -> EventLoopFuture<Vapor.Response> {
let response = Vapor.Response() let response = Vapor.Response()
do { do {
@@ -254,7 +252,15 @@ extension Set: ResponseEncodable where Element: Content {
} }
} }
extension Set: RequestDecodable where Element: Content { extension Set: @retroactive AsyncResponseEncodable where Element: Content {
public func encodeResponse(for request: Vapor.Request) async throws -> Vapor.Response {
let response = Vapor.Response()
try response.content.encode(Array(self))
return response
}
}
extension Set: @retroactive RequestDecodable where Element: Content {
public static func decodeRequest(_ request: Vapor.Request) -> EventLoopFuture<Self> { public static func decodeRequest(_ request: Vapor.Request) -> EventLoopFuture<Self> {
do { do {
let content = try request.content.decode([Element].self) let content = try request.content.decode([Element].self)
@@ -265,6 +271,13 @@ extension Set: RequestDecodable where Element: Content {
} }
} }
extension Set: Content where Element: Content { } extension Set: @retroactive AsyncRequestDecodable where Element: Content {
public static func decodeRequest(_ request: Vapor.Request) async throws -> Self {
let content = try request.content.decode([Element].self)
return Set(content)
}
}
extension Set: @retroactive Content where Element: Content { }
extension JSONValue: Content {}{{/useVapor}} extension JSONValue: Content {}{{/useVapor}}

View File

@@ -70,11 +70,11 @@ extension NullEncodable: Codable where Wrapped: Codable {
} }
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum ErrorResponse: Error { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum ErrorResponse: Error, Sendable {
case error(Int, Data?, URLResponse?, Error) case error(Int, Data?, URLResponse?, Error)
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum DownloadException: Error { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum DownloadException: Error, Sendable {
case responseDataMissing case responseDataMissing
case responseFailed case responseFailed
case requestMissing case requestMissing
@@ -82,7 +82,7 @@ extension NullEncodable: Codable where Wrapped: Codable {
case requestMissingURL case requestMissingURL
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum DecodableRequestBuilderError: Error { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum DecodableRequestBuilderError: Error, Sendable {
case emptyDataResponse case emptyDataResponse
case nilHTTPResponse case nilHTTPResponse
case unsuccessfulHTTPStatusCode case unsuccessfulHTTPStatusCode

View File

@@ -9,10 +9,10 @@ let package = Package(
.macOS(.v10_15), .macOS(.v10_15),
{{/useVapor}} {{/useVapor}}
{{^useVapor}} {{^useVapor}}
.iOS(.v12), .iOS(.v13),
.macOS(.v10_13), .macOS(.v10_15),
.tvOS(.v12), .tvOS(.v13),
.watchOS(.v4), .watchOS(.v6),
{{/useVapor}} {{/useVapor}}
], ],
products: [ products: [
@@ -34,7 +34,7 @@ let package = Package(
.package(url: "https://github.com/ReactiveX/RxSwift", .upToNextMajor(from: "6.8.0")), .package(url: "https://github.com/ReactiveX/RxSwift", .upToNextMajor(from: "6.8.0")),
{{/useRxSwift}} {{/useRxSwift}}
{{#useVapor}} {{#useVapor}}
.package(url: "https://github.com/vapor/vapor", from: "4.0.0") .package(url: "https://github.com/vapor/vapor", from: "4.99.0"),
{{/useVapor}} {{/useVapor}}
], ],
targets: [ targets: [
@@ -42,7 +42,7 @@ let package = Package(
// Targets can depend on other targets in this package, and on products in packages which this package depends on. // Targets can depend on other targets in this package, and on products in packages which this package depends on.
.target( .target(
name: "{{projectName}}", name: "{{projectName}}",
dependencies: [{{#useVapor}}"Vapor", {{/useVapor}}{{#useAlamofire}}"Alamofire", {{/useAlamofire}}{{#usePromiseKit}}"PromiseKit", {{/usePromiseKit}}{{#useRxSwift}}"RxSwift"{{/useRxSwift}}], dependencies: [{{#useVapor}}.product(name: "Vapor", package: "vapor"){{/useVapor}}{{#useAlamofire}}"Alamofire", {{/useAlamofire}}{{#usePromiseKit}}"PromiseKit", {{/usePromiseKit}}{{#useRxSwift}}"RxSwift"{{/useRxSwift}}],
path: "{{swiftPackagePath}}{{^swiftPackagePath}}{{#useSPMFileStructure}}Sources/{{projectName}}{{/useSPMFileStructure}}{{^useSPMFileStructure}}{{projectName}}/Classes{{/useSPMFileStructure}}{{/swiftPackagePath}}" path: "{{swiftPackagePath}}{{^swiftPackagePath}}{{#useSPMFileStructure}}Sources/{{projectName}}{{/useSPMFileStructure}}{{^useSPMFileStructure}}{{projectName}}/Classes{{/useSPMFileStructure}}{{/swiftPackagePath}}"
), ),
], ],

View File

@@ -1,10 +1,10 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = '{{projectName}}'{{#projectDescription}} s.name = '{{projectName}}'{{#projectDescription}}
s.summary = '{{.}}'{{/projectDescription}} s.summary = '{{.}}'{{/projectDescription}}
s.ios.deployment_target = '12.0' s.ios.deployment_target = '13.0'
s.osx.deployment_target = '10.13' s.osx.deployment_target = '10.15'
s.tvos.deployment_target = '12.0' s.tvos.deployment_target = '13.0'
s.watchos.deployment_target = '4.0' s.watchos.deployment_target = '6.0'
s.version = '{{podVersion}}{{^podVersion}}{{#apiInfo}}{{version}}{{/apiInfo}}{{^apiInfo}}}0.0.1{{/apiInfo}}{{/podVersion}}' s.version = '{{podVersion}}{{^podVersion}}{{#apiInfo}}{{version}}{{/apiInfo}}{{^apiInfo}}}0.0.1{{/apiInfo}}{{/podVersion}}'
s.source = {{#podSource}}{{& podSource}}{{/podSource}}{{^podSource}}{ :git => 'git@github.com:OpenAPITools/openapi-generator.git', :tag => 'v{{#apiInfo}}{{version}}{{/apiInfo}}{{^apiInfo}}}0.0.1{{/apiInfo}}' }{{/podSource}} s.source = {{#podSource}}{{& podSource}}{{/podSource}}{{^podSource}}{ :git => 'git@github.com:OpenAPITools/openapi-generator.git', :tag => 'v{{#apiInfo}}{{version}}{{/apiInfo}}{{^apiInfo}}}0.0.1{{/apiInfo}}' }{{/podSource}}
{{#podAuthors}} {{#podAuthors}}

View File

@@ -27,23 +27,23 @@ extension NumericRule: Sendable where T: Sendable {}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var uniqueItems: Bool {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} var uniqueItems: Bool
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum StringValidationErrorKind: Error { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum StringValidationErrorKind: Error, Sendable {
case minLength, maxLength, pattern case minLength, maxLength, pattern
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum NumericValidationErrorKind: Error { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum NumericValidationErrorKind: Error, Sendable {
case minimum, maximum, multipleOf case minimum, maximum, multipleOf
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum ArrayValidationErrorKind: Error { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} enum ArrayValidationErrorKind: Error, Sendable {
case minItems, maxItems, uniqueItems case minItems, maxItems, uniqueItems
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct ValidationError<T: Error & Hashable>: Error { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct ValidationError<T: Error & Hashable & Sendable>: Error, Sendable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} fileprivate(set) var kinds: Set<T> {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} fileprivate(set) var kinds: Set<T>
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct Validator { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} struct Validator: Sendable {
/// Validate a string against a rule. /// Validate a string against a rule.
/// - Parameter string: The String you wish to validate. /// - Parameter string: The String you wish to validate.
/// - Parameter rule: The StringRule you wish to use for validation. /// - Parameter rule: The StringRule you wish to use for validation.

View File

@@ -8,9 +8,7 @@
import Foundation{{#usePromiseKit}} import Foundation{{#usePromiseKit}}
@preconcurrency import PromiseKit{{/usePromiseKit}}{{#useRxSwift}} @preconcurrency import PromiseKit{{/usePromiseKit}}{{#useRxSwift}}
@preconcurrency import RxSwift{{/useRxSwift}}{{#useCombine}} @preconcurrency import RxSwift{{/useRxSwift}}{{#useCombine}}
#if canImport(Combine) import Combine{{/useCombine}}{{#useVapor}}
import Combine
#endif{{/useCombine}}{{#useVapor}}
import Vapor{{/useVapor}}{{#swiftUseApiNamespace}} import Vapor{{/useVapor}}{{#swiftUseApiNamespace}}
extension {{projectName}}API { extension {{projectName}}API {
@@ -94,9 +92,7 @@ extension {{projectName}}API {
- parameter apiConfiguration: The configuration for the http request.{{/apiStaticMethod}} - parameter apiConfiguration: The configuration for the http request.{{/apiStaticMethod}}
- returns: Promise<{{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Void{{/returnType}}> - returns: Promise<{{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Void{{/returnType}}>
*/ */
{{#isDeprecated}} @available(*, deprecated, message: "{{#isDeprecated}}This operation is deprecated. | {{/isDeprecated}}NOTICE: We are considering deprecating PromiseKit support in the Swift 6 generator. If you are still using it, please share your use case here: https://github.com/OpenAPITools/openapi-generator/issues/22791")
@available(*, deprecated, message: "This operation is deprecated.")
{{/isDeprecated}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} {{#apiStaticMethod}}class {{/apiStaticMethod}}func {{operationId}}({{#allParams}}{{paramName}}: {{#isEnum}}{{#isContainer}}[{{enumName}}_{{operationId}}]{{/isContainer}}{{^isContainer}}{{enumName}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{^-last}}, {{/-last}}{{/allParams}}{{#apiStaticMethod}}{{#hasParams}}, {{/hasParams}}apiConfiguration: {{projectName}}APIConfiguration = {{projectName}}APIConfiguration.shared{{/apiStaticMethod}}) -> Promise<{{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Void{{/returnType}}> { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} {{#apiStaticMethod}}class {{/apiStaticMethod}}func {{operationId}}({{#allParams}}{{paramName}}: {{#isEnum}}{{#isContainer}}[{{enumName}}_{{operationId}}]{{/isContainer}}{{^isContainer}}{{enumName}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{^-last}}, {{/-last}}{{/allParams}}{{#apiStaticMethod}}{{#hasParams}}, {{/hasParams}}apiConfiguration: {{projectName}}APIConfiguration = {{projectName}}APIConfiguration.shared{{/apiStaticMethod}}) -> Promise<{{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Void{{/returnType}}> {
let deferred = Promise<{{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Void{{/returnType}}>.pending() let deferred = Promise<{{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Void{{/returnType}}>.pending()
{{operationId}}WithRequestBuilder({{#allParams}}{{paramName}}: {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#apiStaticMethod}}{{#hasParams}}, {{/hasParams}}apiConfiguration: apiConfiguration{{/apiStaticMethod}}).execute { result in {{operationId}}WithRequestBuilder({{#allParams}}{{paramName}}: {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#apiStaticMethod}}{{#hasParams}}, {{/hasParams}}apiConfiguration: apiConfiguration{{/apiStaticMethod}}).execute { result in
@@ -163,11 +159,9 @@ extension {{projectName}}API {
- parameter apiConfiguration: The configuration for the http request.{{/apiStaticMethod}} - parameter apiConfiguration: The configuration for the http request.{{/apiStaticMethod}}
- returns: AnyPublisher<{{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Void{{/returnType}}, Error> - returns: AnyPublisher<{{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Void{{/returnType}}, Error>
*/ */
#if canImport(Combine)
{{#isDeprecated}} {{#isDeprecated}}
@available(*, deprecated, message: "This operation is deprecated.") @available(*, deprecated, message: "This operation is deprecated.")
{{/isDeprecated}} {{/isDeprecated}}
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} {{#apiStaticMethod}}class {{/apiStaticMethod}}func {{operationId}}({{#allParams}}{{paramName}}: {{#isEnum}}{{#isContainer}}[{{enumName}}_{{operationId}}]{{/isContainer}}{{^isContainer}}{{enumName}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{^-last}}, {{/-last}}{{/allParams}}{{#apiStaticMethod}}{{#hasParams}}, {{/hasParams}}apiConfiguration: {{projectName}}APIConfiguration = {{projectName}}APIConfiguration.shared{{/apiStaticMethod}}) -> AnyPublisher<{{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Void{{/returnType}}, Error> { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} {{#apiStaticMethod}}class {{/apiStaticMethod}}func {{operationId}}({{#allParams}}{{paramName}}: {{#isEnum}}{{#isContainer}}[{{enumName}}_{{operationId}}]{{/isContainer}}{{^isContainer}}{{enumName}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{^-last}}, {{/-last}}{{/allParams}}{{#apiStaticMethod}}{{#hasParams}}, {{/hasParams}}apiConfiguration: {{projectName}}APIConfiguration = {{projectName}}APIConfiguration.shared{{/apiStaticMethod}}) -> AnyPublisher<{{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{^returnType}}Void{{/returnType}}, Error> {
let requestBuilder = {{operationId}}WithRequestBuilder({{#allParams}}{{paramName}}: {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#apiStaticMethod}}{{#hasParams}}, {{/hasParams}}apiConfiguration: apiConfiguration{{/apiStaticMethod}}) let requestBuilder = {{operationId}}WithRequestBuilder({{#allParams}}{{paramName}}: {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#apiStaticMethod}}{{#hasParams}}, {{/hasParams}}apiConfiguration: apiConfiguration{{/apiStaticMethod}})
let requestTask = requestBuilder.requestTask let requestTask = requestBuilder.requestTask
@@ -197,7 +191,6 @@ extension {{projectName}}API {
.eraseToAnyPublisher() .eraseToAnyPublisher()
{{/combineDeferred}} {{/combineDeferred}}
} }
#endif
{{/useCombine}} {{/useCombine}}
{{#useAsyncAwait}} {{#useAsyncAwait}}
@@ -212,7 +205,6 @@ extension {{projectName}}API {
{{#isDeprecated}} {{#isDeprecated}}
@available(*, deprecated, message: "This operation is deprecated.") @available(*, deprecated, message: "This operation is deprecated.")
{{/isDeprecated}} {{/isDeprecated}}
@available(macOS 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} {{#apiStaticMethod}}class {{/apiStaticMethod}}func {{operationId}}({{#allParams}}{{paramName}}: {{#isEnum}}{{#isContainer}}[{{enumName}}_{{operationId}}]{{/isContainer}}{{^isContainer}}{{enumName}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{^-last}}, {{/-last}}{{/allParams}}{{#apiStaticMethod}}{{#hasParams}}, {{/hasParams}}apiConfiguration: {{projectName}}APIConfiguration = {{projectName}}APIConfiguration.shared{{/apiStaticMethod}}) async throws(ErrorResponse){{#returnType}} -> {{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{/returnType}} { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} {{#apiStaticMethod}}class {{/apiStaticMethod}}func {{operationId}}({{#allParams}}{{paramName}}: {{#isEnum}}{{#isContainer}}[{{enumName}}_{{operationId}}]{{/isContainer}}{{^isContainer}}{{enumName}}_{{operationId}}{{/isContainer}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{^-last}}, {{/-last}}{{/allParams}}{{#apiStaticMethod}}{{#hasParams}}, {{/hasParams}}apiConfiguration: {{projectName}}APIConfiguration = {{projectName}}APIConfiguration.shared{{/apiStaticMethod}}) async throws(ErrorResponse){{#returnType}} -> {{{returnType}}}{{#returnType}}{{#isResponseOptional}}?{{/isResponseOptional}}{{/returnType}}{{/returnType}} {
return try await {{operationId}}WithRequestBuilder({{#allParams}}{{paramName}}: {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#apiStaticMethod}}{{#hasParams}}, {{/hasParams}}apiConfiguration: apiConfiguration{{/apiStaticMethod}}).execute().body return try await {{operationId}}WithRequestBuilder({{#allParams}}{{paramName}}: {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#apiStaticMethod}}{{#hasParams}}, {{/hasParams}}apiConfiguration: apiConfiguration{{/apiStaticMethod}}).execute().body
} }
@@ -359,19 +351,19 @@ extension {{projectName}}API {
{{#isDeprecated}} {{#isDeprecated}}
@available(*, deprecated, message: "This operation is deprecated.") @available(*, deprecated, message: "This operation is deprecated.")
{{/isDeprecated}} {{/isDeprecated}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} {{#apiStaticMethod}}class {{/apiStaticMethod}}func {{operationId}}Raw({{#allParams}}{{paramName}}: {{#isEnum}}{{#isArray}}[{{enumName}}_{{operationId}}]{{/isArray}}{{^isArray}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}headers: HTTPHeaders = {{projectName}}APIConfiguration.shared.customHeaders, beforeSend: (inout ClientRequest) throws -> () = { _ in }) -> EventLoopFuture<ClientResponse> { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} {{#apiStaticMethod}}class {{/apiStaticMethod}}func {{operationId}}Raw({{#allParams}}{{paramName}}: {{#isEnum}}{{#isArray}}[{{enumName}}_{{operationId}}]{{/isArray}}{{^isArray}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}headers: HTTPHeaders? = nil, apiConfiguration: {{projectName}}APIConfiguration = {{projectName}}APIConfiguration.shared, beforeSend: (inout ClientRequest) throws -> () = { _ in }) -> EventLoopFuture<ClientResponse> {
{{^pathParams}}let{{/pathParams}}{{#pathParams}}{{#-first}}var{{/-first}}{{/pathParams}} localVariablePath = "{{{path}}}"{{#pathParams}} {{^pathParams}}let{{/pathParams}}{{#pathParams}}{{#-first}}var{{/-first}}{{/pathParams}} localVariablePath = "{{{path}}}"{{#pathParams}}
let {{paramName}}PreEscape = String(describing: {{#isEnum}}{{paramName}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}.rawValue{{/isContainer}}{{/isEnum}}{{^isEnum}}{{paramName}}{{/isEnum}}) let {{paramName}}PreEscape = String(describing: {{#isEnum}}{{paramName}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}.rawValue{{/isContainer}}{{/isEnum}}{{^isEnum}}{{paramName}}{{/isEnum}})
let {{paramName}}PostEscape = {{paramName}}PreEscape.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? "" let {{paramName}}PostEscape = {{paramName}}PreEscape.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? ""
localVariablePath = localVariablePath.replacingOccurrences(of: "{{=<% %>=}}{<%baseName%>}<%={{ }}=%>", with: {{paramName}}PostEscape, options: .literal, range: nil){{/pathParams}} localVariablePath = localVariablePath.replacingOccurrences(of: "{{=<% %>=}}{<%baseName%>}<%={{ }}=%>", with: {{paramName}}PostEscape, options: .literal, range: nil){{/pathParams}}
let localVariableURLString = apiConfiguration.basePath + localVariablePath let localVariableURLString = apiConfiguration.basePath + localVariablePath
guard let localVariableApiClient = {{#swiftUseApiNamespace}}{{projectName}}API.{{/swiftUseApiNamespace}}apiConfiguration.apiClient else { guard let localVariableApiClient = apiConfiguration.apiClient else {
fatalError("apiConfiguration.apiClient is not set.") fatalError("apiConfiguration.apiClient is not set.")
} }
return localVariableApiClient.send(.{{httpMethod}}, headers: headers, to: URI(string: localVariableURLString)) { localVariableRequest in return localVariableApiClient.send(.{{httpMethod}}, headers: headers ?? apiConfiguration.customHeaders, to: URI(string: localVariableURLString)) { localVariableRequest in
try {{#swiftUseApiNamespace}}{{projectName}}API.{{/swiftUseApiNamespace}}Configuration.apiWrapper(&localVariableRequest) try apiConfiguration.apiWrapper(&localVariableRequest)
{{#hasHeaderParams}}{{#headerParams}} {{#hasHeaderParams}}{{#headerParams}}
localVariableRequest.headers.add(name: "{{baseName}}", value: {{#isArray}}{{paramName}}{{^required}}?{{/required}}.map { $0{{#isEnum}}.rawValue{{/isEnum}}.description }.description{{/isArray}}{{^isArray}}{{#isEnum}}{{paramName}}{{^required}}?{{/required}}.rawValue.description{{/isEnum}}{{^isEnum}}{{paramName}}{{^required}}?{{/required}}.description{{/isEnum}}{{/isArray}}{{^required}} ?? ""{{/required}}) localVariableRequest.headers.add(name: "{{baseName}}", value: {{#isArray}}{{paramName}}{{^required}}?{{/required}}.map { $0{{#isEnum}}.rawValue{{/isEnum}}.description }.description{{/isArray}}{{^isArray}}{{#isEnum}}{{paramName}}{{^required}}?{{/required}}.rawValue.description{{/isEnum}}{{^isEnum}}{{paramName}}{{^required}}?{{/required}}.description{{/isEnum}}{{/isArray}}{{^required}} ?? ""{{/required}})
{{/headerParams}}{{/hasHeaderParams}} {{/headerParams}}{{/hasHeaderParams}}
@@ -439,8 +431,8 @@ extension {{projectName}}API {
{{#isDeprecated}} {{#isDeprecated}}
@available(*, deprecated, message: "This operation is deprecated.") @available(*, deprecated, message: "This operation is deprecated.")
{{/isDeprecated}} {{/isDeprecated}}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} {{#apiStaticMethod}}class {{/apiStaticMethod}}func {{operationId}}({{#allParams}}{{paramName}}: {{#isEnum}}{{#isArray}}[{{enumName}}_{{operationId}}]{{/isArray}}{{^isArray}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}headers: HTTPHeaders = {{projectName}}APIConfiguration.shared.customHeaders, beforeSend: (inout ClientRequest) throws -> () = { _ in }) -> EventLoopFuture<{{#lambda.titlecase}}{{operationId}}{{/lambda.titlecase}}> { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} {{#apiStaticMethod}}class {{/apiStaticMethod}}func {{operationId}}({{#allParams}}{{paramName}}: {{#isEnum}}{{#isArray}}[{{enumName}}_{{operationId}}]{{/isArray}}{{^isArray}}{{#isContainer}}{{{dataType}}}{{/isContainer}}{{^isContainer}}{{{datatypeWithEnum}}}_{{operationId}}{{/isContainer}}{{/isArray}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}{{^required}}? = nil{{/required}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}headers: HTTPHeaders? = nil, apiConfiguration: {{projectName}}APIConfiguration = {{projectName}}APIConfiguration.shared, beforeSend: (inout ClientRequest) throws -> () = { _ in }) -> EventLoopFuture<{{#lambda.titlecase}}{{operationId}}{{/lambda.titlecase}}> {
return {{operationId}}Raw({{#allParams}}{{paramName}}: {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}headers: headers, beforeSend: beforeSend).flatMapThrowing { response -> {{#lambda.titlecase}}{{operationId}}{{/lambda.titlecase}} in return {{operationId}}Raw({{#allParams}}{{paramName}}: {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}headers: headers, apiConfiguration: apiConfiguration, beforeSend: beforeSend).flatMapThrowing { response -> {{#lambda.titlecase}}{{operationId}}{{/lambda.titlecase}} in
switch response.status.code { switch response.status.code {
{{#responses}} {{#responses}}
{{#isDefault}}default{{/isDefault}}{{^isDefault}}case {{code}}{{/isDefault}}: {{#isDefault}}default{{/isDefault}}{{^isDefault}}case {{code}}{{/isDefault}}:

View File

@@ -7,7 +7,7 @@
import Foundation import Foundation
import Alamofire import Alamofire
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} class AlamofireRequestBuilderFactory: RequestBuilderFactory { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} final class AlamofireRequestBuilderFactory: RequestBuilderFactory, Sendable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init() {} {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init() {}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
@@ -27,7 +27,7 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable {
var managerStore = SynchronizedDictionary<String, Alamofire.Session>() var managerStore = SynchronizedDictionary<String, Alamofire.Session>()
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class AlamofireRequestBuilder<T>: RequestBuilder<T>, @unchecked Sendable { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class AlamofireRequestBuilder<T: Sendable>: RequestBuilder<T>, @unchecked Sendable {
required {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(method: String, URLString: String, parameters: [String: any Sendable]?, headers: [String: String] = [:], requiresAuthentication: Bool, apiConfiguration: {{projectName}}APIConfiguration = {{projectName}}APIConfiguration.shared) { required {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(method: String, URLString: String, parameters: [String: any Sendable]?, headers: [String: String] = [:], requiresAuthentication: Bool, apiConfiguration: {{projectName}}APIConfiguration = {{projectName}}APIConfiguration.shared) {
super.init(method: method, URLString: URLString, parameters: parameters, headers: headers, requiresAuthentication: requiresAuthentication, apiConfiguration: apiConfiguration) super.init(method: method, URLString: URLString, parameters: parameters, headers: headers, requiresAuthentication: requiresAuthentication, apiConfiguration: apiConfiguration)
} }
@@ -255,7 +255,7 @@ fileprivate class AlamofireRequestBuilderConfiguration: @unchecked Sendable {
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class AlamofireDecodableRequestBuilder<T: Decodable>: AlamofireRequestBuilder<T>, @unchecked Sendable { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class AlamofireDecodableRequestBuilder<T: Decodable & Sendable>: AlamofireRequestBuilder<T>, @unchecked Sendable {
override fileprivate func processRequest(request: DataRequest, managerId: String, completion: @Sendable @escaping (_ result: Swift.Result<Response<T>, ErrorResponse>) -> Void) { override fileprivate func processRequest(request: DataRequest, managerId: String, completion: @Sendable @escaping (_ result: Swift.Result<Response<T>, ErrorResponse>) -> Void) {
if let credential = self.credential { if let credential = self.credential {

View File

@@ -40,7 +40,7 @@ extension URLSession: URLSessionProtocol {
extension URLSessionDataTask: URLSessionDataTaskProtocol {} extension URLSessionDataTask: URLSessionDataTaskProtocol {}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} class URLSessionRequestBuilderFactory: RequestBuilderFactory { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} final class URLSessionRequestBuilderFactory: RequestBuilderFactory, Sendable {
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init() {} {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init() {}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} func getNonDecodableBuilder<T>() -> RequestBuilder<T>.Type {
@@ -69,7 +69,7 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable {
var credentialStore = SynchronizedDictionary<Int, URLCredential>() var credentialStore = SynchronizedDictionary<Int, URLCredential>()
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class URLSessionRequestBuilder<T>: RequestBuilder<T>, @unchecked Sendable { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class URLSessionRequestBuilder<T: Sendable>: RequestBuilder<T>, @unchecked Sendable {
required {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(method: String, URLString: String, parameters: [String: any Sendable]?, headers: [String: String] = [:], requiresAuthentication: Bool, apiConfiguration: {{projectName}}APIConfiguration = {{projectName}}APIConfiguration.shared) { required {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} init(method: String, URLString: String, parameters: [String: any Sendable]?, headers: [String: String] = [:], requiresAuthentication: Bool, apiConfiguration: {{projectName}}APIConfiguration = {{projectName}}APIConfiguration.shared) {
super.init(method: method, URLString: URLString, parameters: parameters, headers: headers, requiresAuthentication: requiresAuthentication, apiConfiguration: apiConfiguration) super.init(method: method, URLString: URLString, parameters: parameters, headers: headers, requiresAuthentication: requiresAuthentication, apiConfiguration: apiConfiguration)
@@ -157,6 +157,8 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable {
let dataTask = urlSession.dataTaskFromProtocol(with: modifiedRequest) { data, response, error in let dataTask = urlSession.dataTaskFromProtocol(with: modifiedRequest) { data, response, error in
self.cleanupRequest() self.cleanupRequest()
self.apiConfiguration.interceptor.didReceiveResponse(urlRequest: modifiedRequest, urlSession: urlSession, requestBuilder: self, data: data, response: response, error: error)
if let error = error { if let error = error {
self.retryRequest( self.retryRequest(
urlRequest: modifiedRequest, urlRequest: modifiedRequest,
@@ -196,7 +198,7 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable {
return return
} }
self.processRequestResponse(urlRequest: request, data: data, httpResponse: httpResponse, error: error, completion: completion) self.processRequestResponse(urlRequest: modifiedRequest, urlSession: urlSession, data: data, httpResponse: httpResponse, error: error, completion: completion)
} }
self.onProgressReady?(dataTask.progress) self.onProgressReady?(dataTask.progress)
@@ -205,15 +207,25 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable {
self.requestTask.set(task: dataTask) self.requestTask.set(task: dataTask)
self.apiConfiguration.interceptor.willSendRequest(urlRequest: modifiedRequest, urlSession: urlSession, requestBuilder: self)
dataTask.resume() dataTask.resume()
case .failure(let error): case .failure(let error):
self.apiConfiguration.interceptor.didComplete(urlRequest: request, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error))
self.apiConfiguration.apiResponseQueue.async { self.apiConfiguration.apiResponseQueue.async {
completion(.failure(ErrorResponse.error(415, nil, nil, error))) completion(.failure(ErrorResponse.error(415, nil, nil, error)))
} }
} }
} }
} catch { } catch {
// Request creation failed - create a minimal request for error reporting
let failedURL = URL(string: URLString) ?? URL(string: "about:blank")!
var failedRequest = URLRequest(url: failedURL)
failedRequest.httpMethod = method
self.apiConfiguration.interceptor.didComplete(urlRequest: failedRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: nil, result: .failure(error))
self.apiConfiguration.apiResponseQueue.async { self.apiConfiguration.apiResponseQueue.async {
completion(.failure(ErrorResponse.error(415, nil, nil, error))) completion(.failure(ErrorResponse.error(415, nil, nil, error)))
} }
@@ -235,6 +247,7 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable {
self.execute(completion: completion) self.execute(completion: completion)
case .dontRetry: case .dontRetry:
self.apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: response, result: .failure(error))
self.apiConfiguration.apiResponseQueue.async { self.apiConfiguration.apiResponseQueue.async {
completion(.failure(ErrorResponse.error(statusCode, data, response, error))) completion(.failure(ErrorResponse.error(statusCode, data, response, error)))
} }
@@ -242,12 +255,13 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable {
} }
} }
fileprivate func processRequestResponse(urlRequest: URLRequest, data: Data?, httpResponse: HTTPURLResponse, error: Error?, completion: @escaping (_ result: Swift.Result<Response<T>, ErrorResponse>) -> Void) { fileprivate func processRequestResponse(urlRequest: URLRequest, urlSession: URLSessionProtocol, data: Data?, httpResponse: HTTPURLResponse, error: Error?, completion: @Sendable @escaping (_ result: Swift.Result<Response<T>, ErrorResponse>) -> Void) {
switch T.self { switch T.self {
case is Void.Type: case is Void.Type:
let result = () as! T
completion(.success(Response(response: httpResponse, body: () as! T, bodyData: data))) apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .success(result))
completion(.success(Response(response: httpResponse, body: result, bodyData: data)))
default: default:
fatalError("Unsupported Response Body Type - \(String(describing: T.self))") fatalError("Unsupported Response Body Type - \(String(describing: T.self))")
@@ -319,19 +333,17 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable {
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class URLSessionDecodableRequestBuilder<T: Decodable>: URLSessionRequestBuilder<T>, @unchecked Sendable { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}open{{/nonPublicApi}} class URLSessionDecodableRequestBuilder<T: Decodable & Sendable>: URLSessionRequestBuilder<T>, @unchecked Sendable {
override fileprivate func processRequestResponse(urlRequest: URLRequest, data: Data?, httpResponse: HTTPURLResponse, error: Error?, completion: @escaping (_ result: Swift.Result<Response<T>, ErrorResponse>) -> Void) { override fileprivate func processRequestResponse(urlRequest: URLRequest, urlSession: URLSessionProtocol, data: Data?, httpResponse: HTTPURLResponse, error: Error?, completion: @Sendable @escaping (_ result: Swift.Result<Response<T>, ErrorResponse>) -> Void) {
switch T.self { switch T.self {
case is String.Type: case is String.Type:
let body = data.flatMap { String(data: $0, encoding: .utf8) } ?? "" let body = data.flatMap { String(data: $0, encoding: .utf8) } ?? ""
apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .success(body as! T))
completion(.success(Response<T>(response: httpResponse, body: body as! T, bodyData: data))) completion(.success(Response<T>(response: httpResponse, body: body as! T, bodyData: data)))
case is URL.Type: case is URL.Type:
do { do {
guard error == nil else { guard error == nil else {
throw DownloadException.responseFailed throw DownloadException.responseFailed
} }
@@ -358,29 +370,37 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable {
try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil) try fileManager.createDirectory(atPath: directoryPath, withIntermediateDirectories: true, attributes: nil)
try data.write(to: filePath, options: .atomic) try data.write(to: filePath, options: .atomic)
apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .success(filePath as! T))
completion(.success(Response(response: httpResponse, body: filePath as! T, bodyData: data))) completion(.success(Response(response: httpResponse, body: filePath as! T, bodyData: data)))
} catch let requestParserError as DownloadException { } catch let requestParserError as DownloadException {
apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .failure(requestParserError))
completion(.failure(ErrorResponse.error(400, data, httpResponse, requestParserError))) completion(.failure(ErrorResponse.error(400, data, httpResponse, requestParserError)))
} catch { } catch {
apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .failure(error))
completion(.failure(ErrorResponse.error(400, data, httpResponse, error))) completion(.failure(ErrorResponse.error(400, data, httpResponse, error)))
} }
case is Void.Type: case is Void.Type:
let result = () as! T
completion(.success(Response(response: httpResponse, body: () as! T, bodyData: data))) apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .success(result))
completion(.success(Response(response: httpResponse, body: result, bodyData: data)))
case is Data.Type: case is Data.Type:
let result = data as! T
completion(.success(Response(response: httpResponse, body: data as! T, bodyData: data))) apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .success(result))
completion(.success(Response(response: httpResponse, body: result, bodyData: data)))
default: default:
guard let unwrappedData = data, !unwrappedData.isEmpty else { guard let unwrappedData = data, !unwrappedData.isEmpty else {
if let expressibleByNilLiteralType = T.self as? ExpressibleByNilLiteral.Type { if let expressibleByNilLiteralType = T.self as? ExpressibleByNilLiteral.Type {
completion(.success(Response(response: httpResponse, body: expressibleByNilLiteralType.init(nilLiteral: ()) as! T, bodyData: data))) let result = expressibleByNilLiteralType.init(nilLiteral: ()) as! T
apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: data, response: httpResponse, result: .success(result))
completion(.success(Response(response: httpResponse, body: result, bodyData: data)))
} else { } else {
completion(.failure(ErrorResponse.error(httpResponse.statusCode, nil, httpResponse, DecodableRequestBuilderError.emptyDataResponse))) let emptyDataError = DecodableRequestBuilderError.emptyDataResponse
apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: nil, response: httpResponse, result: .failure(emptyDataError))
completion(.failure(ErrorResponse.error(httpResponse.statusCode, nil, httpResponse, emptyDataError)))
} }
return return
} }
@@ -389,8 +409,10 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable {
switch decodeResult { switch decodeResult {
case let .success(decodableObj): case let .success(decodableObj):
apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: unwrappedData, response: httpResponse, result: .success(decodableObj))
completion(.success(Response(response: httpResponse, body: decodableObj, bodyData: unwrappedData))) completion(.success(Response(response: httpResponse, body: decodableObj, bodyData: unwrappedData)))
case let .failure(error): case let .failure(error):
apiConfiguration.interceptor.didComplete(urlRequest: urlRequest, urlSession: urlSession, requestBuilder: self, data: unwrappedData, response: httpResponse, result: .failure(error))
completion(.failure(ErrorResponse.error(httpResponse.statusCode, unwrappedData, httpResponse, error))) completion(.failure(ErrorResponse.error(httpResponse.statusCode, unwrappedData, httpResponse, error)))
} }
} }
@@ -398,7 +420,7 @@ fileprivate class URLSessionRequestBuilderConfiguration: @unchecked Sendable {
} }
fileprivate final class SessionDelegate: NSObject, URLSessionTaskDelegate { fileprivate final class SessionDelegate: NSObject, URLSessionTaskDelegate {
func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { func urlSession(_ session: URLSession, task: URLSessionTask, didReceive challenge: URLAuthenticationChallenge, completionHandler: @Sendable @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling var disposition: URLSession.AuthChallengeDisposition = .performDefaultHandling
@@ -458,7 +480,7 @@ private class FormDataEncoding: ParameterEncoding {
let contentTypeForFormPart: (_ fileURL: URL) -> String? let contentTypeForFormPart: (_ fileURL: URL) -> String?
init(contentTypeForFormPart: @escaping (_ fileURL: URL) -> String?) { init(contentTypeForFormPart: @Sendable @escaping (_ fileURL: URL) -> String?) {
self.contentTypeForFormPart = contentTypeForFormPart self.contentTypeForFormPart = contentTypeForFormPart
} }
@@ -711,20 +733,48 @@ extension JSONDataEncoding: ParameterEncoding {}
case dontRetry case dontRetry
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} protocol OpenAPIInterceptor { {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} protocol OpenAPIInterceptor: Sendable {
func intercept<T>(urlRequest: URLRequest, urlSession: URLSessionProtocol, requestBuilder: RequestBuilder<T>, completion: @escaping (Result<URLRequest, Error>) -> Void) // MARK: - Request Modification & Retry
func retry<T>(urlRequest: URLRequest, urlSession: URLSessionProtocol, requestBuilder: RequestBuilder<T>, data: Data?, response: URLResponse?, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) /// Called before the request is sent. Allows modifying the URLRequest (e.g., adding authentication headers).
func intercept<T>(urlRequest: URLRequest, urlSession: URLSessionProtocol, requestBuilder: RequestBuilder<T>, completion: @Sendable @escaping (Result<URLRequest, Error>) -> Void)
/// Called when a request fails. Allows the interceptor to decide whether to retry the request.
func retry<T>(urlRequest: URLRequest, urlSession: URLSessionProtocol, requestBuilder: RequestBuilder<T>, data: Data?, response: URLResponse?, error: Error, completion: @Sendable @escaping (OpenAPIInterceptorRetry) -> Void)
// MARK: - Lifecycle Hooks
/// Called right before the request is sent, after all modifications from `intercept()` have been applied.
/// Useful for logging the final request that will be sent.
func willSendRequest<T>(urlRequest: URLRequest, urlSession: URLSessionProtocol, requestBuilder: RequestBuilder<T>)
/// Called when the raw response is received, before any processing or decoding.
/// Useful for logging raw responses or performing custom validation.
func didReceiveResponse<T>(urlRequest: URLRequest, urlSession: URLSessionProtocol, requestBuilder: RequestBuilder<T>, data: Data?, response: URLResponse?, error: Error?)
/// Called after the request completes (either success or failure).
/// Useful for cleanup, analytics, or performance monitoring.
func didComplete<T>(urlRequest: URLRequest, urlSession: URLSessionProtocol, requestBuilder: RequestBuilder<T>, data: Data?, response: URLResponse?, result: Result<T, Error>)
} }
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} class DefaultOpenAPIInterceptor: OpenAPIInterceptor { // MARK: - Default Implementations (No-op)
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} extension OpenAPIInterceptor {
func willSendRequest<T>(urlRequest: URLRequest, urlSession: URLSessionProtocol, requestBuilder: RequestBuilder<T>) {}
func didReceiveResponse<T>(urlRequest: URLRequest, urlSession: URLSessionProtocol, requestBuilder: RequestBuilder<T>, data: Data?, response: URLResponse?, error: Error?) {}
func didComplete<T>(urlRequest: URLRequest, urlSession: URLSessionProtocol, requestBuilder: RequestBuilder<T>, data: Data?, response: URLResponse?, result: Result<T, Error>) {}
}
{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} final class DefaultOpenAPIInterceptor: OpenAPIInterceptor {
public init() {} public init() {}
public func intercept<T>(urlRequest: URLRequest, urlSession: URLSessionProtocol, requestBuilder: RequestBuilder<T>, completion: @escaping (Result<URLRequest, any Error>) -> Void) { public func intercept<T>(urlRequest: URLRequest, urlSession: URLSessionProtocol, requestBuilder: RequestBuilder<T>, completion: @Sendable @escaping (Result<URLRequest, any Error>) -> Void) {
completion(.success(urlRequest)) completion(.success(urlRequest))
} }
public func retry<T>(urlRequest: URLRequest, urlSession: URLSessionProtocol, requestBuilder: RequestBuilder<T>, data: Data?, response: URLResponse?, error: Error, completion: @escaping (OpenAPIInterceptorRetry) -> Void) { public func retry<T>(urlRequest: URLRequest, urlSession: URLSessionProtocol, requestBuilder: RequestBuilder<T>, data: Data?, response: URLResponse?, error: Error, completion: @Sendable @escaping (OpenAPIInterceptorRetry) -> Void) {
completion(.dontRetry) completion(.dontRetry)
} }
} }

View File

@@ -25,6 +25,5 @@ extension {{projectName}}API {
{{#swiftUseApiNamespace}} {{#swiftUseApiNamespace}}
} }
{{/swiftUseApiNamespace}}{{#models}}{{#model}}{{#vendorExtensions.x-swift-identifiable}} {{/swiftUseApiNamespace}}{{#models}}{{#model}}{{#vendorExtensions.x-swift-identifiable}}
@available(iOS 13, tvOS 13, watchOS 6, macOS 10.15, *)
extension {{#swiftUseApiNamespace}}{{projectName}}API.{{/swiftUseApiNamespace}}{{{classname}}}: Identifiable {} extension {{#swiftUseApiNamespace}}{{projectName}}API.{{/swiftUseApiNamespace}}{{{classname}}}: Identifiable {}
{{/vendorExtensions.x-swift-identifiable}}{{/model}}{{/models}} {{/vendorExtensions.x-swift-identifiable}}{{/model}}{{/models}}

View File

@@ -1,5 +1,5 @@
{{^objcCompatible}}{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#useClasses}}final class{{/useClasses}}{{^useClasses}}struct{{/useClasses}} {{{classname}}}: {{^useClasses}}Sendable, {{/useClasses}}{{#useClasses}}{{#readonlyProperties}}@unchecked Sendable, {{/readonlyProperties}}{{/useClasses}}{{#useVapor}}Content{{/useVapor}}{{^useVapor}}Codable{{/useVapor}}{{#vendorExtensions.x-swift-hashable}}, Hashable{{/vendorExtensions.x-swift-hashable}} { {{^objcCompatible}}{{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} {{#useClasses}}final class{{/useClasses}}{{^useClasses}}struct{{/useClasses}} {{{classname}}}: {{^useClasses}}Sendable, {{/useClasses}}{{#useClasses}}{{#readonlyProperties}}@unchecked Sendable, {{/readonlyProperties}}{{/useClasses}}{{#useVapor}}Content{{/useVapor}}{{^useVapor}}Codable{{/useVapor}}{{#vendorExtensions.x-swift-hashable}}, Hashable{{/vendorExtensions.x-swift-hashable}} {
{{/objcCompatible}}{{#objcCompatible}}@objcMembers {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} class {{classname}}: NSObject, Codable { {{/objcCompatible}}{{#objcCompatible}}@objcMembers {{#nonPublicApi}}internal{{/nonPublicApi}}{{^nonPublicApi}}public{{/nonPublicApi}} final class {{classname}}: NSObject, Codable, @unchecked Sendable {
{{/objcCompatible}} {{/objcCompatible}}
{{#allVars}} {{#allVars}}

View File

@@ -1,5 +1,6 @@
import { HttpHeaders, HttpParams, HttpParameterCodec } from '@angular/common/http'; import { HttpHeaders, HttpParameterCodec } from '@angular/common/http';
import { Param } from './param'; import { Param } from './param';
import { OpenApiHttpParams } from './query.params';
export interface {{configurationParametersInterfaceName}} { export interface {{configurationParametersInterfaceName}} {
/** /**
@@ -198,7 +199,7 @@ constructor({ accessToken, apiKeys, basePath, credentials, encodeParam, encoder,
: headers; : headers;
} }
public addCredentialToQuery(credentialKey: string, paramName: string, query: HttpParams): HttpParams { public addCredentialToQuery(credentialKey: string, paramName: string, query: OpenApiHttpParams): OpenApiHttpParams {
const value = this.lookupCredential(credentialKey); const value = this.lookupCredential(credentialKey);
return value return value
? query.set(paramName, value) ? query.set(paramName, value)

View File

@@ -42,6 +42,19 @@ export interface {{#prefixParameterInterfaces}}{{classname}}{{/prefixParameterIn
*/ */
export interface {{classname}}Interface { export interface {{classname}}Interface {
{{#operation}} {{#operation}}
/**
* Creates request options for {{nickname}} without sending the request
{{#allParams}}
* @param {{=<% %>=}}{<%&dataType%>}<%={{ }}=%> {{^required}}[{{/required}}{{paramName}}{{^required}}]{{/required}} {{description}}
{{/allParams}}
{{#isDeprecated}}
* @deprecated
{{/isDeprecated}}
* @throws {RequiredError}
* @memberof {{classname}}Interface
*/
{{nickname}}RequestOpts({{#allParams.0}}requestParameters: {{#prefixParameterInterfaces}}{{classname}}{{/prefixParameterInterfaces}}{{operationIdCamelCase}}Request{{/allParams.0}}): Promise<runtime.RequestOpts>;
/** /**
* {{&notes}} * {{&notes}}
{{#summary}} {{#summary}}
@@ -95,17 +108,12 @@ export class {{classname}} extends runtime.BaseAPI {
{{#operation}} {{#operation}}
/** /**
{{#notes}} * Creates request options for {{nickname}} without sending the request
* {{&notes}}
{{/notes}}
{{#summary}}
* {{&summary}}
{{/summary}}
{{#isDeprecated}} {{#isDeprecated}}
* @deprecated * @deprecated
{{/isDeprecated}} {{/isDeprecated}}
*/ */
async {{nickname}}Raw({{#allParams.0}}requestParameters: {{#prefixParameterInterfaces}}{{classname}}{{/prefixParameterInterfaces}}{{operationIdCamelCase}}Request, {{/allParams.0}}initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<{{{returnType}}}{{^returnType}}void{{/returnType}}>> { async {{nickname}}RequestOpts({{#allParams.0}}requestParameters: {{#prefixParameterInterfaces}}{{classname}}{{/prefixParameterInterfaces}}{{operationIdCamelCase}}Request{{/allParams.0}}): Promise<runtime.RequestOpts> {
{{#allParams}} {{#allParams}}
{{#required}} {{#required}}
if (requestParameters['{{paramName}}'] == null) { if (requestParameters['{{paramName}}'] == null) {
@@ -304,7 +312,7 @@ export class {{classname}} extends runtime.BaseAPI {
{{/isDateTimeType}} {{/isDateTimeType}}
{{/pathParams}} {{/pathParams}}
const response = await this.request({ return {
path: urlPath, path: urlPath,
method: '{{httpMethod}}', method: '{{httpMethod}}',
headers: headerParameters, headers: headerParameters,
@@ -337,7 +345,23 @@ export class {{classname}} extends runtime.BaseAPI {
{{#hasFormParams}} {{#hasFormParams}}
body: formParams, body: formParams,
{{/hasFormParams}} {{/hasFormParams}}
}, initOverrides); };
}
/**
{{#notes}}
* {{&notes}}
{{/notes}}
{{#summary}}
* {{&summary}}
{{/summary}}
{{#isDeprecated}}
* @deprecated
{{/isDeprecated}}
*/
async {{nickname}}Raw({{#allParams.0}}requestParameters: {{#prefixParameterInterfaces}}{{classname}}{{/prefixParameterInterfaces}}{{operationIdCamelCase}}Request, {{/allParams.0}}initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<{{{returnType}}}{{^returnType}}void{{/returnType}}>> {
const requestOptions = await this.{{nickname}}RequestOpts({{#allParams.0}}requestParameters{{/allParams.0}});
const response = await this.request(requestOptions, initOverrides);
{{#returnType}} {{#returnType}}
{{#isResponseFile}} {{#isResponseFile}}

View File

@@ -671,6 +671,32 @@ public class DefaultGeneratorTest {
Assert.assertEquals(servers.get(2).url, "http://notrailingslash.io:80/v2"); Assert.assertEquals(servers.get(2).url, "http://notrailingslash.io:80/v2");
} }
@Test
public void testHandlesRelativeUrlsWithSpecialChars() {
final Map<String, String> specToBasePath = Map.of(
"src/test/resources/3_0/relative-url-point.yaml", "/api/v4.0",
"src/test/resources/3_0/relative-url-dash.yaml", "/api-v3",
"src/test/resources/3_0/relative-url-tilde.yaml", "/~api/v5",
"src/test/resources/3_0/relative-url-at.yaml", "/api/@6"
);
specToBasePath.forEach((spec, expectedBasePath) -> {
OpenAPI openAPI = TestUtils.parseFlattenSpec(spec);
ClientOptInput opts = new ClientOptInput();
opts.openAPI(openAPI);
DefaultCodegen config = new DefaultCodegen();
config.setStrictSpecBehavior(false);
opts.config(config);
final DefaultGenerator generator = new DefaultGenerator();
generator.opts(opts);
generator.configureGeneratorProperties();
Map<String, Object> bundle = generator.buildSupportFileBundle(new ArrayList<>(), new ArrayList<>(), new ArrayList<>());
final String actualBasePath = (String) bundle.get("basePath");
Assert.assertEquals(actualBasePath, expectedBasePath);
});
}
@Test @Test
public void testHandlesRelativeUrlsInServers() { public void testHandlesRelativeUrlsInServers() {
OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue_10056.yaml"); OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/3_0/issue_10056.yaml");

View File

@@ -0,0 +1,15 @@
openapi: 3.0.1
info:
title: OpenAPI Petstore
description: "sample spec"
license:
name: Apache-2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
version: 1.0.0
servers:
- url: /api/@6
tags: []
paths: {}
components:
schemas: {}
securitySchemes: {}

View File

@@ -0,0 +1,15 @@
openapi: 3.0.1
info:
title: OpenAPI Petstore
description: "sample spec"
license:
name: Apache-2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
version: 1.0.0
servers:
- url: /api-v3
tags: []
paths: {}
components:
schemas: {}
securitySchemes: {}

View File

@@ -0,0 +1,15 @@
openapi: 3.0.1
info:
title: OpenAPI Petstore
description: "sample spec"
license:
name: Apache-2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
version: 1.0.0
servers:
- url: /api/v4.0
tags: []
paths: {}
components:
schemas: {}
securitySchemes: {}

View File

@@ -0,0 +1,15 @@
openapi: 3.0.1
info:
title: OpenAPI Petstore
description: "sample spec"
license:
name: Apache-2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
version: 1.0.0
servers:
- url: /~api/v5
tags: []
paths: {}
components:
schemas: {}
securitySchemes: {}

View File

@@ -15,7 +15,7 @@
<packaging>pom</packaging> <packaging>pom</packaging>
<name>openapi-generator-project</name> <name>openapi-generator-project</name>
<!-- RELEASE_VERSION --> <!-- RELEASE_VERSION -->
<version>7.19.0</version> <version>7.20.0-SNAPSHOT</version>
<!-- /RELEASE_VERSION --> <!-- /RELEASE_VERSION -->
<url>https://github.com/openapitools/openapi-generator</url> <url>https://github.com/openapitools/openapi-generator</url>
<scm> <scm>

View File

@@ -1 +1 @@
7.19.0-SNAPSHOT 7.20.0-SNAPSHOT

View File

@@ -6,7 +6,7 @@ This C# SDK is automatically generated by the [OpenAPI Generator](https://openap
- API version: 0.1.0 - API version: 0.1.0
- SDK version: 1.0.0 - SDK version: 1.0.0
- Generator version: 7.19.0-SNAPSHOT - Generator version: 7.20.0-SNAPSHOT
- Build package: org.openapitools.codegen.languages.CSharpClientCodegen - Build package: org.openapitools.codegen.languages.CSharpClientCodegen
<a id="frameworks-supported"></a> <a id="frameworks-supported"></a>

View File

@@ -1 +1 @@
7.19.0-SNAPSHOT 7.20.0-SNAPSHOT

View File

@@ -7,7 +7,7 @@ This API client was generated by the [OpenAPI Generator](https://openapi-generat
- API version: 0.1.0 - API version: 0.1.0
- Package version: 1.0.0 - Package version: 1.0.0
- Generator version: 7.19.0-SNAPSHOT - Generator version: 7.20.0-SNAPSHOT
- Build package: org.openapitools.codegen.languages.GoClientCodegen - Build package: org.openapitools.codegen.languages.GoClientCodegen
## Installation ## Installation

View File

@@ -1 +1 @@
7.19.0-SNAPSHOT 7.20.0-SNAPSHOT

View File

@@ -7,7 +7,7 @@ This API client was generated by the [OpenAPI Generator](https://openapi-generat
- API version: 0.1.0 - API version: 0.1.0
- Package version: 1.0.0 - Package version: 1.0.0
- Generator version: 7.19.0-SNAPSHOT - Generator version: 7.20.0-SNAPSHOT
- Build package: org.openapitools.codegen.languages.GoClientCodegen - Build package: org.openapitools.codegen.languages.GoClientCodegen
## Installation ## Installation

View File

@@ -1 +1 @@
7.19.0-SNAPSHOT 7.20.0-SNAPSHOT

View File

@@ -4,7 +4,7 @@ Echo Server API
- API version: 0.1.0 - API version: 0.1.0
- Generator version: 7.19.0-SNAPSHOT - Generator version: 7.20.0-SNAPSHOT
Echo Server API Echo Server API

View File

@@ -80,7 +80,7 @@ import org.openapitools.client.auth.Authentication;
import org.openapitools.client.auth.HttpBasicAuth; import org.openapitools.client.auth.HttpBasicAuth;
import org.openapitools.client.auth.HttpBearerAuth; import org.openapitools.client.auth.HttpBearerAuth;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.19.0-SNAPSHOT") @javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.20.0-SNAPSHOT")
public class ApiClient extends JavaTimeFormatter { public class ApiClient extends JavaTimeFormatter {
protected Map<String, String> defaultHeaderMap = new HashMap<String, String>(); protected Map<String, String> defaultHeaderMap = new HashMap<String, String>();
protected Map<String, String> defaultCookieMap = new HashMap<String, String>(); protected Map<String, String> defaultCookieMap = new HashMap<String, String>();

View File

@@ -16,7 +16,7 @@ package org.openapitools.client;
import java.util.Map; import java.util.Map;
import java.util.List; import java.util.List;
@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.19.0-SNAPSHOT") @javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen", comments = "Generator version: 7.20.0-SNAPSHOT")
public class ApiException extends Exception { public class ApiException extends Exception {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;

Some files were not shown because too many files have changed in this diff Show More