diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 0000000000..be88519961
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1 @@
+* @oapi-codegen/maintainers
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 0000000000..cf30ec2c3c
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,5 @@
+github:
+- oapi-codegen
+- jamietanna
+tidelift: go/github.com/oapi-codegen/oapi-codegen/v2
+open_collective: oapi-codegen
diff --git a/.github/label-actions.yml b/.github/label-actions.yml
new file mode 100644
index 0000000000..342da5bb30
--- /dev/null
+++ b/.github/label-actions.yml
@@ -0,0 +1,49 @@
+'auto:no-head-branch':
+ comment: >
+ Thanks for the contribution!
+
+ It looks like this PR was raised from the `main` branch.
+
+ As per [our contributing guidelines](https://github.com/oapi-codegen/oapi-codegen/blob/main/CONTRIBUTING.md#before-you-raise-a-pr), this can make it difficult for us to push changes to your fork - for instance to directly push a change to address a comment that we would raise, or to finalise changes before merge.
+
+ Please re-raise the PR from a branch on your repository that isn't `main` / any protected branches.
+
+ Thank you in advance 🙇🏼
+
+'auto:no-mentions':
+ comment: >
+ Thanks for your use of `oapi-codegen`!
+
+ We are very appreciative of your interest in improving the project, and that you're engaged with us.
+
+ However, @-mentioning the maintainers will be very unlikely to help move your issue along, and we do not want to encourage behaviour that leads to the "noisiest" users getting the benefit over folks who are waiting their turn.
+
+ Please remember that `oapi-codegen` is for the most part run by volunteers, and [we have a request out](https://github.com/oapi-codegen/oapi-codegen/discussions/1606) to companies who use the project to help make it more sustainable, with sponsorship.
+
+ It will only be that sustained financial support will be able to make it possible to work more efficiently towards user requests.
+
+ For more info on engaging with the maintainers, see [our CONTRIBUTING guide](https://github.com/oapi-codegen/oapi-codegen/blob/main/CONTRIBUTING.md#should-i--mention-the-maintainers-on-an-issue).
+
+'auto:pinning-until-release':
+ comment: >
+ [Until there is a defined release cadence planned](https://github.com/oapi-codegen/oapi-codegen/issues/1519), our [official recommendation](https://github.com/oapi-codegen/oapi-codegen/blob/main/README.md#pinning-to-commits) is that you pin to the latest commit on `main`, which will allow you to pull in this change.
+
+'auto:sponsorship':
+ comment: >
+ Please remember that `oapi-codegen` is for the most part run by volunteers, and [we have a request out](https://github.com/oapi-codegen/oapi-codegen/discussions/1606) to companies who use the project to help make it more sustainable, with sponsorship.
+
+ If this is high-priority for your organisation, please consider whether you would like to sponsor ongoing maintenance of the project, or that you may want to engage the maintainers to perform a one-off contract/bug bounty.
+
+ Also remember that although it can seem like "just" a "small change", the maintainers are on the hook for maintaining the changes:
+
+ > [No is temporary, yes is forever](https://www.oreilly.com/library/view/hands-on-design-patterns/9781789135565/3f396314-dac8-446c-ab02-768ae91296fa.xhtml)
+
+'reproduction:needed':
+ comment: >
+ Thanks for the report!
+
+ To help maintainers (or other users) help with triaging and fixing of the issue more easily, we need a [Minimal Reproduction](https://github.com/oapi-codegen/oapi-codegen/blob/main/CONTRIBUTING.md#minimal-reproductions) test case.
+
+ Please follow the instructions, and then share a URL to the repository.
+
+ We will not accept `.zip` files as reproductions, sorry!
diff --git a/.github/labeler.yml b/.github/labeler.yml
new file mode 100644
index 0000000000..792590af6e
--- /dev/null
+++ b/.github/labeler.yml
@@ -0,0 +1,3 @@
+'auto:no-head-branch':
+- head-branch:
+ - '^main$'
diff --git a/.github/sponsors/cybozu.svg b/.github/sponsors/cybozu.svg
new file mode 100644
index 0000000000..6691fbd916
--- /dev/null
+++ b/.github/sponsors/cybozu.svg
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
diff --git a/.github/sponsors/devzero-dark.svg b/.github/sponsors/devzero-dark.svg
new file mode 100644
index 0000000000..9085ad1802
--- /dev/null
+++ b/.github/sponsors/devzero-dark.svg
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.github/sponsors/devzero-light.svg b/.github/sponsors/devzero-light.svg
new file mode 100644
index 0000000000..8889a29199
--- /dev/null
+++ b/.github/sponsors/devzero-light.svg
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.github/sponsors/livepeer-dark.svg b/.github/sponsors/livepeer-dark.svg
new file mode 100644
index 0000000000..2abe96ec95
--- /dev/null
+++ b/.github/sponsors/livepeer-dark.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.github/sponsors/livepeer-light.svg b/.github/sponsors/livepeer-light.svg
new file mode 100644
index 0000000000..71b5a40b27
--- /dev/null
+++ b/.github/sponsors/livepeer-light.svg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.github/sponsors/speakeasy-dark.svg b/.github/sponsors/speakeasy-dark.svg
new file mode 100644
index 0000000000..aae8f7a9d9
--- /dev/null
+++ b/.github/sponsors/speakeasy-dark.svg
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.github/sponsors/speakeasy-light.svg b/.github/sponsors/speakeasy-light.svg
new file mode 100644
index 0000000000..ab439943db
--- /dev/null
+++ b/.github/sponsors/speakeasy-light.svg
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b5e2385b28..d1eced9ef1 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,31 +1,37 @@
-name: Build project
-on: [ push, pull_request ]
+name: CI
+on:
+ push: {}
+ pull_request: {}
+ workflow_dispatch: {}
+permissions:
+ contents: read
jobs:
build:
- name: Build
+ uses: oapi-codegen/actions/.github/workflows/ci.yml@0b10ad68a53148bd29896be82ad92027b35507a3 # v0.8.0
+ with:
+ lint_versions: '["1.26"]'
+ # The module requires Go 1.25.9, so exclude 1.24 from the default matrix.
+ excluding_versions: '["1.24", "oldstable", "stable"]'
+
+ build-binaries:
runs-on: ubuntu-latest
strategy:
- fail-fast: false
- # perform matrix testing to give us an earlier insight into issues with different versions of supported major versions of Go
+ fail-fast: true
matrix:
- # strategy is used to allow us to pin to a specific Go version, or use the version available in our `go.mod`
- strategy: ['go-version']
- version: [1.21]
- include:
- # pick up the Go version from the `go.mod`
- - strategy: 'go-version-file'
- version: 'go.mod'
+ version:
+ - "1.26"
+ - "1.25"
steps:
- name: Check out source code
- uses: actions/checkout@v3
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Go
- uses: actions/setup-go@v3
+ uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
- ${{ matrix.strategy }}: ${{ matrix.version }}
-
- - name: Test
- run: make test
+ go-version: ${{ matrix.version }}
- name: Build
run: go build ./cmd/oapi-codegen
+ env:
+ # A combination of our GitHub Actions setup, with the Go toolchain, leads to inconsistencies in calling `go env`, in particular with Go 1.21, where having (the default) `GOTOOLCHAIN=auto` results in build failures
+ GOTOOLCHAIN: local
diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml
deleted file mode 100644
index 7e79884f36..0000000000
--- a/.github/workflows/generate.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-name: Ensure generated files are up-to-date
-on: [ push, pull_request ]
-jobs:
- build:
- name: Build
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- # perform matrix testing to give us an earlier insight into issues with different versions of supported major versions of Go
- matrix:
- # strategy is used to allow us to pin to a specific Go version, or use the version available in our `go.mod`
- strategy: ['go-version']
- version: [1.21]
- include:
- # pick up the Go version from the `go.mod`
- - strategy: 'go-version-file'
- version: 'go.mod'
- steps:
- - name: Check out source code
- uses: actions/checkout@v3
-
- - name: Set up Go
- uses: actions/setup-go@v3
- with:
- ${{ matrix.strategy }}: ${{ matrix.version }}
-
- - name: Run `make generate`
- run: make generate
-
- - name: Check for no untracked files
- run: git status && git diff-index --exit-code -p HEAD --
diff --git a/.github/workflows/govulncheck.yml b/.github/workflows/govulncheck.yml
new file mode 100644
index 0000000000..742c902f26
--- /dev/null
+++ b/.github/workflows/govulncheck.yml
@@ -0,0 +1,39 @@
+name: Determine known CVEs through `govulncheck`
+on:
+ push:
+ branches:
+ - main
+ schedule:
+ # Mondays at 0000
+ - cron: "0 0 * * 1"
+
+permissions:
+ contents: read
+
+jobs:
+ check-for-vulnerabilities:
+ name: Check for vulnerabilities using `govulncheck`
+ runs-on: ubuntu-latest
+ permissions:
+ security-events: write
+ contents: read
+ steps:
+ - uses: golang/govulncheck-action@b625fbe08f3bccbe446d94fbf87fcc875a4f50ee # v1.0.4
+ with:
+ # to be explicit, we're only checking the top-level `oapi-codegen` package
+ # we are intentionally NOT intending to keep on top of security updates in `internal/test` or `examples`, or any submodules thereof
+ go-package: ./...
+ # NOTE that we want to produce the SARIF-formatted report, which can then be consumed by other tools ...
+ output-format: sarif
+ output-file: govulncheck.sarif
+
+ # ... such as the Code Scanning tab (https://github.com/oapi-codegen/oapi-codegen/security/code-scanning?query=is%3Aopen+branch%3Amain+tool%3Agovulncheck)
+ - name: Upload SARIF file
+ uses: github/codeql-action/upload-sarif@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
+ with:
+ sarif_file: govulncheck.sarif
+ category: govulncheck
+
+ - name: Print code scanning results URL
+ run: |
+ echo "Results: https://github.com/${{ github.repository }}/security/code-scanning?query=is%3Aopen+branch%3Amain+tool%3Agovulncheck"
diff --git a/.github/workflows/label-actions.yml b/.github/workflows/label-actions.yml
new file mode 100644
index 0000000000..0d3f63627f
--- /dev/null
+++ b/.github/workflows/label-actions.yml
@@ -0,0 +1,23 @@
+name: 'Label Actions'
+
+on:
+ issues:
+ types: [labeled]
+ discussion:
+ types: [labeled]
+ pull_request_target:
+ types: [labeled]
+
+permissions:
+ contents: read
+ issues: write
+ discussions: write
+ pull-requests: write
+
+jobs:
+ reaction:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: dessant/label-actions@65225c179d3b2502f6eda7b3d15101a3f412366b # v5.0.3
+ with:
+ github-token: ${{ github.token }}
diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml
new file mode 100644
index 0000000000..d0a8024b05
--- /dev/null
+++ b/.github/workflows/labeler.yml
@@ -0,0 +1,15 @@
+name: "Pull Request Labeler"
+on:
+- pull_request_target
+
+permissions:
+ contents: read
+
+jobs:
+ labeler:
+ permissions:
+ contents: read
+ pull-requests: write
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/labeler@f27b608878404679385c85cfa523b85ccb86e213 # v6.1.0
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
deleted file mode 100644
index 816093ded0..0000000000
--- a/.github/workflows/lint.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-name: Lint project
-on: [push, pull_request]
-jobs:
- build:
- name: Build
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- # perform matrix testing to give us an earlier insight into issues with different versions of supported major versions of Go
- matrix:
- # strategy is used to allow us to pin to a specific Go version, or use the version available in our `go.mod`
- strategy: ['go-version']
- version: [1.21]
- include:
- # pick up the Go version from the `go.mod`
- - strategy: 'go-version-file'
- version: 'go.mod'
- steps:
- - name: Check out source code
- uses: actions/checkout@v3
-
- - name: Set up Go
- uses: actions/setup-go@v3
- with:
- ${{ matrix.strategy }}: ${{ matrix.version }}
-
- - name: Run `make lint-ci`
- run: make lint-ci
diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml
new file mode 100644
index 0000000000..4a05c48b70
--- /dev/null
+++ b/.github/workflows/release-drafter.yml
@@ -0,0 +1,25 @@
+name: Release Drafter
+
+on:
+ push:
+ branches:
+ - main
+ workflow_dispatch: {}
+
+permissions:
+ contents: read
+
+jobs:
+ update_release_draft:
+ permissions:
+ contents: write
+ pull-requests: write
+ runs-on: ubuntu-latest
+ steps:
+ - uses: release-drafter/release-drafter@c2e2804cc59f45f57076a99af580d0fedb697927 # v7.3.0
+ with:
+ name: next
+ tag: next
+ version: next
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
new file mode 100644
index 0000000000..24990b1090
--- /dev/null
+++ b/.github/workflows/scorecard.yml
@@ -0,0 +1,46 @@
+name: Scorecard supply-chain security
+on:
+ schedule:
+ - cron: "0 5 * * 1"
+ push:
+ branches:
+ - main
+
+permissions: read-all
+
+jobs:
+ analysis:
+ name: Scorecard analysis
+ runs-on: ubuntu-latest
+ permissions:
+ # Needed to upload the results to code-scanning dashboard
+ security-events: write
+ # Needed to publish results and get a badge (see publish_results below)
+ id-token: write
+
+ steps:
+ - name: "Checkout code"
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
+ with:
+ persist-credentials: false
+ show-progress: false
+
+ - name: "Run analysis"
+ uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
+ with:
+ results_file: results.sarif
+ results_format: sarif
+ publish_results: true
+
+ - name: "Upload artifact"
+ uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ with:
+ name: SARIF file
+ path: results.sarif
+ retention-days: 5
+
+ # Upload the results to GitHub's code scanning dashboard
+ - name: "Upload to code-scanning"
+ uses: github/codeql-action/upload-sarif@9e0d7b8d25671d64c341c19c0152d693099fb5ba # v4.35.5
+ with:
+ sarif_file: results.sarif
diff --git a/.github/workflows/tidy.yml b/.github/workflows/tidy.yml
deleted file mode 100644
index 946208c426..0000000000
--- a/.github/workflows/tidy.yml
+++ /dev/null
@@ -1,31 +0,0 @@
-name: Ensure `go mod tidy` has been run
-on: [ push, pull_request ]
-jobs:
- build:
- name: Build
- runs-on: ubuntu-latest
- strategy:
- fail-fast: false
- # perform matrix testing to give us an earlier insight into issues with different versions of supported major versions of Go
- matrix:
- # strategy is used to allow us to pin to a specific Go version, or use the version available in our `go.mod`
- strategy: ['go-version']
- version: [1.21]
- include:
- # pick up the Go version from the `go.mod`
- - strategy: 'go-version-file'
- version: 'go.mod'
- steps:
- - name: Check out source code
- uses: actions/checkout@v3
-
- - name: Set up Go
- uses: actions/setup-go@v3
- with:
- ${{ matrix.strategy }}: ${{ matrix.version }}
-
- - name: Install `tidied`
- run: go install gitlab.com/jamietanna/tidied@latest
-
- - name: Check for no untracked files
- run: git ls-files go.mod '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $(dirname {}) && tidied -verbose'
diff --git a/.golangci.yml b/.golangci.yml
deleted file mode 100644
index 7fe7ef5c22..0000000000
--- a/.golangci.yml
+++ /dev/null
@@ -1,3 +0,0 @@
-issues:
- exclude:
- - '.*This has been replaced by github.com/oapi-codegen/runtime.*'
diff --git a/.greptile/config.json b/.greptile/config.json
new file mode 100644
index 0000000000..e301f7f66f
--- /dev/null
+++ b/.greptile/config.json
@@ -0,0 +1,13 @@
+{
+{
+ "strictness": 2,
+ "commentTypes": ["logic", "syntax"],
+ "fileSettings": [
+ {
+ "pattern": "**/*.gen.go",
+ "strictness": 1,
+ "commentTypes": ["logic"]
+ }
+ ]
+}
+
diff --git a/.greptile/rules.md b/.greptile/rules.md
new file mode 100644
index 0000000000..a0cdc817ac
--- /dev/null
+++ b/.greptile/rules.md
@@ -0,0 +1,71 @@
+# Code Review Rules for oapi-codegen
+
+These rules guide automated code review for this repository. oapi-codegen is a code generator that turns OpenAPI 3.x specs into Go server stubs, clients, and types. The primary risk surface in any change is **the generated output that downstream users compile against** — review with that in mind.
+
+## 1. Generated files (`*.gen.go`)
+
+Files matching `*.gen.go` are produced by the code generator and committed to source control so CI can verify they are up-to-date. You do **not** need to read every generated file in a PR — spot check a representative sample.
+
+When spot checking, look for:
+
+- **Drift unrelated to the stated change.** If the PR claims to fix X, but a `*.gen.go` diff also shows unrelated reshuffling (renamed identifiers, reordered methods, formatting churn, removed comments, regenerated imports), call it out. This often indicates an accidental commit from a different branch, an out-of-date local toolchain, or a template change the author did not intend.
+- **Diffs that look "too small" for the described change.** If the PR claims to add a new code generation feature but the only generated diff is a one-line tweak in one file, the test fixtures may not have been regenerated — flag it.
+- **Diffs that look "too large" for the described change.** A small template tweak should not produce thousands of lines of churn across every fixture. If it does, the template change probably has a wider blast radius than the author realized.
+
+You do not need to suggest stylistic improvements inside `*.gen.go` files — they are templated output, not hand-written code.
+
+## 2. Configuration changes must update the JSON schema
+
+Whenever `pkg/codegen/configuration.go` is modified — particularly the `Configuration`, `GenerateOptions`, `OutputOptions`, or `CompatibilityOptions` structs — the corresponding JSON Schema at `configuration-schema.json` (repo root) **must** be updated to match.
+
+Flag any PR that changes `pkg/codegen/configuration.go` without a corresponding edit to `configuration-schema.json`. The schema is consumed by IDEs and validation tooling; an out-of-sync schema silently breaks downstream users' configs.
+
+## 3. Watch for breaking changes to the generated API surface
+
+Generated code is compiled into downstream users' binaries. Any change that alters the **shape** of generated code is a potential breaking change for every user of oapi-codegen, even if the change is "just" in a template.
+
+Flag the following patterns and call them out as breaking-change risks:
+
+- **Function/method signature changes** in generated server interfaces, client methods, or strict server handler types — added/removed/reordered parameters, changed return types, changed receiver types.
+- **Removed or renamed exported types, functions, methods, fields, or constants** in generated output.
+- **Changed Go types for existing fields** (e.g., `*string` → `string`, `int` → `int64`, switching between value and pointer receivers, swapping a concrete type for an interface).
+- **Renamed JSON struct tags** or other tags that affect serialization wire format.
+- **Reordered struct fields** when the struct is embedded or used in positional contexts (rare but worth noting).
+- **Removed or renamed template helper functions** that user-supplied template overrides may depend on (templates in `pkg/codegen/templates/` and helpers in `pkg/codegen/template_helpers.go`).
+
+Per the project's stated practice, behavior-changing features in codegen should be **opt-in via configuration** (new flags under `generate`, `output-options`, or `compatibility`), not silent breaking changes. If you see a behavior change that is unconditional, ask whether it should be gated behind a new compatibility flag.
+
+## 4. Template changes should be evaluated across all router backends
+
+The repo supports multiple server frameworks via separate template subdirectories under `pkg/codegen/templates/`:
+
+- `chi/`
+- `echo/`
+- `fiber/`
+- `gin/`
+- `gorilla/`
+- `iris/`
+- `stdhttp/` (net/http ServeMux, Go 1.22+)
+- `strict/` (the strict-server wrapper layer, applied on top of any backend)
+
+Plus shared templates at the top level: `client.tmpl`, `client-with-responses.tmpl`, `typedef.tmpl`, `param-types.tmpl`, `request-bodies.tmpl`, `inline.tmpl`, `imports.tmpl`, `constants.tmpl`, `server-urls.tmpl`, `additional-properties.tmpl`, `union.tmpl`, `union-and-additional-properties.tmpl`.
+
+When a PR modifies a template, ask:
+
+- **Does this change apply to other backends?** A bug fix or new feature in one backend's template often needs an analogous fix in the others. The implementation will not be identical — each framework has its own routing, middleware, and parameter-binding idioms — but the *intent* should usually be applied everywhere it is relevant.
+- **If only one backend is touched, is that intentional?** A change scoped to a single backend may be correct (e.g., a Fiber-specific bug, a Gin-specific middleware quirk). If so, the PR description should explain why. If there is no such explanation and the change looks generally applicable, flag it.
+- **Did the strict-server templates need a corresponding update?** Strict-mode wraps the per-backend handlers and frequently needs parallel changes.
+- **Were the integration tests in `internal/test/` updated?** This module imports every framework and is the primary place backend-parity bugs surface.
+
+Be pragmatic: do not demand identical changes in seven places. Do your best to assess whether a change is conceptually backend-agnostic (most template changes are) or genuinely backend-specific (some are), and flag missing parity only when the change looks generally applicable.
+
+## 5. Dependencies
+
+- Watch out for users making `go.mod` changes which advance the Go version to a new minor release. We want these to be explicitly justified in the commit message. Maintenance version bumps are ok. Mention that the maintainers would prefer to do a minor version bump themselves.
+- Watch out for unnecessary dependency changes that creep into code reviews, just because people tend to do it out of habit. Every dependency update should have a reason if it's bundled with codegen changes.
+
+## 6. General
+
+- The repo is a multi-module monorepo. Cross-module changes (e.g., to `runtime/` consumers) deserve extra scrutiny.
+- `internal/test/` contains regression tests keyed to GitHub issues. New bug fixes should generally include a regression test there.
+- Generated files are committed; CI fails if `make generate` produces a diff. If a PR's generated files look stale, that will fail CI regardless — but flagging it in review saves a round-trip.
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000000..9790225376
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,103 @@
+## Contributing
+
+If you're interested in contributing to `oapi-codegen`, the first thing we have to say is thank you! We'd like to extend our gratitude to anyone who takes the time to improve this project.
+
+`oapi-codegen` is being actively maintained, however the two people who do so are very busy, and can only set aside time for this project every once in a while, so our release cadence is slow and conservative.
+
+> [!NOTE]
+> We're actively considering what needs to change to make `oapi-codegen` more sustainable, and hope that we can share soon some options.
+
+This guide is a starting point, and we'll absolutely improve it on an ongoing basis. We've managed to go ~4 years without a substantial guide like this - sometimes to the detriment of contributors - and would love to keep improving this guide, and the project, for the best of the community.
+
+### When may we not change things?
+
+Generating code which others depend on, which is based on something as complex as OpenAPI is fraught with many edge cases, and we prefer to leave things as they are if there is a reasonable workaround.
+
+We'll try to avoid adding too much noise into generated code, or introduce breaking changes (as per SemVer). See also "Backwards compatibility" in the README.
+
+### Raising a bug
+
+If you believe you have encountered a bug, please raise an issue.
+
+> [!TIP]
+> Please follow the [minimal reproductions](#minimal-reproductions) documentation to improve our ability to support triaging
+
+This may get converted into a feature request if we don't deem it a bug, but a missing feature.
+
+### Asking a question
+
+We'd prefer that questions about "how do I use (this feature)?" or "what do the community think about ...?" get asked using [GitHub Discussions](https://github.com/oapi-codegen/oapi-codegen/discussions) which allow the community to answer them more easily.
+
+### Making changes that tweak generated code
+
+If you are making changes to the codebase that affects the code that gets generated, you will need to make sure that you have regenerated any generated test cases in the codebase using `make generate`.
+
+These generated test cases and examples provide a means to not only validate the functionality, but as they are checked in to source code, allow us to see if there are any subtle issues or breaking changes.
+
+> [!NOTE]
+> Significant changes to generated code are unlikely to be merged, especially in cases where there would be a breaking change that all consumers would have to respond to i.e. renaming a function or changing the function signature.
+>
+> However, if we can make this an opt-in feature (using the `output-options` configuration object) then that would be our preference.
+
+### Feature enhancements
+
+It's great that you would like to improve `oapi-codegen` and add new futures.
+
+We would prefer there be an issue raised for a feature request first, especially if it may be a duplicate of existing requests. However, sometimes that isn't possible - or takes longer than the code changes required - so it can be excused.
+
+Features that amend the way existing codegen works should - ideally - be behind an opt-in feature flag using the `output-options` configuration object.
+
+### Minimal reproductions
+
+> [!TIP]
+> The minimal reproductions for bugs may get taken into the codebase (licensed under `Apache-2.0`) as a test-case for future regression testing
+>
+> However, this can only be done if you license the code under `Apache-2.0` itself - if you are comfortable doing so, please do.
+
+When raising a bug report, or asking a question about functionality, it's super helpful if you can share:
+
+- The version of `oapi-codegen` you're using
+ - You _may_ get asked to update to a later - or latest - version, to see if the issue persists
+- The YAML configuration file you're using
+- The OpenAPI spec you're using
+ - However, we would prefer it only be the _absolute minimum_ specification, to limit the noise while trying to debug the issue, and to reduce information exposure from internal API development
+- What problem you're seeing
+- What the expected behaviour is
+- What version of Go you're using
+
+> [!CAUTION]
+> When sharing a minimal reproduction, please be aware of sharing any internal information about the APIs you're developing, or any sensitive Intellectual Property.
+
+### Before you raise a PR
+
+> [!NOTE]
+> Please raise PRs from a branch that isn't the `master` or `main` branch on your repo. This generally means that as maintainers, we can't push changes to the branch directly.
+
+Before you send the PR, please run the following commands locally:
+
+```sh
+make tidy
+make test
+make generate
+make lint
+```
+
+It is important to use the `make` tasks due to the way we're (ab)using the Go module system to split the project into multiple modules to reduce our dependency bloat in the main module.
+
+These are also run in GitHub Actions, across a number of Go releases.
+
+It's recommended to raise a draft PR first, so you can get feedback on the PR from GitHub, and review your own changes, before getting the attention of a maintainer.
+
+Once your draft PR passes basic CI, remove the draft status, and at that point, the [Greptile](https://www.greptile.com/) code review system, in addition to the maintainers, will go over your code.
+It doesn't re-review updates, to save on costs, so if you would like a second review, tag `@greptileai` in one of your responses to the comments, and ask it
+to redo the review, or push back if you think it's wrong. We've got it set very conservatively, but we've configured it with guidance on what to
+watch for in PR's, since over the years, we've learned the pain points.
+
+### "Should I @-mention the maintainers on an issue"
+
+Please try to avoid pinging the maintainers in an issue, Pull Request, or discussion.
+
+> [!NOTE]
+> We're actively considering what needs to change to make `oapi-codegen` more sustainable, and hope that we can share soon some options.
+
+The project is run on a volunteer basis, and as such, tagging us on issues - especially if you've just raised them - is largely unhelpful. We monitor the issues and work to triage them as best we can with the time we have allocated for it.
diff --git a/Makefile b/Makefile
index a765d6c295..5b72cd3840 100644
--- a/Makefile
+++ b/Makefile
@@ -6,27 +6,47 @@ help:
@echo "Targets:"
@echo " generate: regenerate all generated files"
@echo " test: run all tests"
- @echo " gin_example generate gin example server code"
@echo " tidy tidy go mod"
+ @echo " lint lint the project"
$(GOBIN)/golangci-lint:
- curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(GOBIN) v1.54.0
+ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/main/install.sh | sh -s -- -b $(GOBIN) v2.12.2
.PHONY: tools
tools: $(GOBIN)/golangci-lint
lint: tools
- git ls-files go.mod '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && $(GOBIN)/golangci-lint run ./...'
+ # run the root module explicitly, to prevent recursive calls by re-invoking `make ...` top-level
+ $(GOBIN)/golangci-lint run ./...
+ # then, for all child modules, use a module-managed `Makefile`
+ git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && env GOBIN=$(GOBIN) make lint'
lint-ci: tools
- git ls-files go.mod '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && $(GOBIN)/golangci-lint run ./... --out-format=github-actions --timeout=5m'
+ # for the root module, explicitly run the step, to prevent recursive calls
+ $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m
+ # then, for all child modules, use a module-managed `Makefile`
+ git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && env GOBIN=$(GOBIN) make lint-ci'
generate:
- git ls-files go.mod '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && go generate ./...'
+ # for the root module, explicitly run the step, to prevent recursive calls
+ go generate ./...
+ # then, for all child modules, use a module-managed `Makefile`
+ git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make generate'
test:
- git ls-files go.mod '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && go test -cover ./...'
+ # for the root module, explicitly run the step, to prevent recursive calls
+ go test -cover ./...
+ # then, for all child modules, use a module-managed `Makefile`
+ git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make test'
tidy:
- @echo "tidy..."
- git ls-files go.mod '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && go mod tidy'
+ # for the root module, explicitly run the step, to prevent recursive calls
+ go mod tidy
+ # then, for all child modules, use a module-managed `Makefile`
+ git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make tidy'
+
+tidy-ci:
+ # for the root module, explicitly run the step, to prevent recursive calls
+ tidied -verbose
+ # then, for all child modules, use a module-managed `Makefile`
+ git ls-files '**/*go.mod' -z | xargs -0 -I{} bash -xc 'cd $$(dirname {}) && make tidy-ci'
diff --git a/README.md b/README.md
index b9e6ddad70..c8d3d770ef 100644
--- a/README.md
+++ b/README.md
@@ -1,963 +1,4501 @@
-## OpenAPI Client and Server Code Generator
+# `oapi-codegen`
-⚠️ This README may be for the latest development version, which may contain
-unreleased changes. Please ensure you're looking at the README for the latest
-release version.
+[](https://www.bestpractices.dev/projects/9450)
-This package contains a set of utilities for generating Go boilerplate code for
-services based on
-[OpenAPI 3.0](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md)
-API definitions. When working with services, it's important to have an API
-contract which servers and clients both implement to minimize the chances of
-incompatibilities. It's tedious to generate Go models which precisely correspond to
-OpenAPI specifications, so let our code generator do that work for you, so that
-you can focus on implementing the business logic for your service.
+`oapi-codegen` is a command-line tool and library to convert OpenAPI specifications to Go code, be it [server-side implementations](#generating-server-side-boilerplate), [API clients](#generating-api-clients), or simply [HTTP models](#generating-api-models).
-We have chosen to focus on [Echo](https://github.com/labstack/echo) as
-our default HTTP routing engine, due to its speed and simplicity for the generated
-stubs. [Chi](https://github.com/go-chi/chi), [Gin](https://github.com/gin-gonic/gin),
-[gorilla/mux](https://github.com/gorilla/mux), [Fiber](https://github.com/gofiber/fiber), and
-[Iris](https://github.com/kataras/iris) have also been added by contributors as additional routers.
-We chose Echo because the `Context` object is a mockable interface, and it allows for some advanced
-testing.
+Using `oapi-codegen` allows you to reduce the boilerplate required to create or integrate with services based on [OpenAPI 3.0](https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md), and instead focus on writing your business logic, and working on the real value-add for your organisation.
-This package tries to be too simple rather than too generic, so we've made some
-design decisions in favor of simplicity, knowing that we can't generate strongly
-typed Go code for all possible OpenAPI Schemas. If there is a way to accomplish
-something via utility code or reflection, it's probably a better approach than
-code generation, which is fragile due to the very dynamic nature of OpenAPI and
-the very static nature of Go.
+With `oapi-codegen`, there are a few [Key Design Decisions](#key-design-decisions) we've made, including:
-## Contributing
+- idiomatic Go, where possible
+- fairly simple generated code, erring on the side of duplicate code over nicely refactored code
+- supporting as much of OpenAPI 3.x as is possible, alongside Go's type system
-I would like to pre-emptively extend my gratitude to anyone who takes the time
-to improve this project.
+`oapi-codegen` is one part of a wider ecosystem, which can be found described in further detail in the [oapi-codegen organisation on GitHub](https://github.com/oapi-codegen).
-Oapi-codegen is being actively maintained, however the two people who do so
-are very busy, and can only set aside time for this project every once in a while,
-so our release cadence is slow and conservative.
+⚠️ This README may be for the latest development version, which may contain unreleased changes. Please ensure you're looking at the README for the latest release version.
-Generating code which others depend on, which is based on something as complex
-as OpenAPI is fraught with many edge cases, and we prefer to leave things as
-they are if there is a reasonable workaround.
+## Action Required: The repository for this project has changed
-If you do find a case where oapi-codegen is broken, and would like to submit a PR,
-we are very grateful, and will happily look at it.
+As announced in [May 2024](https://github.com/oapi-codegen/oapi-codegen/discussions/1605),
+we have moved the project from the deepmap organization to our own organization, and you will need to update your
+import paths to pull updates past this point. You need to do a recursive search/replace from
+`github.com/deepmap/oapi-codegen/v2` to `github.com/oapi-codegen/oapi-codegen/v2`.
-Since most commits affect generated code, before sending your PR, please
-ensure that all boilerplate has been regenerated. You can do this from the top level
-of the repository by running:
+> [!IMPORTANT]
+> `oapi-codegen` moved to its new home with the version tag `v2.3.0`.
- make generate
+If you are using `v2.2.0` or below, please install like so:
-I realize that our code isn't entirely idiomatic with respect to comments, and
-variable naming and initialisms, especially the generated code, but I'm reluctant
-to merge PR's which change this, due to the breakage they will cause for others. If
-you rename anything under `/pkg` or change the names of variables in generated
-code, you will break other people's code. It's safe to rename internal names.
+```sh
+# for the binary install
+go install github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@v2.2.0
+```
+
+If you are using `v2.3.0` or above, please install like so, using the new module import path:
+
+```sh
+# for the binary install
+go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
+```
+
+## Install
+
+It is recommended to follow [the `go tool` support available from Go 1.24+](https://www.jvt.me/posts/2025/01/27/go-tools-124/) for managing the dependency of `oapi-codegen` alongside your core application.
+
+To do this, you run `go get -tool`:
+
+```sh
+$ go get -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
+# this will then modify your `go.mod`
+```
+
+From there, each invocation of `oapi-codegen` would be used like so:
+
+```go
+//go:generate go tool oapi-codegen -config cfg.yaml ../../api.yaml
+```
+
+Alternatively, you can install it as a binary with:
+
+```sh
+$ go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
+$ oapi-codegen -version
+```
+
+Which then means you can invoke it like so:
+
+```go
+//go:generate oapi-codegen --config=config.yaml ../../api.yaml
+```
+
+Note that you can also [move your `tools.go` into its own sub-module](https://www.jvt.me/posts/2024/09/30/go-tools-module/) to reduce the impact on your top-level `go.mod`.
+
+### Pinning to commits
+
+While the project does not ([yet](https://github.com/oapi-codegen/oapi-codegen/issues/1519)) have a defined release cadence, there may be cases where you want to pull in yet-unreleased changes to your codebase.
+
+Therefore, you may want to pin your dependency on `oapi-codegen` to a given commit hash, rather than a tag.
+
+This is **officially recommended** for consumers of `oapi-codegen`, who want features/bug fixes that haven't yet been released.
+
+We aim to keep the default branch ready-to-release so you should be able to safely pin.
+
+To do so, you can run:
+
+```sh
+# pin to the latest version on the default branch
+$ go get github.com/oapi-codegen/oapi-codegen/v2@main
+# alternatively, to a commit hash i.e. https://github.com/oapi-codegen/oapi-codegen/commit/71e916c59688a6379b5774dfe5904ec222b9a537
+$ go get github.com/oapi-codegen/oapi-codegen/v2@71e916c59688a6379b5774dfe5904ec222b9a537
+```
+
+This will then make a change such as:
+
+```diff
+diff --git go.mod go.mod
+index 44f29a4..436a780 100644
+--- go.mod
++++ go.mod
+@@ -2,21 +2,20 @@
+-require github.com/oapi-codegen/oapi-codegen/v2 v2.1.0
++require github.com/oapi-codegen/oapi-codegen/v2 v2.1.1-0.20240331212514-80f0b978ef16
+```
+
+## Usage
+
+`oapi-codegen` is largely configured using a YAML configuration file, to simplify the number of flags that users need to remember, and to make reading the `go:generate` command less daunting.
+
+For full details of what is supported, it's worth checking out [the GoDoc for `codegen.Configuration`](https://pkg.go.dev/github.com/oapi-codegen/oapi-codegen/v2/pkg/codegen#Configuration).
+
+We also have [a JSON Schema](configuration-schema.json) that can be used by IDEs/editors with the Language Server Protocol (LSP) to perform intelligent suggestions, i.e.:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/v2.7.1/configuration-schema.json
+package: api
+# ...
+```
+
+Note that it's recommended to pin to a specific version of the configuration schema, so it matches the version of `oapi-codegen` you're using. For instance, if you're using [Renovate](https://docs.renovatebot.com/), you can [have Renovate automagically update this version for you](https://www.jvt.me/posts/2026/03/01/oapi-codegen-config-renovate/).
+
+### Backwards compatibility
+
+Although we strive to retain backwards compatibility - as a project that's using a stable API per SemVer - there are sometimes opportunities we must take to fix a bug that could cause a breaking change for [people relying upon the behaviour](https://xkcd.com/1172/).
+
+In this case, we will expose a [compatibility option](https://pkg.go.dev/github.com/oapi-codegen/oapi-codegen/v2/pkg/codegen#CompatibilityOptions) to restore old behaviour.
+
+## Features
+
+At a high level, `oapi-codegen` supports:
+
+- Generating server-side boilerplate for [a number of servers](#supported-servers) ([docs](#generating-server-side-boilerplate))
+- Generating client API boilerplate ([docs](#generating-api-clients))
+- Generating the types ([docs](#generating-api-models))
+- Splitting large OpenAPI specs across multiple packages([docs](#import-mapping))
+ - This is also known as "Import Mapping" or "external references" across our documentation / discussion in GitHub issues
+
+## What does it look like?
+
+Below we can see a trimmed down example taken from the OpenAPI Petstore [example](examples/petstore-expanded/stdhttp/api/petstore.gen.go):
+
+```go
+// generated code
+
+type ServerInterface interface {
+ // ...
+ // Returns all pets
+ // (GET /pets)
+ FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams)
+ // ...
+}
+
+// FindPets operation middleware
+func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params FindPetsParams
+
+ // ------------- Optional query parameter "tags" -------------
+
+ err = runtime.BindQueryParameter("form", true, false, "tags", r.URL.Query(), ¶ms.Tags)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err})
+ return
+ }
+
+ // ------------- Optional query parameter "limit" -------------
+
+ err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), ¶ms.Limit)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.FindPets(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ m.HandleFunc("GET "+options.BaseURL+"/pets", wrapper.FindPets)
+
+ return m
+}
+```
+
+Then, in your own code, you implement the underlying logic for the `FindPets` implementation:
+
+```go
+type PetStore struct {
+ Pets map[int64]Pet
+ NextId int64
+ Lock sync.Mutex
+}
+
+// Make sure we conform to ServerInterface
+
+var _ ServerInterface = (*PetStore)(nil)
+
+func NewPetStore() *PetStore {
+ return &PetStore{
+ Pets: make(map[int64]Pet),
+ NextId: 1000,
+ }
+}
+
+// FindPets implements all the handlers in the ServerInterface
+func (p *PetStore) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) {
+ p.Lock.Lock()
+ defer p.Lock.Unlock()
+
+ var result []Pet
+
+ for _, pet := range p.Pets {
+ if params.Tags != nil {
+ // If we have tags, filter pets by tag
+ for _, t := range *params.Tags {
+ if pet.Tag != nil && (*pet.Tag == t) {
+ result = append(result, pet)
+ }
+ }
+ } else {
+ // Add all pets if we're not filtering
+ result = append(result, pet)
+ }
+
+ if params.Limit != nil {
+ l := int(*params.Limit)
+ if len(result) >= l {
+ // We're at the limit
+ break
+ }
+ }
+ }
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(result)
+}
+```
+
+As we can see, `oapi-codegen` simplifies some of the boilerplate by taking parameters out of the request and instead allows us to focus on the implementation.
+
+You'll note that there's still a bit more marshaling of request/response data, which is further reduced by using the [Strict server](#strict-server) functionality.
+
+
+When using the strict server, you'll have the following generated code:
+
+```go
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+ // ...
+ // Returns all pets
+ // (GET /pets)
+ FindPets(ctx context.Context, request FindPetsRequestObject) (FindPetsResponseObject, error)
+ // ...
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+// FindPets operation middleware
+func (sh *strictHandler) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) {
+ var request FindPetsRequestObject
+
+ request.Params = params
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.FindPets(ctx, request.(FindPetsRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "FindPets")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(FindPetsResponseObject); ok {
+ if err := validResponse.VisitFindPetsResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+```
+
+Then, in your own code, you implement the underlying logic for the `FindPets` implementation:
+
+```go
+// Make sure we conform to StrictServerInterface
+
+var _ StrictServerInterface = (*PetStore)(nil)
+
+func NewPetStore() *PetStore {
+ return &PetStore{
+ Pets: make(map[int64]Pet),
+ NextId: 1000,
+ }
+}
+
+// FindPets implements all the handlers in the ServerInterface
+func (p *PetStore) FindPets(ctx context.Context, request FindPetsRequestObject) (FindPetsResponseObject, error) {
+ p.Lock.Lock()
+ defer p.Lock.Unlock()
+
+ var result []Pet
+
+ for _, pet := range p.Pets {
+ if request.Params.Tags != nil {
+ // If we have tags, filter pets by tag
+ for _, t := range *request.Params.Tags {
+ if pet.Tag != nil && (*pet.Tag == t) {
+ result = append(result, pet)
+ }
+ }
+ } else {
+ // Add all pets if we're not filtering
+ result = append(result, pet)
+ }
+
+ if request.Params.Limit != nil {
+ l := int(*request.Params.Limit)
+ if len(result) >= l {
+ // We're at the limit
+ break
+ }
+ }
+ }
+
+ return FindPets200JSONResponse(result), nil
+}
+```
+
+We can see that this provides the best means to focus on the implementation of the business logic within the endpoint, rather than (un)marshalling types to and from JSON, or wrangling cookies or headers.
+
+## Key design decisions
+
+- Produce an interface that can be satisfied by your implementation, with reduced boilerplate
+- Bulk processing and parsing of OpenAPI document in Go
+- Resulting output is using Go's `text/template`s, which are user-overridable
+- Attempts to produce Idiomatic Go
+- Single-file output
+- Support multiple OpenAPI files by having a package-per-OpenAPI file
+- Support of OpenAPI 3.0
+ - OpenAPI 3.1 support is [awaiting upstream support](https://github.com/oapi-codegen/oapi-codegen/issues/373)
+ However, we do have an experimental version using a different OpenAPI parser which does support 3.1 and 3.2, which
+ you can play around with in our [experimental repo](https://github.com/oapi-codegen/oapi-codegen-exp/tree/main/experimental)
+ - Note that this does not include OpenAPI 2.0 (aka Swagger)
+- Extract parameters from requests, to reduce work required by your implementation
+- Implicit `additionalProperties` are ignored by default ([more details](#additional-properties-additionalproperties))
+- Prune unused types by default
+
+## Generating server-side boilerplate
+
+`oapi-codegen` shines by making it fairly straightforward (note that this is a purposeful choice of wording here - we want to avoid words like "easy") to generate the server-side boilerplate for a backend API.
+
+Below you can find the supported servers, and more information about how to implement a server using them.
+
+To provide you a fully Test Driven Development style test harness to confirm you are following the specification, you could use a tool such as [openapi.tanna.dev/go/validator](https://openapi.tanna.dev/go/validator/), or craft your own.
+
+### Supported Servers
+
+Right now, we support the following servers, and are supportive of adding new servers, too!
+
+
+
+
+
+Server
+
+
+generate flag to enable code generation
+
+
+Required Go Version
+
+
+Example usage
+
+
+
+
+
+
+[Chi](https://github.com/go-chi/chi)
+
+
+
+chi-server
+
+
+1.22+
+
+
+
+
+For a Chi server, you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: ...
+package: api
+generate:
+ chi-server: true
+ models: true
+output: gen.go
+```
+
+To implement this, check out [the Chi docs](#impl-chi).
+
+
+
+
+
+
+
+[Echo](https://github.com/labstack/echo)
+
+
+
+echo-server
+
+
+1.22+
+
+
+
+For an Echo server, you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: ...
+package: api
+generate:
+ echo-server: true
+ models: true
+output: gen.go
+```
+
+To implement this, check out [the Echo docs](#impl-echo).
+
+
+
+
+
+
+
+[Fiber](https://github.com/gofiber/fiber)
+
+
+
+fiber-server
+
+
+1.24+
+
+
+
+For a Fiber server, you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: ...
+package: api
+generate:
+ fiber-server: true
+ models: true
+output: gen.go
+```
+
+To implement this, check out [the Fiber docs](#impl-fiber).
+
+
+
+
+
+
+
+
+[Gin](https://github.com/gin-gonic/gin)
+
+
+
+gin-server
+
+
+1.22+
+
+
+
+For a Gin server, you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: ...
+package: api
+generate:
+ gin-server: true
+ models: true
+output: gen.go
+```
+
+To implement this, check out [the Gin docs](#impl-gin).
+
+
+
+
+
+
+
+
+[gorilla/mux](https://github.com/gorilla/mux)
+
+
+
+gorilla-server
+
+
+1.22+
+
+
+
+For a gorilla/mux server, you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: ...
+package: api
+generate:
+ gorilla-server: true
+ models: true
+output: gen.go
+```
+
+To implement this, check out [the gorilla/mux docs](#impl-gorillamux).
+
+
+
+
+
+
+
+[Iris](https://github.com/kataras/iris)
+
+
+
+iris-server
+
+
+1.22+
+
+
+
+For a Iris server, you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: ...
+package: api
+generate:
+ iris-server: true
+ models: true
+output: gen.go
+```
+
+To implement this, check out [the Iris docs](#impl-iris).
+
+
+
+
+
+
+
+[1.22+ `net/http`](https://pkg.go.dev/net/http)
+
+
+
+std-http-server
+
+
+1.22+
+
+
+
+To use purely `net/http` (for Go 1.22+), you will want a configuration file such as:
+
+```yaml
+# yaml-language-server: ...
+package: api
+generate:
+ std-http-server: true
+ models: true
+output: gen.go
+```
+
+To implement this, check out [the Go 1.22+ `net/http` docs](#impl-stdhttp).
+
+
+
+
+
+
+### Go 1.22+ `net/http`
+
+
+As of Go 1.22, enhancements have been made to the routing of the `net/http` package in the standard library, which makes it a great starting point for implementing a server with, before needing to reach for another router or a full framework.
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(w http.ResponseWriter, r *http.Request)
+}
+
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ // ... omitted for brevity
+
+ m.HandleFunc("GET "+options.BaseURL+"/ping", wrapper.GetPing)
+
+ return m
+}
+```
+
+To implement this HTTP server, we need to write the following code in our [`api/impl.go`](examples/minimal-server/stdhttp/api/impl.go):
+
+```go
+import (
+ "encoding/json"
+ "net/http"
+)
+
+// optional code omitted
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+ "net/http"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/stdhttp/api"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ r := http.NewServeMux()
+
+ // get an `http.Handler` that we can use
+ h := api.HandlerFromMux(server, r)
+
+ s := &http.Server{
+ Handler: h,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
+
+> [!NOTE]
+> If you feel like you've done everything right, but are still receiving `404 page not found` errors, make sure that you've got the `go` directive in your `go.mod` updated to:
+
+```go.mod
+go 1.22
+```
+
+
+
+### Chi
+
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(w http.ResponseWriter, r *http.Request)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ // ...
+
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/ping", wrapper.GetPing)
+ })
+
+ return r
+}
+```
+
+To implement this HTTP server, we need to write the following code in our [`api/impl.go`](examples/minimal-server/chi/api/impl.go):
+
+```go
+import (
+ "encoding/json"
+ "net/http"
+)
+
+// optional code omitted
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+ "net/http"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/chi/api"
+ "github.com/go-chi/chi/v5"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ r := chi.NewMux()
+
+ // get an `http.Handler` that we can use
+ h := api.HandlerFromMux(server, r)
+
+ s := &http.Server{
+ Handler: h,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
+
+### gorilla/mux
+
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(w http.ResponseWriter, r *http.Request)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ // ...
+
+ r.HandleFunc(options.BaseURL+"/ping", wrapper.GetPing).Methods("GET")
+
+ return r
+}
+```
+
+To implement this HTTP server, we need to write the following code in our [`api/impl.go`](examples/minimal-server/gorillamux/api/impl.go):
+
+```go
+import (
+ "encoding/json"
+ "net/http"
+)
+
+// optional code omitted
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+ "net/http"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/gorillamux/api"
+ "github.com/gorilla/mux"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ r := mux.NewRouter()
+
+ // get an `http.Handler` that we can use
+ h := api.HandlerFromMux(server, r)
+
+ s := &http.Server{
+ Handler: h,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
+
+### Echo server
+
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(ctx echo.Context) error
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ // ...
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ // ...
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithBaseURL(router, si, "")
+}
+
+// Registers handlers, and prepends BaseURL to the paths, so that the paths
+// can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ // ...
+
+ router.GET(baseURL+"/ping", wrapper.GetPing)
+
+}
+```
+
+To implement this HTTP server, we need to write the following code in our [`api/impl.go`](examples/minimal-server/echo/api/impl.go):
+
+```go
+import (
+ "net/http"
+
+ "github.com/labstack/echo/v4"
+)
+
+// optional code omitted
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(ctx echo.Context) error {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ return ctx.JSON(http.StatusOK, resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/echo/api"
+ "github.com/labstack/echo/v4"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ e := echo.New()
+
+ api.RegisterHandlers(e, server)
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(e.Start("0.0.0.0:8080"))
+}
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
+
+### Fiber server
+
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(c *fiber.Ctx) error
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router fiber.Router, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, FiberServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
+ // ...
+
+ router.Get(options.BaseURL+"/ping", wrapper.GetPing)
+}
+```
+
+To implement this HTTP server, we need to write the following code in our [`api/impl.go`](examples/minimal-server/fiber/api/impl.go):
+
+```go
+import (
+ "net/http"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+// ensure that we've conformed to the `ServerInterface` with a compile-time check
+var _ ServerInterface = (*Server)(nil)
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(ctx *fiber.Ctx) error {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ return ctx.
+ Status(http.StatusOK).
+ JSON(resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/fiber/api"
+ "github.com/gofiber/fiber/v2"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ app := fiber.New()
+
+ api.RegisterHandlers(app, server)
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(app.Listen("0.0.0.0:8080"))
+}
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
+
+### Gin server
+
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(c *gin.Context)
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router gin.IRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, GinServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) {
+ // ...
+
+ router.GET(options.BaseURL+"/ping", wrapper.GetPing)
+}
+```
+
+To implement this HTTP server, we need to write the following code in our [`api/impl.go`](examples/minimal-server/gorillamux/api/impl.go):
+
+```go
+import (
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+)
+
+// optional code omitted
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(ctx *gin.Context) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ ctx.JSON(http.StatusOK, resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+ "net/http"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/gin/api"
+ "github.com/gin-gonic/gin"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ r := gin.Default()
+
+ api.RegisterHandlers(r, server)
+
+ // And we serve HTTP until the world ends.
+
+ s := &http.Server{
+ Handler: r,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
+
+### Iris server
+
+
+For instance, let's take this straightforward specification:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+```
+
+This then generates code such as:
+
+```go
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(ctx iris.Context)
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router *iris.Application, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, IrisServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router *iris.Application, si ServerInterface, options IrisServerOptions) {
+ // ...
+
+ router.Get(options.BaseURL+"/ping", wrapper.GetPing)
+
+ router.Build()
+}
+```
+
+To implement this HTTP server, we need to write the following code in our [`api/impl.go`](examples/minimal-server/gorillamux/api/impl.go):
+
+```go
+import (
+ "net/http"
+
+ "github.com/kataras/iris/v12"
+)
+
+// optional code omitted
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(ctx iris.Context) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ ctx.StatusCode(http.StatusOK)
+ _ = ctx.JSON(resp)
+}
+```
+
+Now we've got our implementation, we can then write the following code to wire it up and get a running server:
+
+```go
+import (
+ "log"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/iris/api"
+ "github.com/kataras/iris/v12"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ i := iris.Default()
+
+ api.RegisterHandlers(i, server)
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(i.Listen("0.0.0.0:8080"))
+}
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
+
+### Strict server
+
+`oapi-codegen` also supports generating a server that is much more strict with the contract that the implementer requires, and takes inspiration from server-side code generation for RPC servers.
+
+This takes the boilerplate reduction from the non-strict servers and adds additional boilerplate reduction, allowing you to make the following changes to your function signatures:
+
+```diff
+-FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams)
++FindPets(ctx context.Context, request FindPetsRequestObject) (FindPetsResponseObject, error)
+```
+
+This is the highest level of strictness that `oapi-codegen` supports right now, and it's a good idea to start with this if you want the most guardrails to simplify developing your APIs.
+
+The strict server has support for:
+
+- multiple request/response media types and status codes on a given operation
+- first-class support for `multipart/form-data` and `application/x-www-form-urlencoded` requests
+- returning an [HTTP 500 Internal Server Error](https://http.cat/500), when an `error` is returned from a function
+- automagic (un)marshalling of request/responses, and setting `content-type` and HTTP status codes on responses
+- binding request values to a struct, a `multipart.Reader` or providing a `io.Reader`
+
+You can see a little more detail of the generated code in the ["What does it look like"](#what-does-it-look-like-strict) section.
+
+> [!NOTE]
+> To configure the strict server generation, you must specify another server to be generated. For instance:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: api
+generate:
+ # NOTE another server must be added!
+ chi-server: true
+ strict-server: true
+output: server.gen.go
+```
+
+> [!NOTE]
+> This doesn't include [validation of incoming requests](#requestresponse-validation-middleware).
+
+> [!IMPORTANT]
+> When a strict-server spec uses `$ref` to point at a `components/responses/...` (or `components/requestBodies/...`) defined in another spec via `import-mapping`, the destination spec **must also be generated with `strict-server: true`**. The strict envelope embeds the `JSONResponse` type from the destination package; that type only exists when the destination generates a strict server. Without it the generated code will fail to compile with an "undefined" error. See [issue #2010](https://github.com/oapi-codegen/oapi-codegen/issues/2010).
+
+## Generating API clients
+
+As well as generating the server-side boilerplate, `oapi-codegen` can also generate API clients.
+
+This aims to be an API client that can be used to interact with the methods of the API, and is perfectly suited for production usage.
+
+However, if you were looking for a slightly more SDK-style approach, or a mix of generated tests and/or documentation, this API client may not be for you, and you may want to look at alternate tooling.
+
+For instance, given an `api.yaml`:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Generate models
+paths:
+ /client:
+ get:
+ operationId: getClient
+ responses:
+ 200:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ClientType"
+ put:
+ operationId: updateClient
+ responses:
+ 400:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ code:
+ type: string
+ required:
+ - code
+components:
+ schemas:
+ ClientType:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ # NOTE that this is not generated by default because it's not referenced. If you want it, you need to use the following YAML configuration:
+ #
+ # output-options:
+ # skip-prune: true
+ Unreferenced:
+ type: object
+ required:
+ - id
+ properties:
+ id:
+ type: integer
+```
+
+And a `cfg.yaml`:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: client
+output: client.gen.go
+generate:
+ models: true
+ client: true
+```
+
+And a `generate.go`:
+
+```go
+package client
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
+```
+
+This would then generate:
+
+```go
+package client
+
+// ...
+
+// ClientType defines model for ClientType.
+type ClientType struct {
+ Name string `json:"name"`
+}
+
+// ...
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ...
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetClient request
+ GetClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // UpdateClient request
+ UpdateClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+// ...
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetClientWithResponse request
+ GetClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetClientResponse, error)
+
+ // UpdateClientWithResponse request
+ UpdateClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*UpdateClientResponse, error)
+}
+
+type GetClientResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *ClientType
+}
+
+// ...
+```
+
+With this generated client, it is then possible to construct and utilise the client, for instance:
+
+```go
+package client_test
+
+import (
+ "context"
+ "fmt"
+ "log"
+ "net/http"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/client"
+)
+
+func TestClient_canCall() {
+ // custom HTTP client
+ hc := http.Client{}
+
+ // with a raw http.Response
+ {
+ c, err := client.NewClient("http://localhost:1234", client.WithHTTPClient(&hc))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ resp, err := c.GetClient(context.TODO())
+ if err != nil {
+ log.Fatal(err)
+ }
+ if resp.StatusCode != http.StatusOK {
+ log.Fatalf("Expected HTTP 200 but received %d", resp.StatusCode)
+ }
+ }
+
+ // or to get a struct with the parsed response body
+ {
+ c, err := client.NewClientWithResponses("http://localhost:1234", client.WithHTTPClient(&hc))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ resp, err := c.GetClientWithResponse(context.TODO())
+ if err != nil {
+ log.Fatal(err)
+ }
+ if resp.StatusCode() != http.StatusOK {
+ log.Fatalf("Expected HTTP 200 but received %d", resp.StatusCode())
+ }
+
+ fmt.Printf("resp.JSON200: %v\n", resp.JSON200)
+ }
+
+}
+```
+
+### With Server URLs
+
+An OpenAPI specification makes it possible to denote Servers that a client can interact with, such as:
+
+```yaml
+servers:
+- url: https://development.gigantic-server.com/v1
+ description: Development server
+- url: https://{username}.gigantic-server.com:{port}/{basePath}
+ description: The production API server
+ variables:
+ username:
+ # note! no enum here means it is an open value
+ default: demo
+ description: this value is assigned by the service provider, in this example `gigantic-server.com`
+ port:
+ enum:
+ - '8443'
+ - '443'
+ default: '8443'
+ basePath:
+ # open meaning there is the opportunity to use special base paths as assigned by the provider, default is `v2`
+ default: v2
+```
+
+It is possible to opt-in to the generation of these Server URLs with the following configuration:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: serverurls
+output: gen.go
+generate:
+ # NOTE that this uses default settings - if you want to use initialisms to generate i.e. `ServerURLDevelopmentServer`, you should look up the `output-options.name-normalizer` configuration
+ server-urls: true
+```
+
+This will then generate the following boilerplate:
+
+```go
+// (the below does not include comments that are generated)
+
+const ServerUrlDevelopmentServer = "https://development.gigantic-server.com/v1"
+
+type ServerUrlTheProductionAPIServerBasePathVariable string
+const ServerUrlTheProductionAPIServerBasePathVariableDefault = "v2"
+
+type ServerUrlTheProductionAPIServerPortVariable string
+const ServerUrlTheProductionAPIServerPortVariable8443 ServerUrlTheProductionAPIServerPortVariable = "8443"
+const ServerUrlTheProductionAPIServerPortVariable443 ServerUrlTheProductionAPIServerPortVariable = "443"
+const ServerUrlTheProductionAPIServerPortVariableDefault ServerUrlTheProductionAPIServerPortVariable = ServerUrlTheProductionAPIServerPortVariable8443
+
+type ServerUrlTheProductionAPIServerUsernameVariable string
+const ServerUrlTheProductionAPIServerUsernameVariableDefault = "demo"
+
+func ServerUrlTheProductionAPIServer(basePath ServerUrlTheProductionAPIServerBasePathVariable, port ServerUrlTheProductionAPIServerPortVariable, username ServerUrlTheProductionAPIServerUsernameVariable) (string, error) {
+ // ...
+}
+```
+
+Notice that for URLs that are not templated, a simple `const` definition is created.
+
+However, for more complex URLs that defined `variables` in them, we generate the types (and any `enum` values or `default` values), and instead use a function to create the URL.
+
+For a complete example see [`examples/generate/serverurls`](examples/generate/serverurls).
+
+### Duplicate types generated for clients's response object types
+
+When generating the types for interacting with the generated client, `oapi-codegen` will use the `operationId` and add on a `Request` or `Response` suffix.
+
+However, this can clash if you have named your component schemas in a similar way.
+
+For instance:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: "Show that generated client boilerplate can clash if schemas are well named i.e. `*Request` and `*Response`"
+paths:
+ /client:
+ put:
+ operationId: updateClient
+ requestBodies:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateClientRequest'
+ responses:
+ 400:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateClientResponse'
+components:
+ schemas:
+ UpdateClientRequest:
+ type: object
+ properties:
+ code:
+ type: string
+ required:
+ - code
+ UpdateClientResponse:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+```
+
+If you were to generate with this configuration:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: client
+output: client.gen.go
+generate:
+ models: true
+ client: true
+```
+
+This would then result in `go build` failures:
+
+```
+# github.com/oapi-codegen/oapi-codegen/v2/examples/clienttypenameclash
+./client.gen.go:184:6: UpdateClientResponse redeclared in this block
+ ./client.gen.go:17:6: other declaration of UpdateClientResponse
+./client.gen.go:192:7: r.HTTPResponse undefined (type UpdateClientResponse has no field or method HTTPResponse)
+./client.gen.go:193:12: r.HTTPResponse undefined (type UpdateClientResponse has no field or method HTTPResponse)
+./client.gen.go:200:7: r.HTTPResponse undefined (type UpdateClientResponse has no field or method HTTPResponse)
+./client.gen.go:201:12: r.HTTPResponse undefined (type UpdateClientResponse has no field or method HTTPResponse)
+./client.gen.go:224:3: unknown field Body in struct literal of type UpdateClientResponse
+./client.gen.go:225:3: unknown field HTTPResponse in struct literal of type UpdateClientResponse
+./client.gen.go:234:12: response.JSON400 undefined (type *UpdateClientResponse has no field or method JSON400)
+```
+
+To fix this, use the `response-type-suffix` Output Option:
+
+```diff
+ # yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+ package: client
+ output: client.gen.go
+ generate:
+ models: true
+ client: true
++output-options:
++ response-type-suffix: Resp
+```
+
+This will then rename the generated types from the default to use the new suffix:
+
+```diff
+-type UpdateClientResponse struct {
++type UpdateClientResp struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON400 *UpdateClientResponse
+ }
+```
+
+There is no currently planned work to change this behaviour.
+
+## Generating API models
+
+If you're looking to only generate the models for interacting with a remote service, for instance if you need to hand-roll the API client for whatever reason, you can do this as-is.
+
+> [!TIP]
+> Try to define as much as possible within the `#/components/schemas` object, as `oapi-codegen` will generate all the types here.
+>
+> Although we can generate some types based on inline definitions in i.e. a path's response type, it isn't always possible to do this, or if it is generated, can be a little awkward to work with as it may be defined as an anonymous struct.
+
+For instance, given an `api.yaml`:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Generate models
+paths:
+ /client:
+ get:
+ operationId: getClient
+ responses:
+ 200:
+ content:
+ application/json:
+ schema:
+ # NOTE that Client is generated here, because it's within #/components/schemas
+ $ref: "#/components/schemas/Client"
+ put:
+ operationId: updateClient
+ responses:
+ 400:
+ content:
+ application/json:
+ # NOTE that this anonymous object is /not/ generated because it's an anonymous, but would be generated if using `generate: client`
+ # See https://github.com/oapi-codegen/oapi-codegen/issues/1512
+ schema:
+ type: object
+ properties:
+ code:
+ type: string
+ required:
+ - code
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ # NOTE that this is not generated by default because it's not referenced. If you want it, you need to use the following YAML configuration:
+ #
+ # output-options:
+ # skip-prune: true
+ Unreferenced:
+ type: object
+ required:
+ - id
+ properties:
+ id:
+ type: integer
+```
+
+And a `cfg.yaml`:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: onlymodels
+output: only-models.gen.go
+generate:
+ models: true
+```
+
+And a `generate.go`:
+
+```go
+package onlymodels
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
+```
+
+This would then generate:
+
+```go
+package onlymodels
+
+// Client defines model for Client.
+type Client struct {
+ Name string `json:"name"`
+}
+```
+
+If you wish to also generate the `Unreferenced` type, you would need the following `cfg.yaml`:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: onlymodels
+output: only-models.gen.go
+generate:
+ models: true
+output-options:
+ # NOTE that this is only required for the `Unreferenced` type
+ skip-prune: true
+```
+
+For a complete example see [`examples/only-models`](examples/only-models).
+
+## Splitting large OpenAPI specs across multiple packages (aka "Import Mapping" or "external references")
+
+
+When you've got a large OpenAPI specification, you may find it useful to split the contents of the spec across multiple files, using external references, such as:
+
+```yaml
+ responses:
+ 200:
+ description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/User'
+```
+
+This is supported by `oapi-codegen`, through the ability to perform "Import Mapping".
+
+For instance, let's say that we have a large API, which has a user-facing API and an admin API, both of which use a common set of API models.
+
+In this case, we may have an Admin API that looks like:
+
+```yaml
+# admin/api.yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Admin API
+ description: The admin-only portion of the API, which has its own separate OpenAPI spec
+tags:
+ - name: admin
+ description: Admin API endpoints
+ - name: user
+ description: API endpoint that pertains to user data
+paths:
+ /admin/user/{id}:
+ get:
+ tags:
+ - admin
+ - user
+ summary: Get a user's details
+ operationId: getUserById
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 200:
+ description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '../common/api.yaml#/components/schemas/User'
+```
+
+This references the common spec:
+
+```yaml
+# common/api.yaml
+components:
+ schemas:
+ User:
+ type: object
+ additionalProperties: false
+ properties:
+ name:
+ type: string
+ required:
+ - name
+```
+
+So how do we get `oapi-codegen` to generate our code?
+
+### Using a single package with multiple OpenAPI specs
+
+
+
+> [!TIP]
+> Since `oapi-codegen` v2.4.0, it is now possible to split large OpenAPI specifications into the same Go package, using the "self" mapping (denoted by a `-`) when using Import Mapping.
+>
+> This is an improvement on the previous model, which would require splitting files across multiple packages.
+
+> [!NOTE]
+> You still need to have multiple `go generate`s, and any other configuration files.
+
+To get `oapi-codegen`'s single-package support working, we need multiple calls to `oapi-codegen`, one call per OpenAPI spec file:
+
+```sh
+$ go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg-api.yaml ../admin/api.yaml
+$ go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg-user.yaml ../common/api.yaml
+```
+
+This therefore means that we need multiple configuration files, such as `cfg-api.yaml`:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: samepackage
+output: server.gen.go
+generate:
+ models: true
+ chi-server: true
+ strict-server: true
+output-options:
+ # to make sure that all types are generated
+ skip-prune: true
+import-mapping:
+ user.yaml: "-"
+```
+
+And then our `cfg-user.yaml`:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: samepackage
+output: user.gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated
+ skip-prune: true
+```
+
+From here, `oapi-codegen` will generate multiple Go files, all within the same package, which can be used to break down your large OpenAPI specifications, and generate only the subsets of code needed for each part of the spec.
+
+Check out [the import-mapping/samepackage example](examples/import-mapping/samepackage) for the full code.
+
+### Using multiple packages, with one OpenAPI spec per package
+
+To get `oapi-codegen`'s multi-package support working, we need to set up our directory structure:
+
+```
+├── admin
+│ ├── cfg.yaml
+│ └── generate.go
+└── common
+ ├── cfg.yaml
+ └── generate.go
+```
+
+We could start with our configuration file for our admin API spec:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+# admin/cfg.yaml
+package: admin
+output: server.gen.go
+generate:
+ models: true
+ chi-server: true
+output-options:
+ # to make sure that all types are generated
+ skip-prune: true
+# NOTE that this won't work, as it's missing `import-mapping`
+```
+
+If we were to run `oapi-codegen`, this will fail with the following error
+
+```
+error generating code: error creating operation definitions: error generating response definitions: error generating request body definition: error turning reference (../common/api.yaml#/components/schemas/User) into a Go type: unrecognized external reference '../common/api.yaml'; please provide the known import for this reference using option --import-mapping
+```
+
+This is because `oapi-codegen` requires the `import-mapping`:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: admin
+output: server.gen.go
+generate:
+ models: true
+ chi-server: true
+output-options:
+ # to make sure that all types are generated
+ skip-prune: true
+import-mapping:
+ # for a given file/URL that is $ref'd, point `oapi-codegen` to the Go package that this spec is generated into, to perform Go package imports
+ ../common/api.yaml: github.com/oapi-codegen/oapi-codegen/v2/examples/import-mapping/common
+```
+
+This will then generate the following code:
+
+```go
+package admin
+
+import (
+ // ...
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/examples/import-mapping/common"
+)
+
+// User defines model for User.
+type User = externalRef0.User
+```
+
+If you don't want to do this, an alternate option is to [use a single package, with multiple OpenAPI spec files for that given package](#import-mapping-self) or to [bundle your multiple OpenAPI files](https://www.jvt.me/posts/2022/02/10/bundle-openapi/) into a single spec.
+
+Check out [the import-mapping/multiplepackages example](examples/import-mapping/multiplepackages/) for the full code.
+
+## Modifying the input OpenAPI Specification (with OpenAPI Overlay)
+
+Prior to `oapi-codegen` v2.4.0, users wishing to override specific configuration, for instance taking advantage of extensions such as `x-go-type` would need to modify the OpenAPI specification they are using.
+
+In a lot of cases, this OpenAPI specification would be produced by a different team to the consumers (or even a different company) and so asking them to make changes like this were unreasonable.
+
+This would lead to the API consumers needing to vendor the specification from the producer (which is [our recommendation anyway](#https-paths)) and then make any number of local changes to the specification to make it generate code that looks reasonable.
+
+However, in the case that a consumer would update their specification, they would likely end up with a number of merge conflicts.
+
+Now, as of `oapi-codegen` v2.4.0, it is now possible to make changes to the input OpenAPI specification _without needing to modify it directly_.
+
+This takes advantage of the [OpenAPI Overlay specification](https://github.com/OAI/Overlay-Specification), which is a stable specification.
+
+> [!CAUTION]
+> Beware! Here (may) be dragons.
+>
+> The Overlay specification requires the use of JSON Path, which some users may find difficult to write and/or maintain.
+>
+> We still heavily recommend using Overlay functionality, but would like users to be aware of this.
+>
+> There is a [proposed modification to the specification](https://github.com/OAI/Overlay-Specification/pull/32) which would relax the need for JSON Path as the targeting mechanism.
+
+For instance, let's say that we have the following OpenAPI specification, which provides insight into an internal endpoint that we should not be generating any code for (denoted by `x-internal`):
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: "Example to indicate how to use the OpenAPI Overlay specification (https://github.com/OAI/Overlay-Specification)"
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+ delete:
+ x-internal: true
+ responses:
+ '202':
+ content: {}
+```
+
+If we were to run `oapi-codegen` with out-of-the-box functionality, this would then lead to the DELETE endpoint being generated, which we don't want.
+
+Instead, we can define the following `overlay.yaml`:
+
+
+```yaml
+overlay: 1.0.0
+info:
+ title: Overlay
+ version: 0.0.0
+actions:
+- target: "$"
+ description: Perform a structural overlay, which can be more readable, as it's clear what the shape of the document is
+ update:
+ info:
+ x-overlay-applied: structured-overlay
+ paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: Perform a ping request
+- target: $.paths.*[?(@.x-internal)]
+ description: Remove internal endpoints (noted by x-internal)
+ remove: true
+- target: $.paths.*.*[?(@.x-internal)]
+ description: Remove internal endpoints (noted by x-internal)
+ remove: true
+```
+
+And our configuration file for `oapi-codegen`:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: api
+output: ping.gen.go
+generate:
+ models: true
+ gorilla-server: true
+ embedded-spec: true
+output-options:
+ overlay:
+ path: overlay.yaml
+```
+
+This then completely removes the DELETE endpoint _before_ we even start to parse the specification in `oapi-codegen`, so it's as if your specification was provided without that endpoint.
+
+Additionally, we can override other pieces of metadata, such as the description for operations.
+
+Check out [the overlay example](examples/overlay/) for the full code, and some more complex examples.
+
+## Generating Nullable types
+
+It's possible that you want to be able to determine whether a field isn't sent, is sent as `null` or has a value.
+
+For instance, if you had the following OpenAPI property:
+
+```yaml
+S:
+ type: object
+ properties:
+ Field:
+ type: string
+ nullable: true
+ required: []
+```
+
+The default behaviour in `oapi-codegen` is to generate:
+
+```go
+type S struct {
+ Field *string `json:"field,omitempty"`
+}
+```
+
+However, you lose the ability to understand the three cases, as there's no way to distinguish two of the types from each other:
+
+- is this field not sent? (Can be checked with `S.Field == nil`)
+- is this field `null`? (Can be checked with `S.Field == nil`)
+- does this field have a value? (`S.Field != nil && *S.Field == "123"`)
+
+As of `oapi-codegen` [v2.1.0](https://github.com/oapi-codegen/oapi-codegen/releases/tag/v2.1.0) it is now possible to represent this with the `nullable.Nullable` type from [our new library, oapi-codegen/nullable](https://github.com/oapi-codegen/nullable).
+
+If you configure your generator's Output Options to opt-in to this behaviour, as so:
+
+```yaml
+output-options:
+ nullable-type: true
+```
+
+You will now receive the following output:
+
+```go
+type S struct {
+ // note that there's no pointer here, just `omitempty`
+ Field nullable.Nullable[string] `json:"field,omitempty"`
+}
+```
+
+## OpenAPI extensions
+
+As well as the core OpenAPI support, we also support the following OpenAPI extensions, as denoted by the [OpenAPI Specification Extensions](https://spec.openapis.org/oas/v3.0.3#specification-extensions).
+
+The following extensions are supported:
+
+
+
+
+
+Extension
+
+
+Description
+
+
+
+
+
+
+`x-go-type`
+`x-go-type-import`
+
+
+
+Override the generated type definition (and optionally, add an import from another package)
+
+
+
+
+
+
+`x-go-type-skip-optional-pointer`
+
+
+
+Do not add a pointer type for optional fields in structs
+
+
+
+
+
+
+`x-go-name`
+
+
+
+Override the generated name of a field or a type
+
+
+
+
+
+
+`x-go-type-name`
+
+
+
+Override the generated name of a type
+
+
+
+
+
+
+`x-omitempty`
+
+
+
+Force the presence of the JSON tag `omitempty` on a field
+
+
+
+
+
+
+`x-omitzero`
+
+
+
+Force the presence of the JSON tag `omitzero` on a field
+
+
+
+
+
+
+`x-go-json-ignore`
+
+
+
+When (un)marshaling JSON, ignore field(s)
+
+
+
+
+
+
+`x-oapi-codegen-extra-tags`
+
+
+
+Generate arbitrary struct tags to fields
+
+
+
+
+
+
+`x-enum-varnames` / `x-enumNames`
+
+
+
+Override generated variable names for enum constants
+
+
+
+
+
+
+`x-deprecated-reason`
+
+
+
+Add a GoDoc deprecation warning to a type
+
+
+
+
+
+
+`x-order`
+
+
+
+Explicitly order struct fields
+
+
+
+
+
+
+`x-oapi-codegen-only-honour-go-name`
+
+
+
+Only honour the `x-go-name` when generating field names
+
+
+
+
+
+
+### `x-go-type` / `x-go-type-import` - override the generated type definition (and optionally, add an import from another package)
+
+Using the `x-go-type` (and optionally, `x-go-type-import` when you need to import another package) allows overriding the type that `oapi-codegen` determined the generated type should be.
+
+We can see this at play with the following schemas:
+
+```yaml
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ # this is a bit of a contrived example, as you could instead use
+ # `format: uuid` but it explains how you'd do this when there may be
+ # a clash, for instance if you already had a `uuid` package that was
+ # being imported, or ...
+ x-go-type: googleuuid.UUID
+ x-go-type-import:
+ path: github.com/google/uuid
+ name: googleuuid
+ id:
+ type: number
+ # ... this is also a bit of a contrived example, as you could use
+ # `type: integer` but in the case that you know better than what
+ # oapi-codegen is generating, like so:
+ x-go-type: int64
+```
+
+From here, we now get two different models:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id *int64 `json:"id,omitempty"`
+ Name googleuuid.UUID `json:"name"`
+}
+```
+
+You can see this in more detail in [the example code](examples/extensions/xgotype/).
+
+### `x-go-type-skip-optional-pointer` - do not add a pointer type for optional fields in structs
+
+
+
+> [!TIP]
+> If you prefer this behaviour, and prefer to not have to annotate your whole OpenAPI spec for this behaviour, you can use `output-options.prefer-skip-optional-pointer=true` to default this behaviour for all fields.
+>
+> It is then possible to override this on a per-type/per-field basis where necessary.
+
+By default, `oapi-codegen` will generate a pointer for optional fields.
+
+Using the `x-go-type-skip-optional-pointer` extension allows omitting that pointer.
+
+We can see this at play with the following schemas:
+
+```yaml
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ x-go-type-skip-optional-pointer: true
+```
+
+From here, we now get two different models:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+```
+
+You can see this in more detail in [the example code](examples/extensions/xgotypeskipoptionalpointer/).
+
+### `x-go-name` - override the generated name of a field or a type
+
+By default, `oapi-codegen` will attempt to generate the name of fields and types in as best a way it can.
+
+However, sometimes, the name doesn't quite fit what your codebase standards are, or the intent of the field, so you can override it with `x-go-name`.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-go-name
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ # can be used on a type
+ x-go-name: ClientRenamedByExtension
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ # or on a field
+ x-go-name: AccountIdentifier
+```
+
+From here, we now get two different models:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientRenamedByExtension defines model for ClientWithExtension.
+type ClientRenamedByExtension struct {
+ AccountIdentifier *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+```
+
+You can see this in more detail in [the example code](examples/extensions/xgoname/).
+
+### `x-go-type-name` - Override the generated name of a type
+
+> [!NOTE]
+> Notice that this is subtly different to the `x-go-name`, which also applies to _fields_ within `struct`s.
+
+By default, `oapi-codegen` will attempt to generate the name of types in as best a way it can.
+
+However, sometimes, the name doesn't quite fit what your codebase standards are, or the intent of the field, so you can override it with `x-go-name`.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-go-type-name
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ x-go-type-name: ClientRenamedByExtension
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ # NOTE attempting a `x-go-type-name` here is a no-op, as we're not producing a _type_ only a _field_
+ x-go-type-name: ThisWillNotBeUsed
+```
+
+From here, we now get two different models and a type alias:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension = ClientRenamedByExtension
+
+// ClientRenamedByExtension defines model for .
+type ClientRenamedByExtension struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+```
+
+You can see this in more detail in [the example code](examples/extensions/xgotypename/).
+
+### `x-omitempty` - force the presence of the JSON tag `omitempty` on a field
+
+In a case that you may want to add the JSON struct tag `omitempty` to types that don't have one generated by default - for instance a required field - you can use the `x-omitempty` extension.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-omitempty
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ # for some reason, you may want this behaviour, even though it's a required field
+ x-omitempty: true
+ id:
+ type: number
+```
+
+From here, we now get two different models:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name,omitempty"`
+}
+```
+
+You can see this in more detail in [the example code](examples/extensions/xomitempty/).
+
+### `x-omitzero` - force the presence of the JSON tag `omitzero` on a field
+
+> [!NOTE]
+> `omitzero` was added in Go 1.24. If you're not using Go 1.24 in your project, this won't work.
+
+In a case that you may want to add the JSON struct tag `omitzero` to types, you can use the `x-omitempty` extension.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-omitempty
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ x-omitzero: true
+```
+
+From here, we now get two different models:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id *float32 `json:"id,omitempty,omitzero"`
+ Name string `json:"name"`
+}
+```
+
+You can see this in more detail in [the example code](examples/extensions/xomitzero/).
+
+### `x-go-json-ignore` - when (un)marshaling JSON, ignore field(s)
+
+By default, `oapi-codegen` will generate `json:"..."` struct tags for all fields in a struct, so JSON (un)marshaling works.
+
+However, sometimes, you want to omit fields, which can be done with the `x-go-json-ignore` extension.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-go-json-ignore
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ complexField:
+ type: object
+ properties:
+ name:
+ type: string
+ accountName:
+ type: string
+ # ...
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ complexField:
+ type: object
+ properties:
+ name:
+ type: string
+ accountName:
+ type: string
+ # ...
+ x-go-json-ignore: true
+```
+
+From here, we now get two different models:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ ComplexField *struct {
+ AccountName *string `json:"accountName,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"complexField,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ ComplexField *struct {
+ AccountName *string `json:"accountName,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"-"`
+ Name string `json:"name"`
+}
+```
+
+Notice that the `ComplexField` is still generated in full, but the type will then be ignored with JSON marshalling.
+
+You can see this in more detail in [the example code](examples/extensions/xgojsonignore/).
+
+### `x-oapi-codegen-extra-tags` - generate arbitrary struct tags to fields
+
+If you're making use of a field's struct tags to i.e. apply validation, decide whether something should be logged, etc, you can use `x-oapi-codegen-extra-tags` to set additional tags for your generated types.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-oapi-codegen-extra-tags
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ - id
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ - id
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ x-oapi-codegen-extra-tags:
+ validate: "required,min=1,max=256"
+ safe-to-log: "true"
+ gorm: primarykey
+```
+
+From here, we now get two different models:
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id float32 `json:"id"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id float32 `gorm:"primarykey" json:"id" safe-to-log:"true" validate:"required,min=1,max=256"`
+ Name string `json:"name"`
+}
+```
+
+You can see this in more detail in [the example code](examples/extensions/xoapicodegenextratags/).
+
+### `x-enum-varnames` / `x-enumNames` - override generated variable names for enum constants
+
+When consuming an enum value from an external system, the name may not produce a nice variable name. Using the `x-enum-varnames` extension allows overriding the name of the generated variable names.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-enumNames and x-enum-varnames
+components:
+ schemas:
+ ClientType:
+ type: string
+ enum:
+ - ACT
+ - EXP
+ ClientTypeWithNamesExtension:
+ type: string
+ enum:
+ - ACT
+ - EXP
+ x-enumNames:
+ - Active
+ - Expired
+ ClientTypeWithVarNamesExtension:
+ type: string
+ enum:
+ - ACT
+ - EXP
+ x-enum-varnames:
+ - Active
+ - Expired
+```
+
+From here, we now get two different forms of the same enum definition.
+
+```go
+// Defines values for ClientType.
+const (
+ ACT ClientType = "ACT"
+ EXP ClientType = "EXP"
+)
+
+// Defines values for ClientTypeWithNamesExtension.
+const (
+ ClientTypeWithNamesExtensionActive ClientTypeWithNamesExtension = "ACT"
+ ClientTypeWithNamesExtensionExpired ClientTypeWithNamesExtension = "EXP"
+)
+
+// Defines values for ClientTypeWithVarNamesExtension.
+const (
+ ClientTypeWithVarNamesExtensionActive ClientTypeWithVarNamesExtension = "ACT"
+ ClientTypeWithVarNamesExtensionExpired ClientTypeWithVarNamesExtension = "EXP"
+)
+
+// ClientType defines model for ClientType.
+type ClientType string
+
+// ClientTypeWithNamesExtension defines model for ClientTypeWithNamesExtension.
+type ClientTypeWithNamesExtension string
+
+// ClientTypeWithVarNamesExtension defines model for ClientTypeWithVarNamesExtension.
+type ClientTypeWithVarNamesExtension string
+```
+
+You can see this in more detail in [the example code](examples/extensions/xenumnames/).
+
+### `x-deprecated-reason` - add a GoDoc deprecation warning to a type
+
+When an OpenAPI type is deprecated, a deprecation warning can be added in the GoDoc using `x-deprecated-reason`.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-deprecated-reason
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ deprecated: true
+ x-deprecated-reason: Don't use because reasons
+ id:
+ type: number
+ # NOTE that this doesn't generate, as no `deprecated: true` is set
+ x-deprecated-reason: NOTE you shouldn't see this, as you've not deprecated this field
+```
+
+From here, we now get two different forms of the same enum definition.
+
+```go
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id *float32 `json:"id,omitempty"`
+ // Deprecated: Don't use because reasons
+ Name string `json:"name"`
+}
+```
+
+Notice that because we've not set `deprecated: true` to the `name` field, it doesn't generate a deprecation warning.
+
+You can see this in more detail in [the example code](examples/extensions/xdeprecatedreason/).
+
+### `x-order` - explicitly order struct fields
+
+Whether you like certain fields being ordered before others, or you want to perform more efficient packing of your structs, the `x-order` extension is here for you.
+
+Note that `x-order` is 1-indexed - `x-order: 0` is not a valid value.
+
+We can see this at play with the following schemas:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-order
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ a_name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ a_name:
+ type: string
+ x-order: 2
+ id:
+ type: number
+ x-order: 1
+```
+
+From here, we now get two different forms of the same type definition.
+
+```go
+// Client defines model for Client.
+type Client struct {
+ AName *string `json:"a_name,omitempty"`
+ Id *float32 `json:"id,omitempty"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id *float32 `json:"id,omitempty"`
+ AName *string `json:"a_name,omitempty"`
+}
+```
+
+You can see this in more detail in [the example code](examples/extensions/xorder/).
+
+### `x-oapi-codegen-only-honour-go-name` - only honour the `x-go-name` when generating field names
+
+
+> [!WARNING]
+> Using this option may lead to cases where `oapi-codegen`'s rewriting of field names to prevent clashes with other types, or to prevent including characters that may not be valid Go field names.
+
+In some cases, you may not want use the inbuilt options for converting an OpenAPI field name to a Go field name, such as the `name-normalizer: "ToCamelCaseWithInitialisms"`, and instead trust the name that you've defined for the type better.
+
+In this case, you can use `x-oapi-codegen-only-honour-go-name` to enforce this, alongside specifying the `allow-unexported-struct-field-names` compatibility option.
+
+This allows you to take a spec such as:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-oapi-codegen-only-honour-go-name
+components:
+ schemas:
+ TypeWithUnexportedField:
+ description: A struct will be output where one of the fields is not exported
+ properties:
+ name:
+ type: string
+ id:
+ type: string
+ # NOTE that there is an explicit usage of a lowercase character
+ x-go-name: accountIdentifier
+ x-oapi-codegen-extra-tags:
+ json: "-"
+ x-oapi-codegen-only-honour-go-name: true
+```
+
+And we'll generate:
+
+```go
+// TypeWithUnexportedField A struct will be output where one of the fields is not exported
+type TypeWithUnexportedField struct {
+ accountIdentifier *string `json:"-"`
+ Name *string `json:"name,omitempty"`
+}
+```
+
+You can see this in more detail in [the example code](examples/extensions/xoapicodegenonlyhonourgoname).
+
+## Request/response validation middleware
+
+The generated code that `oapi-codegen` produces has some validation for some incoming data, such as checking for required headers, and when using the [strict server](#strict-server) you get some more validation around the correct usage of the response types.
+
+However, this leaves a lot of validation that needs to be done, which can be tedious to hand-write this logic, especially for large or complex OpenAPI specifications.
+
+To simplify this, we use a middleware, which provides the request validation. The middleware you want to use depends on the server you're using:
+
+
+
+
+
+Server
+
+
+Middleware library
+
+
+
+
+
+
+[Chi](https://github.com/go-chi/chi)
+
+
+
+
+[nethttp-middleware](https://github.com/oapi-codegen/nethttp-middleware)
+
+
+
+
+
+
+
+[Echo](https://github.com/labstack/echo)
+
+
+
+
+[echo-middleware](https://github.com/oapi-codegen/echo-middleware)
+
+
+
+
+
+
+
+[Fiber](https://github.com/gofiber/fiber)
+
+
+
+
+[fiber-middleware](https://github.com/oapi-codegen/fiber-middleware)
+
+
+
+
+
+
+
+
+
+[Gin](https://github.com/gin-gonic/gin)
+
+
+
+
+[gin-middleware](https://github.com/oapi-codegen/gin-middleware)
+
+
+
+
+
+
+
+[gorilla/mux](https://github.com/gorilla/mux)
+
+
+
+
+[nethttp-middleware](https://github.com/oapi-codegen/nethttp-middleware)
+
+
+
+
+
+
+
+
+[Iris](https://github.com/kataras/iris)
+
+
+
+
+[iris-middleware](https://github.com/oapi-codegen/iris-middleware)
+
+
+
+
+
+
+
+
+[1.22+ `net/http`](https://pkg.go.dev/net/http)
+
+
+
+
+[nethttp-middleware](https://github.com/oapi-codegen/nethttp-middleware)
+
+
+
+
+
+
+
+
+Any other server (which conforms to `net/http`)
+
+
+
+
+[nethttp-middleware](https://github.com/oapi-codegen/nethttp-middleware)
+
+
+
+
+
+
+
+> [!NOTE]
+> It is [not currently possible](https://github.com/oapi-codegen/oapi-codegen/issues/1038) to validate the HTTP response with a middleware.
+
+> [!NOTE]
+> We're also [exploring](https://github.com/oapi-codegen/exp/issues/1) the use of [libopenapi-validator](https://github.com/pb33f/libopenapi-validator/) for request/response validation middleware
+
+## Implementing security
+
+If you're using a specification with [Security Schemes](https://spec.openapis.org/oas/v3.0.3#security-scheme-object) and [Security Requirements](https://spec.openapis.org/oas/v3.0.3#security-requirement-object), you'll want to authenticate and authorize requests.
+
+### On the server
+
+> [!NOTE]
+> Out-of-the-box, the server-side code generated by `oapi-codegen` does not provide security validation.
+>
+> To perform authentication, you will need to use the [validation middleware](#requestresponse-validation-middleware).
+>
+> In the future, we plan to [implement server-side validation in the generated code](https://github.com/oapi-codegen/oapi-codegen/issues/1524)
+
+To see how this can work, check out the [authenticated API example](examples/authenticated-api/echo).
+
+### On the client
+
+With a generated client, you'll want to use the client's generated `WithRequestEditorFn` function to pass in a given request editor `RequestEditorFn`.
+
+For instance:
+
+```go
+import (
+ "context"
+ "fmt"
+ "log"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/securityprovider"
+)
+
+func main() {
+ basicAuth, err := securityprovider.NewSecurityProviderBasicAuth("my_user", "my_pass")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ client, err := NewClient("https://....", WithRequestEditorFn(basicAuth.Intercept))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ resp, err := client.GetClient(context.TODO())
+ if err != nil {
+ log.Fatal(err)
+ }
+ fmt.Printf("resp.StatusCode: %v\n", resp.StatusCode)
+}
+```
+
+Notice that we're using a pre-built provider from the [`pkg/securityprovider` package](https://pkg.go.dev/github.com/oapi-codegen/oapi-codegen/v2/pkg/securityprovider), which has some inbuilt support for other types of authentication, too.
+
+## Custom code generation
+
+It is possible to extend the inbuilt code generation from `oapi-codegen` using Go's `text/template`s.
+
+You can specify, through your configuration file, the `output-options.user-templates` setting to override the inbuilt templates and use a user-defined template.
+
+> [!NOTE]
+> Filenames given to the `user-templates` configuration must **exactly** match the filename that `oapi-codegen` is looking for
+
+### Local paths
+
+Within your configuration file, you can specify relative or absolute paths to a file to reference for the template, such as:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+# ...
+output-options:
+ user-templates:
+ client-with-responses.tmpl: ./custom-template.tmpl
+ additional-properties.tmpl: /tmp/foo.bar
+ typedef.tmpl: no-prefix.tmpl
+```
+
+> [!WARNING]
+> We do not interpolate `~` or `$HOME` (or other environment variables) in paths given
+
+### HTTPS paths
+
+It is also possible to use HTTPS URLs.
+
+> [!WARNING]
+> Although possible, this does lead to `oapi-codegen` executions not necessarily being reproducible. It's recommended to vendor (copy) the OpenAPI spec into your codebase and reference it locally
+>
+> See [this blog post](https://www.jvt.me/posts/2024/04/27/github-actions-update-file/) for an example of how to use GitHub Actions to manage the updates of files across repos
+>
+> See [this blog post](https://www.jvt.me/posts/2026/02/27/renovate-update-file) for an example of how to use Renovate to manage the updates of files across repos
+>
+> This will be disabled by default (but possible to turn back on via configuration) [in the future](https://github.com/oapi-codegen/oapi-codegen/issues/1564)
+
+To use it, you can use the following configuration:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+# ...
+output-options:
+ user-templates:
+ # The following are referencing a version of the default client-with-responses.tmpl file, but loaded in through GitHub's raw.githubusercontent.com. The general form to use raw.githubusercontent.com is as follows https://raw.githubusercontent.com////path/to/template/template.tmpl
+
+ # Alternatively using raw.githubusercontent.com with a hash
+ client-with-responses.tmpl: https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/ad5eada4f3ccc28a88477cef62ea21c17fc8aa01/pkg/codegen/templates/client-with-responses.tmpl
+ # Alternatively using raw.githubusercontent.com with a tag
+ client-with-responses.tmpl: https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/v2.1.0/pkg/codegen/templates/client-with-responses.tmpl
+ # Alternatively using raw.githubusercontent.com with a branch
+ client-with-responses.tmpl: https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/master/pkg/codegen/templates/client-with-responses.tmpl
+```
-## Overview
+> [!WARNING]
+> If using URLs that pull locations from a Git repo, such as `raw.githubusercontent.com`, it is strongly encouraged to use a tag or a raw commit hash instead of a branch like `main`. Tracking a branch can lead to unexpected API drift, and loss of the ability to reproduce a build.
-We're going to use the OpenAPI example of the
-[Expanded Petstore](https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore-expanded.yaml)
-in the descriptions below, please have a look at it.
+### Inline template
-In order to create a Go server to serve this exact schema, you would have to
-write a lot of boilerplate code to perform all the marshaling and unmarshaling
-into objects which match the OpenAPI 3.0 definition. The code generator in this
-directory does a lot of that for you. You would run it like so:
+It's also possible to set the templates inline in the configuration file:
- go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@latest
- oapi-codegen -package petstore petstore-expanded.yaml > petstore.gen.go
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+# ...
+output-options:
+ user-templates:
+ # NOTE the use of the `|` (pipe symbol) here to denote that this is a
+ # multi-line statement that should preserve newlines. More reading:
+ # https://stackoverflow.com/a/18708156/2257038 and
+ # https://stackoverflow.com/a/15365296/2257038
+ client-with-responses.tmpl: |
+ // ClientWithResponses builds on ClientInterface to offer response payloads
+ type ClientWithResponses struct {
+ ClientInterface
+ }
+ ...
+```
-Let's go through that `petstore.gen.go` file to show you everything which was
-generated.
+### Using the Go package
-## Generated Server Boilerplate
+Alternatively, you are able to use the underlying code generation as a package, which [will be documented in the future](https://github.com/oapi-codegen/oapi-codegen/issues/1487).
-The `/components/schemas` section in OpenAPI defines reusable objects, so Go
-types are generated for these. The Pet Store example defines `Error`, `Pet`,
-`Pets` and `NewPet`, so we do the same in Go:
+## Additional Properties (`additionalProperties`)
-```go
-// Error defines model for Error.
-type Error struct {
- // Error code
- Code int32 `json:"code"`
+[OpenAPI Schemas](https://spec.openapis.org/oas/v3.0.3.html#schema-object) implicitly accept `additionalProperties`, meaning that any fields provided, but not explicitly defined via properties on the schema are accepted as input, and propagated. When unspecified, OpenAPI defines that the `additionalProperties` field is assumed to be `true`.
- // Error message
- Message string `json:"message"`
-}
+For simplicity, and to remove a fair bit of duplication and boilerplate, `oapi-codegen` decides to ignore the implicit `additionalProperties: true`, and instead requires you to specify the `additionalProperties` key to generate the boilerplate.
-// NewPet defines model for NewPet.
-type NewPet struct {
- // Name of the pet
- Name string `json:"name"`
+> [!NOTE]
+> In the future [this will be possible](https://github.com/oapi-codegen/oapi-codegen/issues/1514) to disable this functionality, and honour the implicit `additionalProperties: true`
- // Type of the pet
- Tag *string `json:"tag,omitempty"`
-}
+Below you can see some examples of how `additionalProperties` affects the generated code.
-// Pet defines model for Pet.
-type Pet struct {
- // Unique id of the pet
- Id int64 `json:"id"`
+### Implicit `additionalProperties: true` / no `additionalProperties` set
- // Name of the pet
- Name string `json:"name"`
+```yaml
+components:
+ schemas:
+ Thing:
+ type: object
+ required:
+ - id
+ properties:
+ id:
+ type: integer
+ # implicit additionalProperties: true
+```
+
+Will generate:
- // Type of the pet
- Tag *string `json:"tag,omitempty"`
+```go
+// Thing defines model for Thing.
+type Thing struct {
+ Id int `json:"id"`
}
-// Type definition for component schema "Pets"
-type Pets []Pet
+// with no generated boilerplate nor the `AdditionalProperties` field
```
-It's best to define objects under `/components` field in the schema, since
-those will be turned into named Go types. If you use inline types in your
-handler definitions, we will generate inline, anonymous Go types, but those
-are more tedious to deal with since you will have to redeclare them at every
-point of use.
+### Explicit `additionalProperties: true`
+
+```yaml
+components:
+ schemas:
+ Thing:
+ type: object
+ required:
+ - id
+ properties:
+ id:
+ type: integer
+ # explicit true
+ additionalProperties: true
+```
-For each element in the `paths` map in OpenAPI, we will generate a Go handler
-function in an interface object. Here is the generated Go interface for our
-Echo server.
+Will generate:
```go
-type ServerInterface interface {
- // (GET /pets)
- FindPets(ctx echo.Context, params FindPetsParams) error
- // (POST /pets)
- AddPet(ctx echo.Context) error
- // (DELETE /pets/{id})
- DeletePet(ctx echo.Context, id int64) error
- // (GET /pets/{id})
- FindPetById(ctx echo.Context, id int64) error
+// Thing defines model for Thing.
+type Thing struct {
+ Id int `json:"id"`
+ AdditionalProperties map[string]interface{} `json:"-"`
}
-```
-These are the functions which you will implement yourself in order to create
-a server conforming to the API specification. Normally, all the arguments and
-parameters are stored on the `echo.Context` in handlers, so we do the tedious
-work of unmarshaling the JSON automatically, simply passing values into
-your handlers.
+// with generated boilerplate below
+```
-Notice that `FindPetById` takes a parameter `id int64`. All path arguments
-will be passed as arguments to your function, since they are mandatory.
+
-Remaining arguments can be passed in headers, query arguments or cookies. Those
-will be written to a `params` object. Look at the `FindPets` function above, it
-takes as input `FindPetsParams`, which is defined as follows:
+Boilerplate
```go
-// Parameters object for FindPets
-type FindPetsParams struct {
- Tags *[]string `json:"tags,omitempty"`
- Limit *int32 `json:"limit,omitempty"`
+
+// Getter for additional properties for Thing. Returns the specified
+// element and whether it was found
+func (a Thing) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
}
-```
-The HTTP query parameter `limit` turns into a Go field named `Limit`. It is
-passed by pointer, since it is an optional parameter. If the parameter is
-specified, the pointer will be non-`nil`, and you can read its value.
+// Setter for additional properties for Thing
+func (a *Thing) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
-If you changed the OpenAPI specification to make the parameter required, the
-`FindPetsParams` structure will contain the type by value:
+// Override default JSON handling for Thing to handle AdditionalProperties
+func (a *Thing) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
-```go
-type FindPetsParams struct {
- Tags *[]string `json:"tags,omitempty"`
- Limit int32 `json:"limit"`
+ if raw, found := object["id"]; found {
+ err = json.Unmarshal(raw, &a.Id)
+ if err != nil {
+ return fmt.Errorf("error reading 'id': %w", err)
+ }
+ delete(object, "id")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Thing to handle AdditionalProperties
+func (a Thing) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ object["id"], err = json.Marshal(a.Id)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'id': %w", err)
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
}
```
-### Registering handlers
+
-There are a few ways of registering your http handler based on the type of server generated i.e. `-generate server` or `-generate chi-server`
-Echo
+### `additionalProperties` as `integer`s
-Code generated using `-generate server`.
+```yaml
+components:
+ schemas:
+ Thing:
+ type: object
+ required:
+ - id
+ properties:
+ id:
+ type: integer
+ # simple type
+ additionalProperties:
+ type: integer
+```
-The usage of `Echo` is out of scope of this doc, but once you have an
-echo instance, we generate a utility function to help you associate your handlers
-with this autogenerated code. For the pet store, it looks like this:
+Will generate:
```go
-func RegisterHandlers(router codegen.EchoRouter, si ServerInterface) {
- wrapper := ServerInterfaceWrapper{
- Handler: si,
- }
- router.GET("/pets", wrapper.FindPets)
- router.POST("/pets", wrapper.AddPet)
- router.DELETE("/pets/:id", wrapper.DeletePet)
- router.GET("/pets/:id", wrapper.FindPetById)
+// Thing defines model for Thing.
+type Thing struct {
+ Id int `json:"id"`
+ AdditionalProperties map[string]int `json:"-"`
}
+
+// with generated boilerplate below
```
-The wrapper functions referenced above contain generated code which pulls
-parameters off the `Echo` request context, and unmarshals them into Go objects.
+
-You would register the generated handlers as follows:
+Boilerplate
```go
-func SetupHandler() {
- var myApi PetStoreImpl // This implements the pet store interface
- e := echo.New()
- petstore.RegisterHandlers(e, &myApi)
- ...
+// Getter for additional properties for Thing. Returns the specified
+// element and whether it was found
+func (a Thing) Get(fieldName string) (value int, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
}
-```
-
+// Setter for additional properties for Thing
+func (a *Thing) Set(fieldName string, value int) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]int)
+ }
+ a.AdditionalProperties[fieldName] = value
+}
-Chi
+// Override default JSON handling for Thing to handle AdditionalProperties
+func (a *Thing) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
-Code generated using `-generate chi-server`.
+ if raw, found := object["id"]; found {
+ err = json.Unmarshal(raw, &a.Id)
+ if err != nil {
+ return fmt.Errorf("error reading 'id': %w", err)
+ }
+ delete(object, "id")
+ }
-```go
-type PetStoreImpl struct {}
-func (*PetStoreImpl) GetPets(w http.ResponseWriter, r *http.Request) {
- // Implement me
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]int)
+ for fieldName, fieldBuf := range object {
+ var fieldVal int
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
}
-func SetupHandler() {
- var myApi PetStoreImpl
+// Override default JSON handling for Thing to handle AdditionalProperties
+func (a Thing) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
- r := chi.NewRouter()
- r.Mount("/", Handler(&myApi))
+ object["id"], err = json.Marshal(a.Id)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'id': %w", err)
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
}
```
-
+
-Gin
+### `additionalProperties` with an object
-Code generated using `-generate gin`.
+```yaml
+components:
+ schemas:
+ Thing:
+ type: object
+ required:
+ - id
+ properties:
+ id:
+ type: integer
+ # object
+ additionalProperties:
+ type: object
+ properties:
+ foo:
+ type: string
+```
-The usage of `gin` is out of scope of this doc, but once you have an
-gin instance, we generate a utility function to help you associate your handlers
-with this autogenerated code. For the pet store, it looks like this:
+Will generate:
```go
-// RegisterHandlersWithOptions creates http.Handler with additional options
-func RegisterHandlersWithOptions(router *gin.Engine, si ServerInterface, options GinServerOptions) *gin.Engine {
- wrapper := ServerInterfaceWrapper{
- Handler: si,
- HandlerMiddlewares: options.Middlewares,
- }
-
- router.GET(options.BaseURL+"/pets", wrapper.FindPets)
- router.POST(options.BaseURL+"/pets", wrapper.AddPet)
- router.DELETE(options.BaseURL+"/pets/:id", wrapper.DeletePet)
- router.GET(options.BaseURL+"/pets/:id", wrapper.FindPetByID)
- return router
+// Thing defines model for Thing.
+type Thing struct {
+ Id int `json:"id"`
+ AdditionalProperties map[string]struct {
+ Foo *string `json:"foo,omitempty"`
+ } `json:"-"`
}
-```
-```go
-import (
- "github.com/gin-gonic/gin"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/gin/api"
- middleware "github.com/oapi-codegen/gin-middleware"
-)
+// with generated boilerplate below
+```
-type PetStoreImpl struct {}
-func (*PetStoreImpl) GetPets(w http.ResponseWriter, r *http.Request) {
- // Implement me
-}
+
-func SetupHandler() {
- var myApi PetStoreImpl
+Boilerplate
- r := gin.Default()
- r.Use(middleware.OapiRequestValidator(swagger))
- r = api.RegisterHandlers(r, petStore)
+```go
+// Getter for additional properties for Thing. Returns the specified
+// element and whether it was found
+func (a Thing) Get(fieldName string) (value struct {
+ Foo *string `json:"foo,omitempty"`
+}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
}
-```
-
+// Setter for additional properties for Thing
+func (a *Thing) Set(fieldName string, value struct {
+ Foo *string `json:"foo,omitempty"`
+}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]struct {
+ Foo *string `json:"foo,omitempty"`
+ })
+ }
+ a.AdditionalProperties[fieldName] = value
+}
-net/http
+// Override default JSON handling for Thing to handle AdditionalProperties
+func (a *Thing) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
-[Chi](https://github.com/go-chi/chi) is 100% compatible with `net/http` allowing the following with code generated using `-generate chi-server`.
+ if raw, found := object["id"]; found {
+ err = json.Unmarshal(raw, &a.Id)
+ if err != nil {
+ return fmt.Errorf("error reading 'id': %w", err)
+ }
+ delete(object, "id")
+ }
-```go
-type PetStoreImpl struct {}
-func (*PetStoreImpl) GetPets(w http.ResponseWriter, r *http.Request) {
- // Implement me
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]struct {
+ Foo *string `json:"foo,omitempty"`
+ })
+ for fieldName, fieldBuf := range object {
+ var fieldVal struct {
+ Foo *string `json:"foo,omitempty"`
+ }
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
}
-func SetupHandler() {
- var myApi PetStoreImpl
+// Override default JSON handling for Thing to handle AdditionalProperties
+func (a Thing) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ object["id"], err = json.Marshal(a.Id)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'id': %w", err)
+ }
- http.Handle("/", Handler(&myApi))
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
}
```
-Alternatively, [Gorilla](https://github.com/gorilla/mux) is also 100% compatible with `net/http` and can be generated with `-generate gorilla`.
+
-
+## Globally skipping the "optional pointer"
-Iris
+One of the key things `oapi-codegen` does is to use an "optional pointer", following idiomatic Go practices, to indicate that a field/type is optional.
-Code generated using `-generate iris`.
+This can be tuned on a per-field basis, using the [`x-go-type-skip-optional-pointer` extension](#ext-x-go-type-skip-optional-pointer), but it can be a bit repetitive, or can be more complex when using an OpenAPI Overlay.
-The usage of `iris` is out of scope of this doc, but once you have an
-gin instance, we generate a utility function to help you associate your handlers
-with this autogenerated code. For the pet store, it looks like this:
+As of `oapi-codegen` v2.5.0, this can be tuned in two specific ways, via the following `output-options:`:
-```go
-// RegisterHandlersWithOptions creates http.Handler with additional options
-func RegisterHandlersWithOptions(router *iris.Application, si ServerInterface, options IrisServerOptions) {
+- `prefer-skip-optional-pointer`: a global default that you do _not_ want the "optional pointer" generated. Optional fields will not have an "optional pointer", and will have an `omitempty` JSON tag
+- `prefer-skip-optional-pointer-with-omitzero`: when used in conjunction with `prefer-skip-optional-pointer`, any optional fields are generated with an `omitzero` JSON tag. **Requires Go 1.24+**
- wrapper := ServerInterfaceWrapper{
- Handler: si,
- }
+In both cases, there is control on a per-field level to set `x-go-type-skip-optional-pointer: false` or `x-omitzero: false` to undo these to field(s).
- router.Get(options.BaseURL+"/pets", wrapper.FindPets)
- router.Post(options.BaseURL+"/pets", wrapper.AddPet)
- router.Delete(options.BaseURL+"/pets/:id", wrapper.DeletePet)
- router.Get(options.BaseURL+"/pets/:id", wrapper.FindPetByID)
+For example, when combining both options:
- router.Build()
-}
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
+package: preferskipoptionalpointerwithomitzero
+output: gen.go
+generate:
+ # ...
+output-options:
+ # ...
+ prefer-skip-optional-pointer: true
+ prefer-skip-optional-pointer-with-omitzero: true
```
-```go
-import (
- "github.com/kataras/iris/v12"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/iris/api"
- middleware "github.com/oapi-codegen/iris-middleware"
-)
-```
+When we have the following spec:
-The wrapper functions referenced above contain generated code which pulls
-parameters off the `Iris` request context, and unmarshals them into Go objects.
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: prefer-skip-optional-pointer-with-omitzero
+components:
+ schemas:
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ description: This field is required, so will never have an optional pointer, nor `omitzero`.
+ type: string
+ id:
+ description: This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer. However, it will receive `omitzero`.
+ type: number
+ pointer_id:
+ type: number
+ description: This field should have an optional pointer, as the field-level definition of `x-go-type-skip-optional-pointer` overrides the `prefer-skip-optional-pointer` Output Option. This will also not receive an `omitzero`.
+ # NOTE that this overrides the global preference
+ x-go-type-skip-optional-pointer: false
+ no_omit:
+ type: number
+ description: This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer. This will not receive `omitzero`, as the field-level definition of `x-omitzero` overrides the `prefer-skip-optional-pointer-with-omitzero` Output Option.
+ # NOTE that this overrides the global preference
+ x-omitzero: false
+```
-You would register the generated handlers as follows:
+We then generate the following Go code:
```go
-func SetupHandler() {
- var myApi PetStoreImpl
+// ...
- i := iris.Default()
- i.Use(middleware.OapiRequestValidator(swagger))
- api.RegisterHandlers(r, &myApi)
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ // Id This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer. However, it will receive `omitzero`.
+ Id float32 `json:"id,omitempty,omitzero"`
+
+ // Name This field is required, so will never have an optional pointer, nor `omitzero`.
+ Name string `json:"name"`
+
+ // NoOmit This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer. This will not receive `omitzero`, as the field-level definition of `x-omitzero` overrides the `prefer-skip-optional-pointer-with-omitzero` Output Option.
+ NoOmit float32 `json:"no_omit,omitempty"`
+
+ // PointerId This field should have an optional pointer, as the field-level definition of `x-go-type-skip-optional-pointer` overrides the `prefer-skip-optional-pointer` Output Option. This will also not receive an `omitzero`.
+ PointerId *float32 `json:"pointer_id,omitempty"`
}
```
-
+You can see this in more detail in [the example code for `prefer-skip-optional-pointer`](examples/output-options/preferskipoptionalpointer/) and [example code for `prefer-skip-optional-pointer-with-omitzero`](examples/output-options/preferskipoptionalpointerwithomitzero/)
+
+## Changing the names of generated types
-#### Strict server generation
+As of `oapi-codegen` v2.2.0, it is now possible to use the `output-options` configuration's `name-normalizer` to define the logic for how to convert an OpenAPI name (i.e. an Operation ID or a Schema name) and construct a Go type name.
-oapi-codegen also supports generating RPC inspired strict server, that will parse request bodies and encode responses.
-The main points of this code is to automate some parsing, abstract user code from server specific code,
-and also to force user code to comply with the schema.
-It supports binding of `application/json` and `application/x-www-form-urlencoded` to a struct, for `multipart` requests
-it generates a `multipart.Reader`, which can be used to either manually iterating over parts or using `runtime.BindMultipart`
-function to bind the form to a struct. All other content types are represented by a `io.Reader` interface.
+
-To form a response simply return one of the generated structs with corresponding status code and content type. For example,
-to return a status code 200 JSON response for a AddPet use the `AddPet200JSONResponse` struct which will set the correct
-Content-Type header, status code and will marshal the response data. You can also return an error, that will
-cause an `Internal Server Error` response.
+Example, using default configuration
+
+By default, `oapi-codegen` will perform camel-case conversion, so for a spec such as:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Example code for the `name-normalizer` output option
+paths:
+ /api/pets/{petId}:
+ get:
+ summary: Get pet given identifier.
+ operationId: getHttpPet
+ parameters:
+ - name: petId
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: valid pet
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+components:
+ schemas:
+ Pet:
+ type: object
+ required:
+ - uuid
+ - name
+ properties:
+ uuid:
+ type: string
+ description: The pet uuid.
+ name:
+ type: string
+ description: The name of the pet.
+ Error:
+ required:
+ - code
+ - message
+ properties:
+ code:
+ type: integer
+ format: int32
+ description: Error code
+ message:
+ type: string
+ description: Error message
+ OneOf2things:
+ description: "Notice that the `things` is not capitalised"
+ oneOf:
+ - type: object
+ required:
+ - id
+ properties:
+ id:
+ type: integer
+ - type: object
+ required:
+ - id
+ properties:
+ id:
+ type: string
+ format: uuid
+```
-Short example:
+This will produce:
```go
-type PetStoreImpl struct {}
-func (*PetStoreImpl) GetPets(ctx context.Context, request GetPetsRequestObject) (GetPetsResponseObject, error) {
- var result []Pet
- // Implement me
- return GetPets200JSONResponse(result), nil
+// OneOf2things Notice that the `things` is not capitalised
+type OneOf2things struct {
+ union json.RawMessage
}
-```
-For a complete example see [`examples/petstore-expanded/strict`](https://github.com/deepmap/oapi-codegen/tree/master/examples/petstore-expanded/strict).
+// Pet defines model for Pet.
+type Pet struct {
+ // Name The name of the pet.
+ Name string `json:"name"`
-Code is generated with a configuration flag `generate: strict-server: true` along with any other server (echo, chi, gin and gorilla are supported).
-The generated strict wrapper can then be used as an implementation for `ServerInterface`. Setup example:
+ // Uuid The pet uuid.
+ Uuid string `json:"uuid"`
+}
-```go
-func SetupHandler() {
- var myApi PetStoreImpl
- myStrictApiHandler := api.NewStrictHandler(myApi, nil)
- e := echo.New()
- petstore.RegisterHandlers(e, &myStrictApiHandler)
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetHttpPet request
+ GetHttpPet(ctx context.Context, petId string, reqEditors ...RequestEditorFn) (*http.Response, error)
}
```
-Strict server also has its own middlewares. It can access to both request and response structs,
-as well as raw request\response data. It can be used for logging the parsed request\response objects, transforming go errors into response structs,
-authorization, etc. Note that middlewares are server-specific.
-
-#### Additional Properties in type definitions
+
-[OpenAPI Schemas](https://swagger.io/specification/#schemaObject) implicitly
-accept `additionalProperties`, meaning that any fields provided, but not explicitly
-defined via properties on the schema are accepted as input, and propagated. When
-unspecified, the `additionalProperties` field is assumed to be `true`.
+
-Additional properties are tricky to support in Go with typing, and require
-lots of boilerplate code, so in this library, we assume that `additionalProperties`
-defaults to `false` and we don't generate this boilerplate. If you would like
-an object to accept `additionalProperties`, specify a schema for `additionalProperties`.
+Example, using ToCamelCaseWithInitialisms
-Say we declared `NewPet` above like so:
+By default, `oapi-codegen` will perform camel-case conversion, so for a spec such as:
```yaml
-NewPet:
- required:
- - name
- properties:
- name:
- type: string
- tag:
- type: string
- additionalProperties:
- type: string
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Example code for the `name-normalizer` output option
+paths:
+ /api/pets/{petId}:
+ get:
+ summary: Get pet given identifier.
+ operationId: getHttpPet
+ parameters:
+ - name: petId
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: valid pet
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+components:
+ schemas:
+ Pet:
+ type: object
+ required:
+ - uuid
+ - name
+ properties:
+ uuid:
+ type: string
+ description: The pet uuid.
+ name:
+ type: string
+ description: The name of the pet.
+ Error:
+ required:
+ - code
+ - message
+ properties:
+ code:
+ type: integer
+ format: int32
+ description: Error code
+ message:
+ type: string
+ description: Error message
+ OneOf2things:
+ description: "Notice that the `things` is not capitalised"
+ oneOf:
+ - type: object
+ required:
+ - id
+ properties:
+ id:
+ type: integer
+ - type: object
+ required:
+ - id
+ properties:
+ id:
+ type: string
+ format: uuid
```
-The Go code for `NewPet` would now look like this:
+This will produce:
```go
-// NewPet defines model for NewPet.
-type NewPet struct {
- Name string `json:"name"`
- Tag *string `json:"tag,omitempty"`
- AdditionalProperties map[string]string `json:"-"`
+// OneOf2things Notice that the `things` is not capitalised
+type OneOf2things struct {
+ union json.RawMessage
+}
+
+// Pet defines model for Pet.
+type Pet struct {
+ // Name The name of the pet.
+ Name string `json:"name"`
+
+ // UUID The pet uuid.
+ UUID string `json:"uuid"`
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetHTTPPet request
+ GetHTTPPet(ctx context.Context, petID string, reqEditors ...RequestEditorFn) (*http.Response, error)
}
```
-The additionalProperties, of type `string` become `map[string]string`, which maps
-field names to instances of the `additionalProperties` schema.
+
-```go
-// Getter for additional properties for NewPet. Returns the specified
-// element and whether it was found
-func (a NewPet) Get(fieldName string) (value string, found bool) {...}
-// Setter for additional properties for NewPet
-func (a *NewPet) Set(fieldName string, value string) {...}
+For more details of what the resulting code looks like, check out [the test cases](internal/test/outputoptions/name-normalizer/).
-// Override default JSON handling for NewPet to handle additionalProperties
-func (a *NewPet) UnmarshalJSON(b []byte) error {...}
+## Examples
-// Override default JSON handling for NewPet to handle additionalProperties
-func (a NewPet) MarshalJSON() ([]byte, error) {...}w
-```
+The [examples directory](examples) contains some additional cases which are useful examples for how to use `oapi-codegen`, including how you'd take the Petstore API and implement it with `oapi-codegen`.
-There are many special cases for `additionalProperties`, such as having to
-define types for inner fields which themselves support additionalProperties, and
-all of them are tested via the [`internal/test/components`](https://github.com/deepmap/oapi-codegen/tree/master/internal/test/components) schemas and tests. Please
-look through those tests for more usage examples.
+You could also find some cases of how the project can be used by checking out our [internal test cases](internal/test) which are real-world usages that make up our regression tests.
-#### oneOf/anyOf/allOf support
+### Blog posts
-- `oneOf` and `anyOf` are implemented using delayed parsing with the help of `json.RawMessage`.
- The following schema will result in a type that has methods such as `AsCat`, `AsDog`, `FromCat`, `FromDog`, `MergeCat`, `MergeDog`. If the schema also includes a discriminator the generated code will also have methods such as `Discriminator`, `ValueByDiscriminator` and will force discriminator value in `From` methods.
+We love reading posts by the community about how to use the project.
-```yaml
-schema:
- oneOf:
- - $ref: '#/components/schemas/Cat'
- - $ref: '#/components/schemas/Dog'
-```
+Here are a few we've found around the Web:
-- `allOf` is supported, by taking the union of all the fields in all the
- component schemas. This is the most useful of these operations, and is
- commonly used to merge objects with an identifier, as in the
- `petstore-expanded` example.
+- [Building a Go RESTful API with design-first OpenAPI contracts](https://www.jvt.me/posts/2022/07/12/go-openapi-server/)
+- [A Practical Guide to Using oapi-codegen in Golang API Development with the Fiber Framework](https://medium.com/@fikihalan/a-practical-guide-to-using-oapi-codegen-in-golang-api-development-with-the-fiber-framework-bce2a59380ae)
+- [Generating Go server code from OpenAPI 3 definitions](https://ldej.nl/post/generating-go-from-openapi-3/)
+- [Go Client Code Generation from Swagger and OpenAPI](https://medium.com/@kyodo-tech/go-client-code-generation-from-swagger-and-openapi-a0576831836c)
+- [Go oapi-codegen + request validation](https://blog.commitsmart.com/go-oapi-codegen-request-validation-285398b37dc8)
+- [Streamlining Go + Chi Development: Generating Code from an OpenAPI Spec](https://i4o.dev/blog/oapi-codegen-with-chi-router)
-## Generated Client Boilerplate
+Got one to add? Please raise a PR!
-Once your server is up and running, you probably want to make requests to it. If
-you're going to do those requests from your Go code, we also generate a client
-which is conformant with your schema to help in marshaling objects to JSON. It
-uses the same types and similar function signatures to your request handlers.
+## Frequently Asked Questions (FAQs)
-The interface for the pet store looks like this:
+### Does `oapi-codegen` support OpenAPI 3.1?
-```go
-// The interface specification for the client above.
-type ClientInterface interface {
+No, we don't currently.
- // FindPets request
- FindPets(ctx context.Context, params *FindPetsParams, reqEditors ...RequestEditorFn) (*http.Response, error)
+OpenAPI 3.1 support is [awaiting upstream support](https://github.com/oapi-codegen/oapi-codegen/issues/373).
- // AddPet request with JSON body
- AddPet(ctx context.Context, body NewPet, reqEditors ...RequestEditorFn) (*http.Response, error)
+In the meantime, you could follow [steps from this blog post](https://www.jvt.me/posts/2025/05/04/oapi-codegen-trick-openapi-3-1/) to [use OpenAPI Overlay](#modifying-the-input-openapi-specification-with-openapi-overlay) to "downgrade" the OpenAPI 3.1 spec to OpenAPI 3.0.
- // DeletePet request
- DeletePet(ctx context.Context, id int64, reqEditors ...RequestEditorFn) (*http.Response, error)
+### How does `oapi-codegen` handle `anyOf`, `allOf` and `oneOf`?
- // FindPetById request
- FindPetById(ctx context.Context, id int64, reqEditors ...RequestEditorFn) (*http.Response, error)
-}
+`oapi-codegen` supports `anyOf`, `allOf` and `oneOf` for generated code.
+
+For instance, through the following OpenAPI spec:
+
+```yaml
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Using complex schemas
+ description: An example of `anyOf`, `allOf` and `oneOf`
+components:
+ schemas:
+ # base types
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ Identity:
+ type: object
+ required:
+ - issuer
+ properties:
+ issuer:
+ type: string
+
+ # allOf performs a union of all types defined
+ ClientWithId:
+ allOf:
+ - $ref: '#/components/schemas/Client'
+ - properties:
+ id:
+ type: integer
+ required:
+ - id
+
+ # allOf performs a union of all types defined, but if there's a duplicate field defined, it'll be overwritten by the last schema
+ # https://github.com/oapi-codegen/oapi-codegen/issues/1569
+ IdentityWithDuplicateField:
+ allOf:
+ # `issuer` will be ignored
+ - $ref: '#/components/schemas/Identity'
+ # `issuer` will be ignored
+ - properties:
+ issuer:
+ type: integer
+ # `issuer` will take precedence
+ - properties:
+ issuer:
+ type: object
+ properties:
+ name:
+ type: string
+ required:
+ - name
+
+ # anyOf results in a type that has an `AsClient`/`MergeClient`/`FromClient` and an `AsIdentity`/`MergeIdentity`/`FromIdentity` method so you can choose which of them you want to retrieve
+ ClientAndMaybeIdentity:
+ anyOf:
+ - $ref: '#/components/schemas/Client'
+ - $ref: '#/components/schemas/Identity'
+
+ # oneOf results in a type that has an `AsClient`/`MergeClient`/`FromClient` and an `AsIdentity`/`MergeIdentity`/`FromIdentity` method so you can choose which of them you want to retrieve
+ ClientOrIdentity:
+ oneOf:
+ - $ref: '#/components/schemas/Client'
+ - $ref: '#/components/schemas/Identity'
```
-A Client object which implements the above interface is also generated:
+This results in the following types:
+
+
+
+Base types
```go
-// Client which conforms to the OpenAPI3 specification for this service.
+// Client defines model for Client.
type Client struct {
- // The endpoint of the server conforming to this interface, with scheme,
- // https://api.deepmap.com for example.
- Server string
-
- // HTTP client with any customized settings, such as certificate chains.
- Client http.Client
+ Name string `json:"name"`
+}
- // A callback for modifying requests which are generated before sending over
- // the network.
- RequestEditors []func(ctx context.Context, req *http.Request) error
+// Identity defines model for Identity.
+type Identity struct {
+ Issuer string `json:"issuer"`
}
```
-Each operation in your OpenAPI spec will result in a client function which
-takes the same arguments. It's difficult to handle any arbitrary body that
-Swagger supports, so we've done some special casing for bodies, and you may get
-more than one function for an operation with a request body.
+
-1. If you have more than one request body type, meaning more than one media
- type, you will have a generic handler of this form:
+
- AddPet(ctx context.Context, contentType string, body io.Reader)
+allOf
-2. If you have only a JSON request body, you will get:
+```go
+// ClientWithId defines model for ClientWithId.
+type ClientWithId struct {
+ Id int `json:"id"`
+ Name string `json:"name"`
+}
- AddPet(ctx context.Context, body NewPet)
+// IdentityWithDuplicateField defines model for IdentityWithDuplicateField.
+type IdentityWithDuplicateField struct {
+ Issuer struct {
+ Name string `json:"name"`
+ } `json:"issuer"`
+}
+```
-3. If you have multiple request body types, which include a JSON type you will
- get two functions. We've chosen to give the JSON version a shorter name, as
- we work with JSON and don't want to wear out our keyboards.
+
- AddPet(ctx context.Context, body NewPet)
- AddPetWithBody(ctx context.Context, contentType string, body io.Reader)
+
-The Client object above is fairly flexible, since you can pass in your own
-`http.Client` and a request editing callback. You can use that callback to add
-headers. In our middleware stack, we annotate the context with additional
-information such as the request ID and function tracing information, and we
-use the callback to propagate that information into the request headers. Still, we
-can't foresee all possible usages, so those functions call through to helper
-functions which create requests. In the case of the pet store, we have:
+anyOf
```go
-// Request generator for FindPets
-func NewFindPetsRequest(server string, params *FindPetsParams) (*http.Request, error) {...}
-
-// Request generator for AddPet with JSON body
-func NewAddPetRequest(server string, body NewPet) (*http.Request, error) {...}
-
-// Request generator for AddPet with non-JSON body
-func NewAddPetRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {...}
-
-// Request generator for DeletePet
-func NewDeletePetRequest(server string, id int64) (*http.Request, error) {...}
+import (
+ "encoding/json"
-// Request generator for FindPetById
-func NewFindPetByIdRequest(server string, id int64) (*http.Request, error) {...}
-```
+ "github.com/oapi-codegen/runtime"
+)
-You can call these functions to build an `http.Request` from Go objects, which
-will correspond to your request schema. They map one-to-one to the functions on
-the client, except that we always generate the generic non-JSON body handler.
+// ClientAndMaybeIdentity defines model for ClientAndMaybeIdentity.
+type ClientAndMaybeIdentity struct {
+ union json.RawMessage
+}
-There are some caveats to using this code.
+// AsClient returns the union data inside the ClientAndMaybeIdentity as a Client
+func (t ClientAndMaybeIdentity) AsClient() (Client, error) {
+ var body Client
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
-- exploded, form style query arguments, which are the default argument format
- in OpenAPI 3.0 are undecidable. Say that I have two objects, one composed of
- the fields `(name=bob, id=5)` and another which has `(name=shoe, color=brown)`.
- The first parameter is named `person` and the second is named `item`. The
- default marshaling style for query args would result in
- `/path/?name=bob,id=5&name=shoe,color=brown`. In order to tell what belongs
- to which object, we'd have to look at all the parameters and try to deduce it,
- but we're lazy, so we didn't. Don't use exploded form style arguments if
- you're passing around objects which have similar field names. If you
- used unexploded form parameters, you'd have
- `/path/?person=name,bob,id,5&item=name,shoe,color,brown`, which an be
- parsed unambiguously.
+// FromClient overwrites any union data inside the ClientAndMaybeIdentity as the provided Client
+func (t *ClientAndMaybeIdentity) FromClient(v Client) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
-- Parameters can be defined via `schema` or via `content`. Use the `content` form
- for anything other than trivial objects, they can marshal to arbitrary JSON
- structures. When you send them as cookie (`in: cookie`) arguments, we will
- URL encode them, since JSON delimiters aren't allowed in cookies.
+// MergeClient performs a merge with any union data inside the ClientAndMaybeIdentity, using the provided Client
+func (t *ClientAndMaybeIdentity) MergeClient(v Client) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
-## Using SecurityProviders
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
-If you generate client-code, you can use some default-provided security providers
-which help you to use the various OpenAPI 3 Authentication mechanism.
+// AsIdentity returns the union data inside the ClientAndMaybeIdentity as a Identity
+func (t ClientAndMaybeIdentity) AsIdentity() (Identity, error) {
+ var body Identity
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
-```go
- import (
- "github.com/deepmap/oapi-codegen/pkg/securityprovider"
- )
+// FromIdentity overwrites any union data inside the ClientAndMaybeIdentity as the provided Identity
+func (t *ClientAndMaybeIdentity) FromIdentity(v Identity) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
- func CreateSampleProviders() error {
- // Example BasicAuth
- // See: https://swagger.io/docs/specification/authentication/basic-authentication/
- basicAuthProvider, basicAuthProviderErr := securityprovider.NewSecurityProviderBasicAuth("MY_USER", "MY_PASS")
- if basicAuthProviderErr != nil {
- panic(basicAuthProviderErr)
- }
+// MergeIdentity performs a merge with any union data inside the ClientAndMaybeIdentity, using the provided Identity
+func (t *ClientAndMaybeIdentity) MergeIdentity(v Identity) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
- // Example BearerToken
- // See: https://swagger.io/docs/specification/authentication/bearer-authentication/
- bearerTokenProvider, bearerTokenProviderErr := securityprovider.NewSecurityProviderBearerToken("MY_TOKEN")
- if bearerTokenProviderErr != nil {
- panic(bearerTokenProviderErr)
- }
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
- // Example ApiKey provider
- // See: https://swagger.io/docs/specification/authentication/api-keys/
- apiKeyProvider, apiKeyProviderErr := securityprovider.NewSecurityProviderApiKey("query", "myApiKeyParam", "MY_API_KEY")
- if apiKeyProviderErr != nil {
- panic(apiKeyProviderErr)
- }
+func (t ClientAndMaybeIdentity) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
- // Example providing your own provider using an anonymous function wrapping in the
- // InterceptoFn adapter. The behaviour between the InterceptorFn and the Interceptor interface
- // are the same as http.HandlerFunc and http.Handler.
- customProvider := func(req *http.Request, ctx context.Context) error {
- // Just log the request header, nothing else.
- log.Println(req.Header)
- return nil
- }
+func (t *ClientAndMaybeIdentity) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
- // Exhaustive list of some defaults you can use to initialize a Client.
- // If you need to override the underlying httpClient, you can use the option
- //
- // WithHTTPClient(httpClient *http.Client)
- //
- client, clientErr := NewClient("https://api.deepmap.com", WithRequestEditorFn(apiKeyProvider.Intercept))
- return nil
- }
```
-## Extensions
+
-`oapi-codegen` supports the following extended properties:
+
-- `x-go-type`: specifies Go type name. It allows you to specify the type name for a schema, and
- will override any default value. This extended property isn't supported in all parts of
- OpenAPI, so please refer to the spec as to where it's allowed. Swagger validation tools will
- flag incorrect usage of this property.
-- `x-go-type-skip-optional-pointer`: specifies if the Go type should or should not be a pointer
- when the property is optional. If set to true, the type will not be a pointer if the field is
- optional or nullable. If set to false, the type will be a pointer.
-
- ```yaml
- properties:
- field:
- type: string
- x-go-type-skip-optional-pointer: true
- ```
-
- In the example above, the `field` field will be of type `string` instead of `*string`. This is
- useful when you want to handle the case of an empty string differently than a null value.
-
-- `x-go-name`: specifies Go field name. It allows you to specify the field name for a schema, and
- will override any default value. This extended property isn't supported in all parts of
- OpenAPI, so please refer to the spec as to where it's allowed. Swagger validation tools will
- flag incorrect usage of this property.
-- `x-go-type-name`: This property allows for assigning a Go type name to some part of a schema,
- such as generating a type name for an anonymous object inside another object, or renaming
- an enum. It differs from `x-go-type`, in that it doesn't completely replace some type reference,
- but simply names it.
-- `x-go-json-ignore`: sets tag to `-` to ignore the field in json completely.
-- `x-oapi-codegen-extra-tags`: adds extra Go field tags to the generated struct field. This is
- useful for interfacing with tag based ORM or validation libraries. The extra tags that
- are added are in addition to the regular json tags that are generated. If you specify your
- own `json` tag, you will override the default one.
-
- ```yaml
- components:
- schemas:
- Object:
- properties:
- name:
- type: string
- x-oapi-codegen-extra-tags:
- tag1: value1
- tag2: value2
- ```
+oneOf
- In the example above, field `name` will be declared as:
+```go
+// AsClient returns the union data inside the ClientOrIdentity as a Client
+func (t ClientOrIdentity) AsClient() (Client, error) {
+ var body Client
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
- ```
- Name string `json:"name" tag1:"value1" tag2:"value2"`
- ```
+// FromClient overwrites any union data inside the ClientOrIdentity as the provided Client
+func (t *ClientOrIdentity) FromClient(v Client) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
-- `x-go-type-import`: adds extra Go imports to your generated code. It can help you, when you want to
- choose your own import package for `x-go-type`.
+// MergeClient performs a merge with any union data inside the ClientOrIdentity, using the provided Client
+func (t *ClientOrIdentity) MergeClient(v Client) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
- ```yaml
- schemas:
- Pet:
- properties:
- age:
- x-go-type: myuuid.UUID
- x-go-type-import:
- name: myuuid
- path: github.com/google/uuid
- ```
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
- After code generation you will get this:
+// AsIdentity returns the union data inside the ClientOrIdentity as a Identity
+func (t ClientOrIdentity) AsIdentity() (Identity, error) {
+ var body Identity
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
- ```go
- import (
- ...
- myuuid "github.com/google/uuid"
- )
+// FromIdentity overwrites any union data inside the ClientOrIdentity as the provided Identity
+func (t *ClientOrIdentity) FromIdentity(v Identity) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
- //Pet defines model for Pet.
- type Pet struct {
- Age *myuuid.UUID `json:"age,omitempty"`
- }
+// MergeIdentity performs a merge with any union data inside the ClientOrIdentity, using the provided Identity
+func (t *ClientOrIdentity) MergeIdentity(v Identity) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
- ```
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
- `name` is an optional parameter. Example:
+func (t ClientOrIdentity) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
- ```yaml
- components:
- schemas:
- Pet:
- properties:
- age:
- x-go-type: uuid.UUID
- x-go-type-import:
- path: github.com/google/uuid
- required:
- - age
- ```
+func (t *ClientOrIdentity) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+```
- After code generation you will get this result:
+
- ```go
- import (
- "github.com/google/uuid"
- )
+For more info, check out [the example code](examples/anyof-allof-oneof/).
- // Pet defines model for Pet.
- type Pet struct {
- Age uuid.UUID `json:"age"`
- }
- ```
+### How can I ignore parts of the spec I don't care about?
-- `x-enum-varnames`: supplies other enum names for the corresponding values. (alias: `x-enumNames`)
+By default, `oapi-codegen` will generate everything from the specification.
- ```yaml
- components:
- schemas:
- Object:
- properties:
- category:
- type: integer
- enum: [0, 1, 2]
- x-enum-varnames:
- - notice
- - warning
- - urgent
- ```
-
- After code generation you will get this result:
-
- ```go
- // Defines values for ObjectCategory.
- const (
- Notice ObjectCategory = 0
- Urgent ObjectCategory = 2
- Warning ObjectCategory = 1
- )
-
- // ObjectCategory defines model for Object.Category.
- type ObjectCategory int
- ```
-
-## Using `oapi-codegen`
-
-The default options for `oapi-codegen` will generate everything; client, server,
-type definitions and embedded swagger spec, but you can generate subsets of
-those via the `-generate` flag. It defaults to `types,client,server,spec`, but
-you can specify any combination of those.
-
-- `types`: generate all type definitions for all types in the OpenAPI spec. This
- will be everything under `#components`, as well as request parameter, request
- body, and response type objects.
-- `server`: generate the Echo server boilerplate. `server` requires the types in the
- same package to compile.
-- `chi-server`: generate the Chi server boilerplate. This code is dependent on
- that produced by the `types` target.
-- `fiber`: generate the Fiber server boilerplate. This code is dependent
- on that produced by the `types` target.
-- `iris`: generate the Iris server boilerplate. This code is dependent
- on that produced by the `types` target.
-- `client`: generate the client boilerplate. It, too, requires the types to be
- present in its package.
-- `spec`: embed the OpenAPI spec into the generated code as a gzipped blob.
- This is then usable with the `OapiRequestValidator`, or to be used by other
- methods that need access to the parsed OpenAPI specification
-- `skip-fmt`: skip running `goimports` on the generated code. This is useful for debugging
- the generated file in case the spec contains weird strings.
-- `skip-prune`: skip pruning unused components from the spec prior to generating
- the code.
-- `import-mapping`: specifies a map of references external OpenAPI specs to go
- Go include paths. Please see below.
-
-So, for example, if you would like to produce only the server code, you could
-run `oapi-codegen -generate types,server`. You could generate `types` and
-`server` into separate files, but both are required for the server code.
-
-`oapi-codegen` can filter paths base on their tags in the openapi definition.
-Use either `-include-tags` or `-exclude-tags` followed by a comma-separated list
-of tags. For instance, to generate a server that serves all paths except those
-tagged with `auth` or `admin`, use the argument, `-exclude-tags="auth,admin"`.
-To generate a server that only handles `admin` paths, use the argument
-`-include-tags="admin"`. When neither of these arguments is present, all paths
-are generated.
-
-`oapi-codegen` can filter schemas based on the option `--exclude-schemas`, which is
-a comma separated list of schema names. For instance, `--exclude-schemas=Pet,NewPet`
-will exclude from generation schemas `Pet` and `NewPet`. This allow to have a
-in the same package a manually defined structure or interface and refer to it
-in the openapi spec.
-
-Since `go generate` commands must be a single line, all the options above can make
-them pretty unwieldy, so you can specify all of the options in a configuration
-file via the `--config` option. Please see the test under
-[`/internal/test/externalref/`](https://github.com/deepmap/oapi-codegen/blob/master/internal/test/externalref/externalref.cfg.yaml)
-for an example. The structure of the file is as follows:
-
-```yaml
-package: externalref
-generate:
- models: true
- embedded-spec: true
-import-mapping:
- ./packageA/spec.yaml: github.com/deepmap/oapi-codegen/internal/test/externalref/packageA
- ./packageB/spec.yaml: github.com/deepmap/oapi-codegen/internal/test/externalref/packageB
-output: externalref.gen.go
+If you'd like to reduce what's generated, you can use one of a few options in [the configuration file](#usage) to tune the generation of the resulting output:
+
+```yaml
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
output-options:
- skip-prune: true
+ include-tags: []
+ exclude-tags: []
+ include-operation-ids: []
+ exclude-operation-ids: []
+ exclude-schemas: []
```
-Have a look at [`cmd/oapi-codegen/oapi-codegen.go`](https://github.com/deepmap/oapi-codegen/blob/master/cmd/oapi-codegen/oapi-codegen.go#L48)
-to see all the fields on the configuration structure.
+Check [the docs](https://pkg.go.dev/github.com/oapi-codegen/oapi-codegen/v2/pkg/codegen#OutputOptions) for more details of usage.
-### Import Mappings
+### Should I commit the generated code?
-OpenAPI specifications may contain references to other OpenAPI specifications,
-and we need some additional information in order to be able to generate correct
-Go code.
+We recommend doing so, yes, for the following reasons:
-An external reference looks like this:
+- It means it's easier to view the impact of a change - be it due to an upgrade of `oapi-codegen`, or a change to your spec - and has helped catch (possibly) breaking changes in the past more easily
+- It then allows your codebase to be consumed as a library, as all the files are committed
- $ref: ./some_spec.yaml#/components/schemas/Type
+This means you'll need to have your CI/CD pipeline validate that generated files are all up-to-date, but that's a fairly straightforward piece of work.
-We assume that you have already generated the boilerplate code for `./some_spec.yaml`
-using `oapi-codegen`, and you have a package which contains the generated code,
-let's call it `github.com/deepmap/some-package`. You need to tell `oapi-codegen` that
-`some_spec.yaml` corresponds to this package, and you would do it by specifying
-this command line argument:
+### Should I lint the generated code?
- -import-mapping=./some_spec.yaml:github.com/deepmap/some-package
+We really ask that you don't. Although it intends to be idiomatic Go code, it's not expected to pass all the various linting rules that your project may apply.
-This tells us that in order to resolve references generated from `some_spec.yaml` we
-need to import `github.com/deepmap/some-package`. You may specify multiple mappings
-by comma separating them in the form `key1:value1,key2:value2`.
+> [!NOTE]
+> We will, on occasion, improve the generated code to fix some linting warnings, such as those from `go vet`, but this should not be an expected change.
-## What's missing or incomplete
+### I've just updated my version of `kin-openapi`, and now I can't build my code 😠
-This code is still young, and not complete, since we're filling it in as we
-need it. We've not yet implemented several things:
+The [kin-openapi](https://github.com/getkin/kin-openapi) project - which we 💜 for providing a great library and set of tooling for interacting with OpenAPI - is a pre-v1 release, which means that they're within their rights to push breaking changes.
-- `patternProperties` isn't yet supported and will exit with an error. Pattern
- properties were defined in JSONSchema, and the `kin-openapi` Swagger object
- knows how to parse them, but they're not part of OpenAPI 3.0, so we've left
- them out, as support is very complicated.
+This may lead to breakage in your consuming code, and if so, sorry that's happened!
-## Making changes to code generation
+We'll be aware of the issue, and will work to update both the core `oapi-codegen` and the middlewares accordingly.
-The code generator uses a tool to inline all the template definitions into
-code, so that we don't have to deal with the location of the template files.
-When you update any of the files under the `templates/` directory, you will
-need to regenerate the template inlines:
+## Contributors
- go generate ./pkg/codegen/templates
+We're very appreciative of [the many contributors over the years](https://github.com/oapi-codegen/oapi-codegen/graphs/contributors) and the ongoing use of the project 💜
-All this command does is inline the files ending in `.tmpl` into the specified
-Go file.
+
+
+
-Afterwards you should run `go generate ./...`, and the templates will be updated
-accordingly.
+## Sponsors
-Alternatively, you can provide custom templates to override built-in ones using
-the `-templates` flag specifying a path to a directory containing templates
-files. These files **must** be named identically to built-in template files
-(see `pkg/codegen/templates/*.tmpl` in the source code), and will be interpreted
-on-the-fly at run time. Example:
+For the most part, `oapi-codegen` is maintained in two busy peoples' free time. As noted in [Creating a more sustainable model for `oapi-codegen` in the future](https://github.com/oapi-codegen/oapi-codegen/discussions/1606), we're looking to make this a more sustainable project in the future.
- $ ls -1 my-templates/
- client.tmpl
- typedef.tmpl
- $ oapi-codegen \
- -templates my-templates/ \
- -generate types,client \
- petstore-expanded.yaml
+Please consider sponsoring us through GitHub Sponsors either [on the organisation](https://github.com/sponsors/oapi-codegen/) or [directly for Jamie](https://github.com/sponsors/jamietanna/), which helps work towards us being able to maintain the project long term.
-When using the configuration file, it is possible to provide templates directly
-as text, as a local path, or as a URL. If the data provided to the
-configuration file is more than one line, the local path and URL checks will be
-ignored and will be treated as raw template text. If one line, the string
-will be used to check for a local file, followed by checking performing a HTTP
-GET request. If the file lookup returns any error other than not found, or the
-HTTP request returns a non 200 response code, the generator will error.
+See [this blog post from Tidelift](https://blog.tidelift.com/paying-maintainers-the-howto) for more details on how to talk to your company about sponsoring maintainers of (Open Source) projects you depend on.
-⚠️ Warning: If using urls that tracks against git repositories such as
-`raw.githubusercontent.com`, it is strongly encouraged to use a tag or a hash
-instead of a branch like `main`. Tracking a branch can lead to unexpected API
-drift, and loss of the ability to reproduce a build.
+We are also generously sponsored by the following folks, each of whom provide sponsorship for 1 hour of work a month:
-Examples:
-
-```yaml
-output: api.gen.go
-package: api
-output-options:
- user-templates:
- # using a local file
- client-with-responses.tmpl: /home/username/workspace/templatesProject/my-client-with-responses.tmpl
-
- # The following are referencing a versuion of the default
- # client-with-responses.tmpl file, but loaded in through
- # github's raw.githubusercontent.com. The general form
- # to use raw.githubusercontent.com is as follows
- # https://raw.githubusercontent.com////path/to/template/template.tmpl
-
- # using raw.githubusercontent.com with a hash
- client-with-responses.tmpl: https://raw.githubusercontent.com/deepmap/oapi-codegen/7b010099dcf1192b3bfaa3898b5f375bb9590ddf/pkg/codegen/templates/client-with-responses.tmpl
- # using raw.githubusercontent.com with a tag
- client-with-responses.tmpl: https://raw.githubusercontent.com/deepmap/oapi-codegen/v1.12.4/pkg/codegen/templates/client-with-responses.tmpl
- # using raw.githubusercontent.com with a branch
- client-with-responses.tmpl: https://raw.githubusercontent.com/deepmap/oapi-codegen/master/pkg/codegen/templates/client-with-responses.tmpl
-
- #This example is directly embedding the template into the config file.
- client-with-responses.tmpl: |
- // ClientWithResponses builds on ClientInterface to offer response payloads
- type ClientWithResponses struct {
- ClientInterface
- }
- ...
- # template shortened for brevity
+
+
+
+
+
+
+
+
+
-```
+
+
+
+
+
-Using the configuration file to load in templates **will** load in templates
-with names other than those defined by the built in templates. These user
-templates will not be called unless the user overrides a built in template to
-call them however.
+(Note that the order of appearance the order in which sponsorship was received)
diff --git a/SUPPORT.md b/SUPPORT.md
new file mode 100644
index 0000000000..41fd214d54
--- /dev/null
+++ b/SUPPORT.md
@@ -0,0 +1,41 @@
+# Support model
+
+[`oapi-codegen`](https://github.com/oapi-codegen/oapi-codegen) is currently supported in a best-efforts means, due to the [Core Maintainers](https://github.com/oapi-codegen/governance/#core-maintainer) working in their "off hours" from their busy jobs.
+
+We do thoroughly appreciate our users, the feature requests and bug reports raised, and want to set expectations accordingly.
+
+Related:
+
+- [Creating a more sustainable model for `oapi-codegen` in the future](https://github.com/oapi-codegen/oapi-codegen/discussions/1606)
+- [Looking back at `oapi-codegen`'s last year](https://github.com/oapi-codegen/oapi-codegen/discussions/1985)
+
+## Supported versions
+
+Only the latest minor release version of `oapi-codegen` is supported for active development.
+
+`oapi-codegen` does not currently backport any bug fixes.
+
+## Security updates
+
+Related: [`oapi-codegen`'s organisational security policy (`SECURITY.md`)](https://github.com/oapi-codegen/.github/blob/HEAD/SECURITY.md).
+
+## Minimum required Go toolchain version
+
+As per [the install instructions](https://github.com/oapi-codegen/oapi-codegen/#install), `oapi-codegen`'s recommended installation model is as a source-tracked dependency, for instance using `go tool`.
+
+Because of this, we take more care to resist bumping the `go` directive, as it has a knock-on effect for all consumers of `oapi-codegen`, as it requires the consumer to _also_ bump their `go` directive.
+
+When considering whether to bump the `go` directive, we will consider:
+
+- Do we _definitely_ need to pull in this new version of Go?
+ - Can we work around it by not using new language features?
+- If this is a requirement of an upstream dependency, can upstream use build tags ([like so](https://github.com/charmbracelet/log/pull/13)), to allow us to continue using old versions of Go?
+ - If it is a requirement, and we don't want to bump it (yet), can we avoid the Go version bump?
+- Is the new version supported by the Go team?
+ - We're comfortable not requiring the Go version being in active support - it's up to consumers to decide what toolchain + standard library version they want to use to build
+
+We will not mandate a `toolchain` directive.
+
+## Additional support
+
+For additional support, it's worth reading [oapi-codegen/governance: Sponsorship](https://github.com/oapi-codegen/governance/#sponsorship), and visiting the different [funding options](https://github.com/oapi-codegen/oapi-codegen/blob/main/.github/FUNDING.yml).
diff --git a/cmd/oapi-codegen/oapi-codegen.go b/cmd/oapi-codegen/oapi-codegen.go
index 9bf32030d7..f540a6808a 100644
--- a/cmd/oapi-codegen/oapi-codegen.go
+++ b/cmd/oapi-codegen/oapi-codegen.go
@@ -14,6 +14,7 @@
package main
import (
+ "bytes"
"flag"
"fmt"
"os"
@@ -23,13 +24,16 @@ import (
"runtime/debug"
"strings"
- "gopkg.in/yaml.v2"
+ "go.yaml.in/yaml/v3"
- "github.com/deepmap/oapi-codegen/pkg/codegen"
- "github.com/deepmap/oapi-codegen/pkg/util"
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/codegen"
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/util"
)
-func errExit(format string, args ...interface{}) {
+func errExit(format string, args ...any) {
+ if !strings.HasSuffix(format, "\n") {
+ format = format + "\n"
+ }
_, _ = fmt.Fprintf(os.Stderr, format, args...)
os.Exit(1)
}
@@ -47,13 +51,14 @@ var (
// Deprecated: The options below will be removed in a future
// release. Please use the new config file format.
- flagIncludeTags string
- flagExcludeTags string
- flagImportMapping string
- flagExcludeSchemas string
- flagResponseTypeSuffix string
- flagAliasTypes bool
- flagInitalismOverrides bool
+ flagIncludeTags string
+ flagExcludeTags string
+ flagIncludeOperationIDs string
+ flagExcludeOperationIDs string
+ flagImportMapping string
+ flagExcludeSchemas string
+ flagResponseTypeSuffix string
+ flagAliasTypes bool
)
type configuration struct {
@@ -66,16 +71,18 @@ type configuration struct {
// oldConfiguration is deprecated. Please add no more flags here. It is here
// for backwards compatibility, and it will be removed in the future.
type oldConfiguration struct {
- PackageName string `yaml:"package"`
- GenerateTargets []string `yaml:"generate"`
- OutputFile string `yaml:"output"`
- IncludeTags []string `yaml:"include-tags"`
- ExcludeTags []string `yaml:"exclude-tags"`
- TemplatesDir string `yaml:"templates"`
- ImportMapping map[string]string `yaml:"import-mapping"`
- ExcludeSchemas []string `yaml:"exclude-schemas"`
- ResponseTypeSuffix string `yaml:"response-type-suffix"`
- Compatibility codegen.CompatibilityOptions `yaml:"compatibility"`
+ PackageName string `yaml:"package"`
+ GenerateTargets []string `yaml:"generate"`
+ OutputFile string `yaml:"output"`
+ IncludeTags []string `yaml:"include-tags"`
+ ExcludeTags []string `yaml:"exclude-tags"`
+ IncludeOperationIDs []string `yaml:"include-operation-ids"`
+ ExcludeOperationIDs []string `yaml:"exclude-operation-ids"`
+ TemplatesDir string `yaml:"templates"`
+ ImportMapping map[string]string `yaml:"import-mapping"`
+ ExcludeSchemas []string `yaml:"exclude-schemas"`
+ ResponseTypeSuffix string `yaml:"response-type-suffix"`
+ Compatibility codegen.CompatibilityOptions `yaml:"compatibility"`
}
// noVCSVersionOverride allows overriding the version of the application for cases where no Version Control System (VCS) is available when building, for instance when using a Nix derivation.
@@ -95,15 +102,16 @@ func main() {
// All flags below are deprecated, and will be removed in a future release. Please do not
// update their behavior.
flag.StringVar(&flagGenerate, "generate", "types,client,server,spec",
- `Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "gin", "gorilla", "spec", "skip-fmt", "skip-prune", "fiber", "iris".`)
+ `Comma-separated list of code to generate; valid options: "types", "client", "chi-server", "server", "gin", "gorilla", "spec", "skip-fmt", "skip-prune", "fiber", "iris", "std-http".`)
flag.StringVar(&flagIncludeTags, "include-tags", "", "Only include operations with the given tags. Comma-separated list of tags.")
flag.StringVar(&flagExcludeTags, "exclude-tags", "", "Exclude operations that are tagged with the given tags. Comma-separated list of tags.")
+ flag.StringVar(&flagIncludeOperationIDs, "include-operation-ids", "", "Only include operations with the given operation-ids. Comma-separated list of operation-ids.")
+ flag.StringVar(&flagExcludeOperationIDs, "exclude-operation-ids", "", "Exclude operations with the given operation-ids. Comma-separated list of operation-ids.")
flag.StringVar(&flagTemplatesDir, "templates", "", "Path to directory containing user templates.")
flag.StringVar(&flagImportMapping, "import-mapping", "", "A dict from the external reference to golang package path.")
flag.StringVar(&flagExcludeSchemas, "exclude-schemas", "", "A comma separated list of schemas which must be excluded from generation.")
flag.StringVar(&flagResponseTypeSuffix, "response-type-suffix", "", "The suffix used for responses types.")
- flag.BoolVar(&flagAliasTypes, "alias-types", false, "Alias type declarations of possible.")
- flag.BoolVar(&flagInitalismOverrides, "initialism-overrides", false, "Use initialism overrides.")
+ flag.BoolVar(&flagAliasTypes, "alias-types", false, "Alias type declarations if possible.")
flag.Parse()
@@ -149,10 +157,14 @@ func main() {
errExit("error reading config file '%s': %v\n", flagConfigFile, err)
}
var oldConfig oldConfiguration
- oldErr := yaml.UnmarshalStrict(configFile, &oldConfig)
+ oldDec := yaml.NewDecoder(bytes.NewReader(configFile))
+ oldDec.KnownFields(true)
+ oldErr := oldDec.Decode(&oldConfig)
var newConfig configuration
- newErr := yaml.UnmarshalStrict(configFile, &newConfig)
+ newDec := yaml.NewDecoder(bytes.NewReader(configFile))
+ newDec.KnownFields(true)
+ newErr := newDec.Decode(&newConfig)
// If one of the two files parses, but the other fails, we know the
// answer.
@@ -240,7 +252,13 @@ func main() {
errExit("error parsing'%s' as YAML: %v\n", flagConfigFile, err)
}
}
- opts = newConfigFromOldConfig(oldConfig)
+ var err error
+ opts, err = newConfigFromOldConfig(oldConfig)
+ if err != nil {
+ flag.PrintDefaults()
+ errExit("error creating new config from old config: %v\n", err)
+ }
+
}
// Ensure default values are set if user hasn't specified some needed
@@ -256,37 +274,73 @@ func main() {
errExit("configuration error: %v\n", err)
}
+ if warnings := opts.Generate.Warnings(); len(warnings) > 0 {
+ var out strings.Builder
+ out.WriteString("WARNING: A number of warning(s) were returned when validating the GenerateOptions:")
+ for k, v := range warnings {
+ out.WriteString("\n- " + k + ": " + v)
+ }
+
+ _, _ = fmt.Fprint(os.Stderr, out.String())
+ }
+
// If the user asked to output configuration, output it to stdout and exit
if flagOutputConfig {
- buf, err := yaml.Marshal(opts)
- if err != nil {
+ var buf bytes.Buffer
+ enc := yaml.NewEncoder(&buf)
+ enc.SetIndent(2)
+ if err := enc.Encode(opts); err != nil {
errExit("error YAML marshaling configuration: %v\n", err)
}
- fmt.Print(string(buf))
+ _ = enc.Close()
+ fmt.Print(buf.String())
return
}
- swagger, err := util.LoadSwaggerWithCircularReferenceCount(flag.Arg(0), opts.Compatibility.CircularReferenceLimit)
- if err != nil {
- errExit("error loading swagger spec in %s\n: %s", flag.Arg(0), err)
+ overlayOpts := util.LoadSwaggerWithOverlayOpts{
+ Path: opts.OutputOptions.Overlay.Path,
+ // default to strict, but can be overridden
+ Strict: true,
}
- if len(noVCSVersionOverride) > 0 {
- opts.Configuration.NoVCSVersionOverride = &noVCSVersionOverride
+ if opts.OutputOptions.Overlay.Strict != nil {
+ overlayOpts.Strict = *opts.OutputOptions.Overlay.Strict
}
- code, err := codegen.Generate(swagger, opts.Configuration)
+ swagger, err := util.LoadSwaggerWithOverlay(flag.Arg(0), overlayOpts)
if err != nil {
- errExit("error generating code: %s\n", err)
+ errExit("error loading swagger spec in %s\n: %s\n", flag.Arg(0), err)
}
- if opts.OutputFile != "" {
- err = os.WriteFile(opts.OutputFile, []byte(code), 0o644)
- if err != nil {
- errExit("error writing generated code to file: %s\n", err)
+ if strings.HasPrefix(swagger.OpenAPI, "3.1.") {
+ fmt.Fprintln(os.Stderr, "WARNING: You are using an OpenAPI 3.1.x specification, which is not yet supported by oapi-codegen (https://github.com/oapi-codegen/oapi-codegen/issues/373) and so some functionality may not be available. Until oapi-codegen supports OpenAPI 3.1, it is recommended to downgrade your spec to 3.0.x")
+ }
+
+ if len(noVCSVersionOverride) > 0 {
+ opts.NoVCSVersionOverride = &noVCSVersionOverride
+ }
+
+ code, genErr := codegen.Generate(swagger, opts.Configuration)
+
+ // Always emit any generated code to the requested destination, even when
+ // generation returned an error (e.g. the formatter rejected the output).
+ // Writing to the output file lets the user inspect the broken source
+ // directly instead of having it interleaved with stderr.
+ if code != "" {
+ if opts.OutputFile != "" {
+ if err := os.MkdirAll(filepath.Dir(opts.OutputFile), 0o755); err != nil {
+ errExit("error unable to create directory: %s\n", err)
+ }
+ if err := os.WriteFile(opts.OutputFile, []byte(code), 0o644); err != nil {
+ errExit("error writing generated code to file: %s\n", err)
+ }
+ } else {
+ fmt.Print(code)
}
- } else {
- fmt.Print(code)
+ }
+
+ if genErr != nil {
+ errExit("error generating code: %s\n", genErr)
}
}
@@ -382,6 +436,13 @@ func updateConfigFromFlags(cfg *configuration) error {
if flagExcludeTags != "" {
cfg.OutputOptions.ExcludeTags = util.ParseCommandLineList(flagExcludeTags)
}
+ if flagIncludeOperationIDs != "" {
+ cfg.OutputOptions.IncludeOperationIDs = util.ParseCommandLineList(flagIncludeOperationIDs)
+ }
+ if flagExcludeOperationIDs != "" {
+ cfg.OutputOptions.ExcludeOperationIDs = util.ParseCommandLineList(flagExcludeOperationIDs)
+ }
+
if flagTemplatesDir != "" {
templates, err := loadTemplateOverrides(flagTemplatesDir)
if err != nil {
@@ -410,8 +471,6 @@ func updateConfigFromFlags(cfg *configuration) error {
cfg.OutputFile = flagOutputFile
}
- cfg.OutputOptions.InitialismOverrides = flagInitalismOverrides
-
return nil
}
@@ -463,10 +522,14 @@ func generationTargets(cfg *codegen.Configuration, targets []string) error {
opts.FiberServer = true
case "server", "echo-server", "echo":
opts.EchoServer = true
+ case "echo5", "echo5-server":
+ opts.Echo5Server = true
case "gin", "gin-server":
opts.GinServer = true
case "gorilla", "gorilla-server":
opts.GorillaServer = true
+ case "std-http", "std-http-server":
+ opts.StdHTTPServer = true
case "strict-server":
opts.Strict = true
case "client":
@@ -488,7 +551,7 @@ func generationTargets(cfg *codegen.Configuration, targets []string) error {
return nil
}
-func newConfigFromOldConfig(c oldConfiguration) configuration {
+func newConfigFromOldConfig(c oldConfiguration) (configuration, error) {
// Take flags into account.
cfg := updateOldConfigFromFlags(c)
@@ -500,9 +563,7 @@ func newConfigFromOldConfig(c oldConfiguration) configuration {
opts.OutputOptions.ResponseTypeSuffix = flagResponseTypeSuffix
if err := generationTargets(&opts, cfg.GenerateTargets); err != nil {
- fmt.Println(err)
- flag.PrintDefaults()
- os.Exit(1)
+ return configuration{}, fmt.Errorf("generation targets: %w", err)
}
opts.OutputOptions.IncludeTags = cfg.IncludeTags
@@ -511,7 +572,7 @@ func newConfigFromOldConfig(c oldConfiguration) configuration {
templates, err := loadTemplateOverrides(cfg.TemplatesDir)
if err != nil {
- errExit("error loading template overrides: %s\n", err)
+ return configuration{}, fmt.Errorf("loading template overrides: %w", err)
}
opts.OutputOptions.UserTemplates = templates
@@ -522,5 +583,5 @@ func newConfigFromOldConfig(c oldConfiguration) configuration {
return configuration{
Configuration: opts,
OutputFile: cfg.OutputFile,
- }
+ }, nil
}
diff --git a/cmd/oapi-codegen/oapi-codegen_test.go b/cmd/oapi-codegen/oapi-codegen_test.go
index 06992d9f73..f60dbb9afb 100644
--- a/cmd/oapi-codegen/oapi-codegen_test.go
+++ b/cmd/oapi-codegen/oapi-codegen_test.go
@@ -3,14 +3,14 @@ package main
import (
"testing"
- "github.com/deepmap/oapi-codegen/pkg/util"
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/util"
)
func TestLoader(t *testing.T) {
paths := []string{
"../../examples/petstore-expanded/petstore-expanded.yaml",
- "https://petstore3.swagger.io/api/v3/openapi.json",
+ "https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/v2.4.1/examples/petstore-expanded/petstore-expanded.yaml",
}
for _, v := range paths {
diff --git a/configuration-schema.json b/configuration-schema.json
new file mode 100644
index 0000000000..9290cc121a
--- /dev/null
+++ b/configuration-schema.json
@@ -0,0 +1,376 @@
+{
+ "$schema": "http://json-schema.org/draft-07/schema#",
+ "description": "Configuration files for oapi-codegen",
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "package": {
+ "type": "string",
+ "description": "Go package name to generate the code under"
+ },
+ "generate": {
+ "type": "object",
+ "additionalProperties": false,
+ "description": "Generate specifies which supported output formats to generate",
+ "properties": {
+ "iris-server": {
+ "type": "boolean",
+ "description": "IrisServer specifies whether to generate iris server boilerplate"
+ },
+ "chi-server": {
+ "type": "boolean",
+ "description": "ChiServer specifies whether to generate chi server boilerplate"
+ },
+ "fiber-server": {
+ "type": "boolean",
+ "description": "FiberServer specifies whether to generate fiber server boilerplate"
+ },
+ "echo-server": {
+ "type": "boolean",
+ "description": "EchoServer specifies whether to generate echo server boilerplate"
+ },
+ "echo5-server": {
+ "type": "boolean",
+ "description": "Echo5Server specifies whether to generate echo v5 server boilerplate"
+ },
+ "gin-server": {
+ "type": "boolean",
+ "description": "GinServer specifies whether to generate gin server boilerplate"
+ },
+ "gorilla-server": {
+ "type": "boolean",
+ "description": "GorillaServer specifies whether to generate Gorilla server boilerplate"
+ },
+ "std-http-server": {
+ "type": "boolean",
+ "description": "StdHTTPServer specifies whether to generate stdlib http server boilerplate"
+ },
+ "strict-server": {
+ "type": "boolean",
+ "description": "Strict specifies whether to generate strict server wrapper"
+ },
+ "client": {
+ "type": "boolean",
+ "description": "Client specifies whether to generate client boilerplate"
+ },
+ "models": {
+ "type": "boolean",
+ "description": "Models specifies whether to generate type definitions"
+ },
+ "embedded-spec": {
+ "type": "boolean",
+ "description": "EmbeddedSpec indicates whether to embed the swagger spec in the generated code"
+ },
+ "server-urls": {
+ "type": "boolean",
+ "description": "Generate types for the `Server` definitions' URLs, instead of needing to provide your own values"
+ }
+ }
+ },
+ "compatibility": {
+ "type": "object",
+ "additionalProperties": false,
+ "description": "",
+ "properties": {
+ "old-merge-schemas": {
+ "type": "boolean",
+ "description": "In the past, we merged schemas for `allOf` by inlining each schema within the schema list. This approach, though, is incorrect because `allOf` merges at the schema definition level, not at the resulting model level. So, new behavior merges OpenAPI specs but generates different code than we have in the past. Set OldMergeSchemas to true for the old behavior. Please see https://github.com/oapi-codegen/oapi-codegen/issues/531"
+ },
+ "old-allof-sibling-merging": {
+ "type": "boolean",
+ "description": "In the past, when a schema combined `allOf` with sibling fields at the same level (`properties`, `required`, `additionalProperties`, `description`), those siblings were silently discarded and the schema was emitted as a Go type alias to its sole `allOf` target. New behavior merges the parent's siblings with the `allOf` members so the generated type carries every field declared in the spec. This is a more accurate translation of OpenAPI semantics, but it changes the shape of generated types: a schema that previously produced `type X = Y` may now produce a distinct struct embedding Y with extra fields, which is not interchangeable with Y in downstream Go code. Set OldAllOfSiblingMerging to true to restore the prior behavior. Please see https://github.com/oapi-codegen/oapi-codegen/issues/697"
+ },
+ "old-enum-conflicts": {
+ "type": "boolean",
+ "description": "Enum values can generate conflicting typenames, so we've updated the code for enum generation to avoid these conflicts, but it will result in some enum types being renamed in existing code. Set OldEnumConflicts to true to revert to old behavior. Please see: Please see https://github.com/oapi-codegen/oapi-codegen/issues/549"
+ },
+ "old-aliasing": {
+ "type": "boolean",
+ "description": "It was a mistake to generate a go type definition for every $ref in the OpenAPI schema. New behavior uses type aliases where possible, but this can generate code which breaks existing builds. Set OldAliasing to true for old behavior. Please see https://github.com/oapi-codegen/oapi-codegen/issues/549"
+ },
+ "disable-flatten-additional-properties": {
+ "type": "boolean",
+ "description": "When an object contains no members, and only an additionalProperties specification, it is flattened to a map"
+ },
+ "disable-required-readonly-as-pointer": {
+ "type": "boolean",
+ "description": "When an object property is both required and readOnly the go model is generated as a pointer. Set DisableRequiredReadOnlyAsPointer to true to mark them as non pointer. Please see https://github.com/oapi-codegen/oapi-codegen/issues/604"
+ },
+ "always-prefix-enum-values": {
+ "type": "boolean",
+ "description": "When set to true, always prefix enum values with their type name instead of only when typenames would be conflicting."
+ },
+ "apply-chi-middleware-first-to-last": {
+ "type": "boolean",
+ "description": "Our generated code for Chi has historically inverted the order in which Chi middleware is applied such that the last invoked middleware ends up executing first in the Chi chain This resolves the behavior such that middlewares are chained in the order they are invoked. Please see https://github.com/oapi-codegen/oapi-codegen/issues/786"
+ },
+ "apply-gorilla-middleware-first-to-last": {
+ "type": "boolean",
+ "description": "Our generated code for gorilla/mux has historically inverted the order in which gorilla/mux middleware is applied such that the last invoked middleware ends up executing first in the middlewares chain This resolves the behavior such that middlewares are chained in the order they are invoked. Please see https://github.com/oapi-codegen/oapi-codegen/issues/841"
+ },
+ "circular-reference-limit": {
+ "type": "integer",
+ "description": "DEPRECATED: No longer used.\nCircularReferenceLimit allows controlling the limit for circular reference checking. In some OpenAPI specifications, we have a higher number of circular references than is allowed out-of-the-box, but can be tuned to allow traversing them."
+ },
+ "allow-unexported-struct-field-names": {
+ "type": "boolean",
+ "description": "AllowUnexportedStructFieldNames makes it possible to output structs that have fields that are unexported.\nThis is expected to be used in conjunction with an extension such as `x-go-name` to override the output name, and `x-oapi-codegen-extra-tags` to not produce JSON tags for `encoding/json`.\nNOTE that this can be confusing to users of your OpenAPI specification, who may see a field present and therefore be expecting to see it in the response, without understanding the nuance of how `oapi-codegen` generates the code."
+ },
+ "preserve-original-operation-id-casing-in-embedded-spec": {
+ "type": "boolean",
+ "description": "When `oapi-codegen` parses the original OpenAPI specification, it will apply the configured `output-options.name-normalizer` to each operation's `operationId` before that is used to generate code from.\nHowever, this is also applied to the copy of the `operationId`s in the `embedded-spec` generation, which means that the embedded OpenAPI specification is then out-of-sync with the input specificiation.\nTo ensure that the `operationId` in the embedded spec is preserved as-is from the input specification, set this. NOTE that this will not impact generated code.\nNOTE that if you're using `include-operation-ids` or `exclude-operation-ids` you may want to ensure that the `operationId`s used are correct."
+ },
+ "headers-implicitly-required": {
+ "type": "boolean",
+ "description": "Treats all response headers as required, ignoring the `required` property from the header definition. Prior to v2.6.0, oapi-codegen generated all response headers as direct values (implicitly required). The OpenAPI specification defaults headers to optional (required: false), so the corrected behavior generates optional headers as pointers. Set this to true to restore the old behavior where all headers are treated as required.\nPlease see https://github.com/oapi-codegen/oapi-codegen/issues/2267"
+ }
+ }
+ },
+ "output-options": {
+ "type": "object",
+ "additionalProperties": false,
+ "description": "OutputOptions are used to modify the output code in some way",
+ "properties": {
+ "skip-fmt": {
+ "type": "boolean",
+ "description": "Whether to skip go imports on the generated code"
+ },
+ "skip-prune": {
+ "type": "boolean",
+ "description": "Whether to skip pruning unused components on the generated code"
+ },
+ "skip-enum-validate": {
+ "type": "boolean",
+ "description": "Whether to skip generation of the Valid() method on enum types"
+ },
+ "include-tags": {
+ "type": "array",
+ "description": "Only include operations that have one of these tags. Ignored when empty.",
+ "items": {
+ "type": "string"
+ }
+ },
+ "exclude-tags": {
+ "type": "array",
+ "description": "Exclude operations that have one of these tags. Ignored when empty.",
+ "items": {
+ "type": "string"
+ }
+ },
+ "include-operation-ids": {
+ "type": "array",
+ "description": "Only include operations that have one of these operation-ids. Ignored when empty.",
+ "items": {
+ "type": "string"
+ }
+ },
+ "exclude-operation-ids": {
+ "type": "array",
+ "description": "Exclude operations that have one of these operation-ids. Ignored when empty.",
+ "items": {
+ "type": "string"
+ }
+ },
+ "user-templates": {
+ "type": "object",
+ "description": "Override built-in templates from user-provided files",
+ "additionalProperties": {
+ "type": "string"
+ }
+ },
+ "exclude-schemas": {
+ "type": "array",
+ "description": "Exclude from generation schemas with given names. Ignored when empty.",
+ "items": {
+ "type": "string"
+ }
+ },
+ "response-type-suffix": {
+ "type": "string",
+ "description": "The suffix used for responses types"
+ },
+ "client-type-name": {
+ "type": "string",
+ "description": "Override the default generated client type with the value"
+ },
+ "additional-initialisms": {
+ "type": "array",
+ "description": "AdditionalInitialisms defines additional initialisms to be used by the code generator. Has no effect unless the `name-normalizer` is set to `ToCamelCaseWithInitialisms`",
+ "items": {
+ "type": "string"
+ }
+ },
+ "streaming-content-types": {
+ "type": "array",
+ "description": "Additional regex patterns matched against response Content-Type to decide when the strict server should generate a flush-per-chunk streaming response. Merged with the defaults (text/event-stream, application/jsonl, application/x-ndjson). Invalid regexes fail configuration validation.",
+ "items": {
+ "type": "string"
+ }
+ },
+ "nullable-type": {
+ "type": "boolean",
+ "description": "Whether to generate nullable type for nullable fields"
+ },
+ "disable-type-aliases-for-type": {
+ "type": "array",
+ "description": "DisableTypeAliasesForType allows defining which OpenAPI `type`s will explicitly not use type aliases",
+ "items": {
+ "type": "string",
+ "enum": ["array"]
+ }
+ },
+ "name-normalizer": {
+ "type": "string",
+ "description": "NameNormalizer is the method used to normalize Go names and types, for instance converting the text `MyApi` to `MyAPI`. Corresponds with the constants defined for `codegen.NameNormalizerFunction`",
+ "default": "ToCamelCase",
+ "enum": [
+ "ToCamelCase",
+ "ToCamelCaseWithDigits",
+ "ToCamelCaseWithInitialisms"
+ ]
+ },
+ "overlay": {
+ "type": "object",
+ "description": "Overlay defines configuration for the OpenAPI Overlay (https://github.com/OAI/Overlay-Specification) to manipulate the OpenAPI specification before generation. This allows modifying the specification without needing to apply changes directly to it, making it easier to keep it up-to-date.",
+ "properties": {
+ "path": {
+ "description": "The path to the Overlay file",
+ "type": "string"
+ },
+ "strict": {
+ "type": "boolean",
+ "description": "Strict defines whether the Overlay should be applied in a strict way, highlighting any actions that will not take any effect. This can, however, lead to more work when testing new actions in an Overlay, so can be turned off with this setting.",
+ "default": true
+ }
+ },
+ "required": ["path"]
+ },
+ "yaml-tags": {
+ "type": "boolean",
+ "description": "Enable the generation of YAML tags for struct fields"
+ },
+ "client-response-bytes-function": {
+ "type": "boolean",
+ "description": "Enable the generation of a `Bytes()` method on response objects for `ClientWithResponses`"
+ },
+ "skip-client-response-content-type": {
+ "type": "boolean",
+ "description": "Disable the generation of a `ContentType()` method on response objects for `ClientWithResponses`, which is otherwise generated by default."
+ },
+ "skip-response-body-getters": {
+ "type": "boolean",
+ "description": "Disable the generation of `GetBody()` and `Get()` getter methods on response objects for `ClientWithResponses`, which are otherwise generated by default."
+ },
+ "prefer-skip-optional-pointer": {
+ "type": "boolean",
+ "description": "Allows defining at a global level whether to omit the pointer for a type to indicate that the field/type is optional. This is the same as adding `x-go-type-skip-optional-pointer` to each field (manually, or using an OpenAPI Overlay). A field can set `x-go-type-skip-optional-pointer: false` to still require the optional pointer.",
+ "default": false
+ },
+ "prefer-skip-optional-pointer-with-omitzero": {
+ "type": "boolean",
+ "description": "When using `prefer-skip-optional-pointer`, generate the `omitzero` JSON tag for types that would have had an optional pointer. This is the same as adding `x-omitzero` to each field (manually, or using an OpenAPI Overlay). A field can set `x-omitzero: false` to disable the `omitzero` JSON tag.\nNOTE that this requires Go 1.24+.\nNOTE that this must be used alongside `prefer-skip-optional-pointer`, otherwise makes no difference.",
+ "default": false
+ },
+ "prefer-skip-optional-pointer-on-container-types": {
+ "type": "boolean",
+ "description": "Allows disabling the generation of an 'optional pointer' for an optional field that is a container type (such as a slice or a map), which ends up requiring an additional, unnecessary, `... != nil` check. A field can set `x-go-type-skip-optional-pointer: false` to still require the optional pointer.",
+ "default": false
+ },
+ "resolve-type-name-collisions": {
+ "type": "boolean",
+ "description": "When set to true, automatically renames types that collide across different OpenAPI component sections (schemas, parameters, requestBodies, responses, headers) by appending a suffix based on the component section. Also detects collisions between component types and client response wrapper types. Without this, the codegen will error on duplicate type names, requiring manual resolution via x-go-name.",
+ "default": false
+ },
+ "type-mapping": {
+ "type": "object",
+ "additionalProperties": false,
+ "description": "TypeMapping allows customizing OpenAPI type/format to Go type mappings. User-specified mappings are merged on top of the defaults, so you only need to specify the types you want to override.",
+ "properties": {
+ "integer": {
+ "$ref": "#/$defs/format-mapping"
+ },
+ "number": {
+ "$ref": "#/$defs/format-mapping"
+ },
+ "boolean": {
+ "$ref": "#/$defs/format-mapping"
+ },
+ "string": {
+ "$ref": "#/$defs/format-mapping"
+ }
+ }
+ }
+ }
+ },
+ "import-mapping": {
+ "type": "object",
+ "additionalProperties": {
+ "type": "string",
+ "description": "ImportMapping specifies the golang package path for each external reference. A value of `-` will indicate that the current package will be used"
+ }
+ },
+ "additional-imports": {
+ "type": "array",
+ "items": {
+ "type": "object",
+ "additionalProperties": false,
+ "properties": {
+ "alias": {
+ "type": "string"
+ },
+ "package": {
+ "type": "string"
+ }
+ },
+ "required": ["package"]
+ },
+ "description": "AdditionalImports defines any additional Go imports to add to the generated code"
+ },
+ "output": {
+ "type": "string",
+ "description": "The filename to output"
+ }
+ },
+ "required": [
+ "package",
+ "output"
+ ],
+ "$defs": {
+ "simple-type-spec": {
+ "type": "object",
+ "additionalProperties": false,
+ "description": "Specifies a Go type and optional import path",
+ "properties": {
+ "type": {
+ "type": "string",
+ "description": "The Go type to use (e.g. \"int64\", \"time.Time\", \"github.com/shopspring/decimal.Decimal\")"
+ },
+ "import": {
+ "type": "string",
+ "description": "The Go import path required for this type (e.g. \"time\", \"encoding/json\")"
+ }
+ },
+ "required": [
+ "type"
+ ]
+ },
+ "format-mapping": {
+ "type": "object",
+ "additionalProperties": false,
+ "description": "Maps an OpenAPI type's formats to Go types",
+ "properties": {
+ "default": {
+ "$ref": "#/$defs/simple-type-spec",
+ "description": "The default Go type when no format is specified or the format is unrecognized"
+ },
+ "formats": {
+ "type": "object",
+ "description": "Format-specific Go type overrides (e.g. \"int32\": {\"type\": \"int32\"}, \"double\": {\"type\": \"float64\"})",
+ "additionalProperties": {
+ "$ref": "#/$defs/simple-type-spec"
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/examples/Makefile b/examples/Makefile
new file mode 100644
index 0000000000..41d1778de8
--- /dev/null
+++ b/examples/Makefile
@@ -0,0 +1,18 @@
+lint:
+ $(GOBIN)/golangci-lint run ./...
+
+lint-ci:
+ $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m
+
+.PHONY: generate
+generate:
+ go generate ./...
+
+test:
+ go test -cover ./...
+
+tidy:
+ go mod tidy
+
+tidy-ci:
+ tidied -verbose
diff --git a/examples/anyof-allof-oneof/anyofallofoneof.gen.go b/examples/anyof-allof-oneof/anyofallofoneof.gen.go
new file mode 100644
index 0000000000..99b8616833
--- /dev/null
+++ b/examples/anyof-allof-oneof/anyofallofoneof.gen.go
@@ -0,0 +1,167 @@
+// Package anyofallofoneof provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package anyofallofoneof
+
+import (
+ "encoding/json"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// Client defines model for Client.
+type Client struct {
+ Name string `json:"name"`
+}
+
+// ClientAndMaybeIdentity defines model for ClientAndMaybeIdentity.
+type ClientAndMaybeIdentity struct {
+ union json.RawMessage
+}
+
+// ClientOrIdentity defines model for ClientOrIdentity.
+type ClientOrIdentity struct {
+ union json.RawMessage
+}
+
+// ClientWithId defines model for ClientWithId.
+type ClientWithId struct {
+ Id int `json:"id"`
+ Name string `json:"name"`
+}
+
+// Identity defines model for Identity.
+type Identity struct {
+ Issuer string `json:"issuer"`
+}
+
+// IdentityWithDuplicateField defines model for IdentityWithDuplicateField.
+type IdentityWithDuplicateField struct {
+ Issuer struct {
+ Name string `json:"name"`
+ } `json:"issuer"`
+}
+
+// AsClient returns the union data inside the ClientAndMaybeIdentity as a Client
+func (t ClientAndMaybeIdentity) AsClient() (Client, error) {
+ var body Client
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromClient overwrites any union data inside the ClientAndMaybeIdentity as the provided Client
+func (t *ClientAndMaybeIdentity) FromClient(v Client) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeClient performs a merge with any union data inside the ClientAndMaybeIdentity, using the provided Client
+func (t *ClientAndMaybeIdentity) MergeClient(v Client) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsIdentity returns the union data inside the ClientAndMaybeIdentity as a Identity
+func (t ClientAndMaybeIdentity) AsIdentity() (Identity, error) {
+ var body Identity
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromIdentity overwrites any union data inside the ClientAndMaybeIdentity as the provided Identity
+func (t *ClientAndMaybeIdentity) FromIdentity(v Identity) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeIdentity performs a merge with any union data inside the ClientAndMaybeIdentity, using the provided Identity
+func (t *ClientAndMaybeIdentity) MergeIdentity(v Identity) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t ClientAndMaybeIdentity) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *ClientAndMaybeIdentity) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// AsClient returns the union data inside the ClientOrIdentity as a Client
+func (t ClientOrIdentity) AsClient() (Client, error) {
+ var body Client
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromClient overwrites any union data inside the ClientOrIdentity as the provided Client
+func (t *ClientOrIdentity) FromClient(v Client) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeClient performs a merge with any union data inside the ClientOrIdentity, using the provided Client
+func (t *ClientOrIdentity) MergeClient(v Client) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsIdentity returns the union data inside the ClientOrIdentity as a Identity
+func (t ClientOrIdentity) AsIdentity() (Identity, error) {
+ var body Identity
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromIdentity overwrites any union data inside the ClientOrIdentity as the provided Identity
+func (t *ClientOrIdentity) FromIdentity(v Identity) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeIdentity performs a merge with any union data inside the ClientOrIdentity, using the provided Identity
+func (t *ClientOrIdentity) MergeIdentity(v Identity) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t ClientOrIdentity) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *ClientOrIdentity) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
diff --git a/examples/anyof-allof-oneof/api.yaml b/examples/anyof-allof-oneof/api.yaml
new file mode 100644
index 0000000000..61c6a494f1
--- /dev/null
+++ b/examples/anyof-allof-oneof/api.yaml
@@ -0,0 +1,64 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Using complex schemas
+ description: An example of `anyOf`, `allOf` and `oneOf`
+components:
+ schemas:
+ # base types
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ Identity:
+ type: object
+ required:
+ - issuer
+ properties:
+ issuer:
+ type: string
+
+ # allOf performs a union of all types defined
+ ClientWithId:
+ allOf:
+ - $ref: '#/components/schemas/Client'
+ - properties:
+ id:
+ type: integer
+ required:
+ - id
+
+ # allOf performs a union of all types defined, but if there's a duplicate field defined, it'll be overwritten by the last schema
+ # https://github.com/oapi-codegen/oapi-codegen/issues/1569
+ IdentityWithDuplicateField:
+ allOf:
+ # `issuer` will be ignored
+ - $ref: '#/components/schemas/Identity'
+ # `issuer` will be ignored
+ - properties:
+ issuer:
+ type: integer
+ # `issuer` will take precedence
+ - properties:
+ issuer:
+ type: object
+ properties:
+ name:
+ type: string
+ required:
+ - name
+
+ # anyOf results in a type that has an `AsClient`/`MergeClient`/`FromClient` and an `AsIdentity`/`MergeIdentity`/`FromIdentity` method so you can choose which of them you want to retrieve
+ ClientAndMaybeIdentity:
+ anyOf:
+ - $ref: '#/components/schemas/Client'
+ - $ref: '#/components/schemas/Identity'
+
+ # oneOf results in a type that has an `AsClient`/`MergeClient`/`FromClient` and an `AsIdentity`/`MergeIdentity`/`FromIdentity` method so you can choose which of them you want to retrieve
+ ClientOrIdentity:
+ oneOf:
+ - $ref: '#/components/schemas/Client'
+ - $ref: '#/components/schemas/Identity'
diff --git a/examples/anyof-allof-oneof/cfg.yaml b/examples/anyof-allof-oneof/cfg.yaml
new file mode 100644
index 0000000000..6db7862270
--- /dev/null
+++ b/examples/anyof-allof-oneof/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../configuration-schema.json
+package: anyofallofoneof
+output: anyofallofoneof.gen.go
+generate:
+ models: true
+output-options:
+ # NOTE that this is only required for the `Unreferenced` type
+ skip-prune: true
diff --git a/examples/anyof-allof-oneof/generate.go b/examples/anyof-allof-oneof/generate.go
new file mode 100644
index 0000000000..9e993e2b9f
--- /dev/null
+++ b/examples/anyof-allof-oneof/generate.go
@@ -0,0 +1,3 @@
+package anyofallofoneof
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/authenticated-api/echo/api/api.gen.go b/examples/authenticated-api/echo/api/api.gen.go
index 13dc44b3ad..e3c5d2591a 100644
--- a/examples/authenticated-api/echo/api/api.gen.go
+++ b/examples/authenticated-api/echo/api/api.gen.go
@@ -1,11 +1,11 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -21,7 +21,7 @@ import (
)
const (
- BearerAuthScopes = "BearerAuth.Scopes"
+ BearerAuthScopes bearerAuthContextKey = "BearerAuth.Scopes"
)
// Error defines model for Error.
@@ -44,6 +44,9 @@ type ThingWithID struct {
Name string `json:"name"`
}
+// bearerAuthContextKey is the context key for BearerAuth security scheme
+type bearerAuthContextKey string
+
// AddThingJSONRequestBody defines body for AddThing for application/json ContentType.
type AddThingJSONRequestBody = Thing
@@ -184,7 +187,7 @@ func NewListThingsRequest(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -222,7 +225,7 @@ func NewAddThingRequestWithBody(server string, contentType string, body io.Reade
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -290,6 +293,16 @@ type ListThingsResponse struct {
JSON200 *[]ThingWithID
}
+// GetJSON200 returns JSON200
+func (r ListThingsResponse) GetJSON200() *[]ThingWithID {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r ListThingsResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r ListThingsResponse) Status() string {
if r.HTTPResponse != nil {
@@ -306,12 +319,30 @@ func (r ListThingsResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r ListThingsResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type AddThingResponse struct {
Body []byte
HTTPResponse *http.Response
JSON201 *[]ThingWithID
}
+// GetJSON201 returns JSON201
+func (r AddThingResponse) GetJSON201() *[]ThingWithID {
+ return r.JSON201
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r AddThingResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r AddThingResponse) Status() string {
if r.HTTPResponse != nil {
@@ -328,6 +359,14 @@ func (r AddThingResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r AddThingResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// ListThingsWithResponse request returning *ListThingsResponse
func (c *ClientWithResponses) ListThingsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListThingsResponse, error) {
rsp, err := c.ListThings(ctx, reqEditors...)
@@ -425,7 +464,7 @@ type ServerInterfaceWrapper struct {
func (w *ServerInterfaceWrapper) ListThings(ctx echo.Context) error {
var err error
- ctx.Set(BearerAuthScopes, []string{})
+ ctx.Set(string(BearerAuthScopes), []string{})
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.ListThings(ctx)
@@ -436,7 +475,7 @@ func (w *ServerInterfaceWrapper) ListThings(ctx echo.Context) error {
func (w *ServerInterfaceWrapper) AddThing(ctx echo.Context) error {
var err error
- ctx.Set(BearerAuthScopes, []string{"things:w"})
+ ctx.Set(string(BearerAuthScopes), []string{"things:w"})
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.AddThing(ctx)
@@ -458,55 +497,76 @@ type EchoRouter interface {
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
}
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
- router.GET(baseURL+"/things", wrapper.ListThings)
- router.POST(baseURL+"/things", wrapper.AddThing)
+ router.GET(options.BaseURL+"/things", wrapper.ListThings, options.OperationMiddlewares["listThings"]...)
+ router.POST(options.BaseURL+"/things", wrapper.AddThing, options.OperationMiddlewares["addThing"]...)
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/8RUwW7bOBD9lcHsAnsRbCdZ7EE3B8kCDgq0aA3kEAcII44ttjLJDEdxjUD/XpCUHDVO",
- "0/bUiy2Swzfz3rzhE1Zu650lKwHLJwxVTVuVPi+ZHccPz84Ti6G0XTlN8V9TqNh4Mc5imYMhnRW4drxV",
- "giUaK2enWKDsPeUlbYixK3BLIajND4GG48PVIGzsBruuQKaH1jBpLG+wTziE33YFLusYeFS2VduU7W28",
- "FHVAuTZSLy7iLdU079dY3jzh30xrLPGv6bNu0160aU7dFS9zGx1/x6r89+8rqryoxWi87W7jbqCqZSP7",
- "TzFPhjwnxcTzVuq4uk+r/4cEV9dLLHIrY4J8+pywFvHYRWBj1+64BXML9FVtfUMw/7CAXW2qGtpAATIS",
- "iPtCFkLlPAVQVsPV9RJUrKVAMdLEJLE0smIqJaQTzmXGxAIfiUNOdTKZTWbRD86TVd5giWdpq0CvpE5U",
- "pxJlTZ8bkuNyP5K0bAMoaEwQcGvIFyZwTpVqA8V1ALLaO2MFtKNg/xFwj8RsdDymld007l41MEhdgBHo",
- "uxGhI8O148Syp2Wcnawspto5LRcaS3xngixzxbGfwTsbcs9OZ7M8QFbIJiLK+6aHmn4Okc0wgck2Qtt0",
- "8aee643aHVqsmNU+9/h7sV6KlGO8C68IO9c6Uk+BIC7qdCTxcixtOGgaUnDWdGUHUSFbMllmpO1dBit3",
- "d9lTYCw41slo4Inj4IBa2R0bodckn2udRy8PEAU5d3r/W1r/wlgfizl/1sbYQCwTGMwY6ec90n3UzkgN",
- "ysLiAseDLtxSd+SUkz/ulOWYwXLEAFprHlqKPMaPU3odx8/SDQ59ze/Ym7Ex4lsAAAD//9UBNUSMBgAA",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "xFTBbts4EP2VwewCexFsJ1nsQTcHyQIOCrRoDeQQBwgjji22MskMR3GNQP9ekJQcNU7T9tSLLZLDN/Pe",
+ "vOETVm7rnSUrAcsnDFVNW5U+L5kdxw/PzhOLobRdOU3xX1Oo2HgxzmKZgyGdFbh2vFWCJRorZ6dYoOw9",
+ "5SVtiLErcEshqM0PgYbjw9UgbOwGu65ApofWMGksb7BPOITfdgUu6xh4VLZV25TtbbwUdUC5NlIvLuIt",
+ "1TTv11jePOHfTGss8a/ps27TXrRpTt0VL3MbHX/Hqvz37yuqvKjFaLztbuNuoKplI/tPMU+GPCfFxPNW",
+ "6ri6T6v/hwRX10sscitjgnz6nLAW8dhFYGPX7rgFcwv0VW19QzD/sIBdbaoa2kABMhKI+0IWQuU8BVBW",
+ "w9X1ElSspUAx0sQksTSyYiolpBPOZcbEAh+JQ051MplNZtEPzpNV3mCJZ2mrQK+kTlSnEmVNnxuS43I/",
+ "krRsAyhoTBBwa8gXJnBOlWoDxXUAsto7YwW0o2D/EXCPxGx0PKaV3TTuXjUwSF2AEei7EaEjw7XjxLKn",
+ "ZZydrCym2jktFxpLfGeCLHPFsZ/BOxtyz05nszxAVsgmIsr7poeafg6RzTCByTZC23Txp57rjdodWqyY",
+ "1T73+HuxXoqUY7wLrwg71zpST4EgLup0JPFyLG04aBpScNZ0ZQdRIVsyWWak7V0GK3d32VNgLDjWyWjg",
+ "iePggFrZHRuh1ySfa51HLw8QBTl3ev9bWv/CWB+LOX/WxthALBMYzBjp5z3SfdTOSA3KwuICx4Mu3FJ3",
+ "5JSTP+6U5ZjBcsQAWmseWoo8xo9Teh3Hz9INDn3N79ibsTHiWwAAAP//",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -514,7 +574,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -532,12 +592,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -563,3 +623,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/examples/authenticated-api/echo/api/config.yaml b/examples/authenticated-api/echo/api/config.yaml
index 0b176ca618..0893383bc2 100644
--- a/examples/authenticated-api/echo/api/config.yaml
+++ b/examples/authenticated-api/echo/api/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
echo-server: true
diff --git a/examples/authenticated-api/echo/api/doc.go b/examples/authenticated-api/echo/api/doc.go
index 51a3a8292d..e6d8f45d97 100644
--- a/examples/authenticated-api/echo/api/doc.go
+++ b/examples/authenticated-api/echo/api/doc.go
@@ -1,3 +1,3 @@
package api
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml ../../api.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../../api.yaml
diff --git a/examples/authenticated-api/echo/main.go b/examples/authenticated-api/echo/main.go
index d28c28803d..dc4b42c45a 100644
--- a/examples/authenticated-api/echo/main.go
+++ b/examples/authenticated-api/echo/main.go
@@ -5,10 +5,9 @@ import (
"log"
"net"
- "github.com/deepmap/oapi-codegen/examples/authenticated-api/echo/api"
- "github.com/deepmap/oapi-codegen/examples/authenticated-api/echo/server"
"github.com/labstack/echo/v4"
- "github.com/labstack/echo/v4/middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/authenticated-api/echo/api"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/authenticated-api/echo/server"
)
func main() {
@@ -28,7 +27,6 @@ func main() {
if err != nil {
log.Fatalln("error creating middleware:", err)
}
- e.Use(middleware.Logger())
e.Use(mw...)
svr := server.NewServer()
diff --git a/examples/authenticated-api/echo/server/fake_jws.go b/examples/authenticated-api/echo/server/fake_jws.go
index 0cf44e0d90..ce18dded1a 100644
--- a/examples/authenticated-api/echo/server/fake_jws.go
+++ b/examples/authenticated-api/echo/server/fake_jws.go
@@ -4,16 +4,17 @@ import (
"crypto/ecdsa"
"fmt"
- "github.com/deepmap/oapi-codegen/pkg/ecdsafile"
- "github.com/lestrrat-go/jwx/jwa"
- "github.com/lestrrat-go/jwx/jwk"
- "github.com/lestrrat-go/jwx/jws"
- "github.com/lestrrat-go/jwx/jwt"
+ "github.com/lestrrat-go/jwx/v3/jwa"
+ "github.com/lestrrat-go/jwx/v3/jwk"
+ "github.com/lestrrat-go/jwx/v3/jws"
+ "github.com/lestrrat-go/jwx/v3/jwt"
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/ecdsafile"
)
// PrivateKey is an ECDSA private key which was generated with the following
// command:
-// openssl ecparam -name prime256v1 -genkey -noout -out ecprivatekey.pem
+//
+// openssl ecparam -name prime256v1 -genkey -noout -out ecprivatekey.pem
//
// We are using a hard coded key here in this example, but in real applications,
// you would never do this. Your JWT signing key must never be in your application,
@@ -45,14 +46,12 @@ func NewFakeAuthenticator() (*FakeAuthenticator, error) {
}
set := jwk.NewSet()
- pubKey := jwk.NewECDSAPublicKey()
-
- err = pubKey.FromRaw(&privKey.PublicKey)
+ pubKey, err := jwk.Import(&privKey.PublicKey)
if err != nil {
return nil, fmt.Errorf("parsing jwk key: %w", err)
}
- err = pubKey.Set(jwk.AlgorithmKey, jwa.ES256)
+ err = pubKey.Set(jwk.AlgorithmKey, jwa.ES256())
if err != nil {
return nil, fmt.Errorf("setting key algorithm: %w", err)
}
@@ -62,7 +61,10 @@ func NewFakeAuthenticator() (*FakeAuthenticator, error) {
return nil, fmt.Errorf("setting key ID: %w", err)
}
- set.Add(pubKey)
+ err = set.AddKey(pubKey)
+ if err != nil {
+ return nil, fmt.Errorf("adding public key to key set: %w", err)
+ }
return &FakeAuthenticator{PrivateKey: privKey, KeySet: set}, nil
}
@@ -77,7 +79,7 @@ func (f *FakeAuthenticator) ValidateJWS(jwsString string) (jwt.Token, error) {
// SignToken takes a JWT and signs it with our private key, returning a JWS.
func (f *FakeAuthenticator) SignToken(t jwt.Token) ([]byte, error) {
hdr := jws.NewHeaders()
- if err := hdr.Set(jws.AlgorithmKey, jwa.ES256); err != nil {
+ if err := hdr.Set(jws.AlgorithmKey, jwa.ES256()); err != nil {
return nil, fmt.Errorf("setting algorithm: %w", err)
}
if err := hdr.Set(jws.TypeKey, "JWT"); err != nil {
@@ -86,7 +88,7 @@ func (f *FakeAuthenticator) SignToken(t jwt.Token) ([]byte, error) {
if err := hdr.Set(jws.KeyIDKey, KeyID); err != nil {
return nil, fmt.Errorf("setting Key ID: %w", err)
}
- return jwt.Sign(t, jwa.ES256, f.PrivateKey, jwt.WithHeaders(hdr))
+ return jwt.Sign(t, jwt.WithKey(jwa.ES256(), f.PrivateKey, jws.WithProtectedHeaders(hdr)))
}
// CreateJWSWithClaims is a helper function to create JWT's with the specified
diff --git a/examples/authenticated-api/echo/server/jwt_authenticator.go b/examples/authenticated-api/echo/server/jwt_authenticator.go
index 2638a0f5f2..ec11a2245b 100644
--- a/examples/authenticated-api/echo/server/jwt_authenticator.go
+++ b/examples/authenticated-api/echo/server/jwt_authenticator.go
@@ -8,7 +8,7 @@ import (
"strings"
"github.com/getkin/kin-openapi/openapi3filter"
- "github.com/lestrrat-go/jwx/jwt"
+ "github.com/lestrrat-go/jwx/v3/jwt"
middleware "github.com/oapi-codegen/echo-middleware"
)
@@ -21,9 +21,9 @@ type JWSValidator interface {
const JWTClaimsContextKey = "jwt_claims"
var (
- ErrNoAuthHeader = errors.New("Authorization header is missing")
- ErrInvalidAuthHeader = errors.New("Authorization header is malformed")
- ErrClaimsInvalid = errors.New("Provided claims do not match expected scopes")
+ ErrNoAuthHeader = errors.New("authorization header is missing")
+ ErrInvalidAuthHeader = errors.New("authorization header is malformed")
+ ErrClaimsInvalid = errors.New("provided claims do not match expected scopes")
)
// GetJWSFromRequest extracts a JWS string from an Authorization: Bearer header
@@ -89,30 +89,27 @@ func Authenticate(v JWSValidator, ctx context.Context, input *openapi3filter.Aut
// as a list under the "perms" claim, short for permissions, to keep the token
// shorter.
func GetClaimsFromToken(t jwt.Token) ([]string, error) {
- rawPerms, found := t.Get(PermissionsClaim)
- if !found {
+ if !t.Has(PermissionsClaim) {
// If the perms aren't found, it means that the token has none, but it has
// passed signature validation by now, so it's a valid token, so we return
// the empty list.
return make([]string, 0), nil
}
- // rawPerms will be an untyped JSON list, so we need to convert it to
- // a string list.
- rawList, ok := rawPerms.([]interface{})
- if !ok {
- return nil, fmt.Errorf("'%s' claim is unexpected type'", PermissionsClaim)
+ var rawList []interface{}
+ if err := t.Get(PermissionsClaim, &rawList); err != nil {
+ return nil, fmt.Errorf("getting %q claim: %w", PermissionsClaim, err)
}
claims := make([]string, len(rawList))
-
for i, rawClaim := range rawList {
- var ok bool
- claims[i], ok = rawClaim.(string)
+ claim, ok := rawClaim.(string)
if !ok {
return nil, fmt.Errorf("%s[%d] is not a string", PermissionsClaim, i)
}
+ claims[i] = claim
}
+
return claims, nil
}
diff --git a/examples/authenticated-api/echo/server/server.go b/examples/authenticated-api/echo/server/server.go
index caa87e8c09..fbd9bd1598 100644
--- a/examples/authenticated-api/echo/server/server.go
+++ b/examples/authenticated-api/echo/server/server.go
@@ -6,10 +6,10 @@ import (
"sort"
"sync"
- "github.com/deepmap/oapi-codegen/examples/authenticated-api/echo/api"
"github.com/getkin/kin-openapi/openapi3filter"
"github.com/labstack/echo/v4"
middleware "github.com/oapi-codegen/echo-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/authenticated-api/echo/api"
)
type server struct {
@@ -26,7 +26,7 @@ func NewServer() *server {
}
func CreateMiddleware(v JWSValidator) ([]echo.MiddlewareFunc, error) {
- spec, err := api.GetSwagger()
+ spec, err := api.GetSpec()
if err != nil {
return nil, fmt.Errorf("loading spec: %w", err)
}
diff --git a/examples/authenticated-api/echo/server/server_test.go b/examples/authenticated-api/echo/server/server_test.go
index 21366f54bb..5891c71717 100644
--- a/examples/authenticated-api/echo/server/server_test.go
+++ b/examples/authenticated-api/echo/server/server_test.go
@@ -4,9 +4,9 @@ import (
"net/http"
"testing"
- "github.com/deepmap/oapi-codegen/examples/authenticated-api/echo/api"
- "github.com/deepmap/oapi-codegen/pkg/testutil"
"github.com/labstack/echo/v4"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/authenticated-api/echo/api"
+ "github.com/oapi-codegen/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -34,21 +34,21 @@ func TestAPI(t *testing.T) {
t.Logf("writer jwt: %s", string(writerJWT))
// ListPets should return 403 forbidden without credentials
- response := testutil.NewRequest().Get("/things").Go(t, e)
+ response := testutil.NewRequest().Get("/things").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusForbidden, response.Code())
// Using the writer JWT should allow us to insert a thing.
response = testutil.NewRequest().Post("/things").
WithJWSAuth(string(writerJWT)).
WithAcceptJson().
- WithJsonBody(api.Thing{Name: "Thing 1"}).Go(t, e)
+ WithJsonBody(api.Thing{Name: "Thing 1"}).GoWithHTTPHandler(t, e)
require.Equal(t, http.StatusCreated, response.Code())
// Using the reader JWT should forbid inserting a thing.
response = testutil.NewRequest().Post("/things").
WithJWSAuth(string(readerJWT)).
WithAcceptJson().
- WithJsonBody(api.Thing{Name: "Thing 2"}).Go(t, e)
+ WithJsonBody(api.Thing{Name: "Thing 2"}).GoWithHTTPHandler(t, e)
require.Equal(t, http.StatusForbidden, response.Code())
// Both JWT's should allow reading the list of things.
@@ -56,7 +56,7 @@ func TestAPI(t *testing.T) {
for _, jwt := range jwts {
response := testutil.NewRequest().Get("/things").
WithJWSAuth(jwt).
- WithAcceptJson().Go(t, e)
+ WithAcceptJson().GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, response.Code())
}
}
diff --git a/examples/authenticated-api/stdhttp/api/api.gen.go b/examples/authenticated-api/stdhttp/api/api.gen.go
new file mode 100644
index 0000000000..979cd32020
--- /dev/null
+++ b/examples/authenticated-api/stdhttp/api/api.gen.go
@@ -0,0 +1,741 @@
+//go:build go1.22
+
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+)
+
+const (
+ BearerAuthScopes bearerAuthContextKey = "BearerAuth.Scopes"
+)
+
+// Error defines model for Error.
+type Error struct {
+ // Code Error code
+ Code int32 `json:"code"`
+
+ // Message Error message
+ Message string `json:"message"`
+}
+
+// Thing defines model for Thing.
+type Thing struct {
+ Name string `json:"name"`
+}
+
+// ThingWithID defines model for ThingWithID.
+type ThingWithID struct {
+ Id int64 `json:"id"`
+ Name string `json:"name"`
+}
+
+// bearerAuthContextKey is the context key for BearerAuth security scheme
+type bearerAuthContextKey string
+
+// AddThingJSONRequestBody defines body for AddThing for application/json ContentType.
+type AddThingJSONRequestBody = Thing
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // ListThings request
+ ListThings(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // AddThingWithBody request with any body
+ AddThingWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ AddThing(ctx context.Context, body AddThingJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) ListThings(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewListThingsRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) AddThingWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewAddThingRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) AddThing(ctx context.Context, body AddThingJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewAddThingRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewListThingsRequest generates requests for ListThings
+func NewListThingsRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/things")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewAddThingRequest calls the generic AddThing builder with application/json body
+func NewAddThingRequest(server string, body AddThingJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewAddThingRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewAddThingRequestWithBody generates requests for AddThing with any type of body
+func NewAddThingRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/things")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // ListThingsWithResponse request
+ ListThingsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListThingsResponse, error)
+
+ // AddThingWithBodyWithResponse request with any body
+ AddThingWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*AddThingResponse, error)
+
+ AddThingWithResponse(ctx context.Context, body AddThingJSONRequestBody, reqEditors ...RequestEditorFn) (*AddThingResponse, error)
+}
+
+type ListThingsResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *[]ThingWithID
+}
+
+// GetJSON200 returns JSON200
+func (r ListThingsResponse) GetJSON200() *[]ThingWithID {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r ListThingsResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r ListThingsResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r ListThingsResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r ListThingsResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type AddThingResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON201 *[]ThingWithID
+}
+
+// GetJSON201 returns JSON201
+func (r AddThingResponse) GetJSON201() *[]ThingWithID {
+ return r.JSON201
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r AddThingResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r AddThingResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r AddThingResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r AddThingResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// ListThingsWithResponse request returning *ListThingsResponse
+func (c *ClientWithResponses) ListThingsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListThingsResponse, error) {
+ rsp, err := c.ListThings(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseListThingsResponse(rsp)
+}
+
+// AddThingWithBodyWithResponse request with arbitrary body returning *AddThingResponse
+func (c *ClientWithResponses) AddThingWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*AddThingResponse, error) {
+ rsp, err := c.AddThingWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseAddThingResponse(rsp)
+}
+
+func (c *ClientWithResponses) AddThingWithResponse(ctx context.Context, body AddThingJSONRequestBody, reqEditors ...RequestEditorFn) (*AddThingResponse, error) {
+ rsp, err := c.AddThing(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseAddThingResponse(rsp)
+}
+
+// ParseListThingsResponse parses an HTTP response from a ListThingsWithResponse call
+func ParseListThingsResponse(rsp *http.Response) (*ListThingsResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &ListThingsResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest []ThingWithID
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseAddThingResponse parses an HTTP response from a AddThingWithResponse call
+func ParseAddThingResponse(rsp *http.Response) (*AddThingResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &AddThingResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 201:
+ var dest []ThingWithID
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON201 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /things)
+ ListThings(w http.ResponseWriter, r *http.Request)
+
+ // (POST /things)
+ AddThing(w http.ResponseWriter, r *http.Request)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// ListThings operation middleware
+func (siw *ServerInterfaceWrapper) ListThings(w http.ResponseWriter, r *http.Request) {
+
+ ctx := r.Context()
+
+ ctx = context.WithValue(ctx, BearerAuthScopes, []string{})
+
+ r = r.WithContext(ctx)
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.ListThings(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// AddThing operation middleware
+func (siw *ServerInterfaceWrapper) AddThing(w http.ResponseWriter, r *http.Request) {
+
+ ctx := r.Context()
+
+ ctx = context.WithValue(ctx, BearerAuthScopes, []string{"things:w"})
+
+ r = r.WithContext(ctx)
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.AddThing(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{})
+}
+
+// ServeMux is an abstraction of [http.ServeMux].
+type ServeMux interface {
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+ http.Handler
+}
+
+type StdHTTPServerOptions struct {
+ BaseURL string
+ BaseRouter ServeMux
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/things", wrapper.ListThings)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/things", wrapper.AddThing)
+
+ return m
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "xFTBbts4EP2VwewCexFsJ1nsQTcHyQIOCrRoDeQQBwgjji22MskMR3GNQP9ekJQcNU7T9tSLLZLDN/Pe",
+ "vOETVm7rnSUrAcsnDFVNW5U+L5kdxw/PzhOLobRdOU3xX1Oo2HgxzmKZgyGdFbh2vFWCJRorZ6dYoOw9",
+ "5SVtiLErcEshqM0PgYbjw9UgbOwGu65ApofWMGksb7BPOITfdgUu6xh4VLZV25TtbbwUdUC5NlIvLuIt",
+ "1TTv11jePOHfTGss8a/ps27TXrRpTt0VL3MbHX/Hqvz37yuqvKjFaLztbuNuoKplI/tPMU+GPCfFxPNW",
+ "6ri6T6v/hwRX10sscitjgnz6nLAW8dhFYGPX7rgFcwv0VW19QzD/sIBdbaoa2kABMhKI+0IWQuU8BVBW",
+ "w9X1ElSspUAx0sQksTSyYiolpBPOZcbEAh+JQ051MplNZtEPzpNV3mCJZ2mrQK+kTlSnEmVNnxuS43I/",
+ "krRsAyhoTBBwa8gXJnBOlWoDxXUAsto7YwW0o2D/EXCPxGx0PKaV3TTuXjUwSF2AEei7EaEjw7XjxLKn",
+ "ZZydrCym2jktFxpLfGeCLHPFsZ/BOxtyz05nszxAVsgmIsr7poeafg6RzTCByTZC23Txp57rjdodWqyY",
+ "1T73+HuxXoqUY7wLrwg71zpST4EgLup0JPFyLG04aBpScNZ0ZQdRIVsyWWak7V0GK3d32VNgLDjWyWjg",
+ "iePggFrZHRuh1ySfa51HLw8QBTl3ev9bWv/CWB+LOX/WxthALBMYzBjp5z3SfdTOSA3KwuICx4Mu3FJ3",
+ "5JSTP+6U5ZjBcsQAWmseWoo8xo9Teh3Hz9INDn3N79ibsTHiWwAAAP//",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/examples/authenticated-api/stdhttp/api/config.yaml b/examples/authenticated-api/stdhttp/api/config.yaml
new file mode 100644
index 0000000000..9cbde4b66f
--- /dev/null
+++ b/examples/authenticated-api/stdhttp/api/config.yaml
@@ -0,0 +1,10 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: api
+generate:
+ std-http-server: true
+ client: true
+ models: true
+ embedded-spec: true
+output: api.gen.go
+output-options:
+ skip-prune: true
diff --git a/examples/authenticated-api/stdhttp/api/doc.go b/examples/authenticated-api/stdhttp/api/doc.go
new file mode 100644
index 0000000000..e6d8f45d97
--- /dev/null
+++ b/examples/authenticated-api/stdhttp/api/doc.go
@@ -0,0 +1,3 @@
+package api
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../../api.yaml
diff --git a/examples/authenticated-api/stdhttp/main.go b/examples/authenticated-api/stdhttp/main.go
new file mode 100644
index 0000000000..73d330aac4
--- /dev/null
+++ b/examples/authenticated-api/stdhttp/main.go
@@ -0,0 +1,57 @@
+package main
+
+import (
+ "flag"
+ "log"
+ "net/http"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/authenticated-api/stdhttp/api"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/authenticated-api/stdhttp/server"
+)
+
+func main() {
+ port := flag.String("port", "8080", "port where to serve traffic")
+
+ r := http.NewServeMux()
+
+ // Create a fake authenticator. This allows us to issue tokens, and also
+ // implements a validator to check their validity.
+ fa, err := server.NewFakeAuthenticator()
+ if err != nil {
+ log.Fatalln("error creating authenticator:", err)
+ }
+
+ // Create middleware for validating tokens.
+ mw, err := server.CreateMiddleware(fa)
+ if err != nil {
+ log.Fatalln("error creating middleware:", err)
+ }
+
+ svr := server.NewServer()
+
+ h := api.HandlerFromMux(svr, r)
+ // wrap the existing handler with our global middleware
+ h = mw(h)
+
+ // We're going to print some useful things for interacting with this server.
+ // This token allows access to any API's with no specific claims.
+ readerJWS, err := fa.CreateJWSWithClaims([]string{})
+ if err != nil {
+ log.Fatalln("error creating reader JWS:", err)
+ }
+ // This token allows access to API's with no scopes, and with the "things:w" claim.
+ writerJWS, err := fa.CreateJWSWithClaims([]string{"things:w"})
+ if err != nil {
+ log.Fatalln("error creating writer JWS:", err)
+ }
+
+ log.Println("Reader token", string(readerJWS))
+ log.Println("Writer token", string(writerJWS))
+
+ s := &http.Server{
+ Handler: h,
+ Addr: "0.0.0.0:" + *port,
+ }
+
+ log.Fatal(s.ListenAndServe())
+}
diff --git a/examples/authenticated-api/stdhttp/server/fake_jws.go b/examples/authenticated-api/stdhttp/server/fake_jws.go
new file mode 100644
index 0000000000..ce18dded1a
--- /dev/null
+++ b/examples/authenticated-api/stdhttp/server/fake_jws.go
@@ -0,0 +1,111 @@
+package server
+
+import (
+ "crypto/ecdsa"
+ "fmt"
+
+ "github.com/lestrrat-go/jwx/v3/jwa"
+ "github.com/lestrrat-go/jwx/v3/jwk"
+ "github.com/lestrrat-go/jwx/v3/jws"
+ "github.com/lestrrat-go/jwx/v3/jwt"
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/ecdsafile"
+)
+
+// PrivateKey is an ECDSA private key which was generated with the following
+// command:
+//
+// openssl ecparam -name prime256v1 -genkey -noout -out ecprivatekey.pem
+//
+// We are using a hard coded key here in this example, but in real applications,
+// you would never do this. Your JWT signing key must never be in your application,
+// only the public key.
+const PrivateKey = `-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIN2dALnjdcZaIZg4QuA6Dw+kxiSW502kJfmBN3priIhPoAoGCCqGSM49
+AwEHoUQDQgAE4pPyvrB9ghqkT1Llk0A42lixkugFd/TBdOp6wf69O9Nndnp4+HcR
+s9SlG/8hjB2Hz42v4p3haKWv3uS1C6ahCQ==
+-----END EC PRIVATE KEY-----`
+
+const KeyID = `fake-key-id`
+const FakeIssuer = "fake-issuer"
+const FakeAudience = "example-users"
+const PermissionsClaim = "perm"
+
+type FakeAuthenticator struct {
+ PrivateKey *ecdsa.PrivateKey
+ KeySet jwk.Set
+}
+
+var _ JWSValidator = (*FakeAuthenticator)(nil)
+
+// NewFakeAuthenticator creates an authenticator example which uses a hard coded
+// ECDSA key to validate JWT's that it has signed itself.
+func NewFakeAuthenticator() (*FakeAuthenticator, error) {
+ privKey, err := ecdsafile.LoadEcdsaPrivateKey([]byte(PrivateKey))
+ if err != nil {
+ return nil, fmt.Errorf("loading PEM private key: %w", err)
+ }
+
+ set := jwk.NewSet()
+ pubKey, err := jwk.Import(&privKey.PublicKey)
+ if err != nil {
+ return nil, fmt.Errorf("parsing jwk key: %w", err)
+ }
+
+ err = pubKey.Set(jwk.AlgorithmKey, jwa.ES256())
+ if err != nil {
+ return nil, fmt.Errorf("setting key algorithm: %w", err)
+ }
+
+ err = pubKey.Set(jwk.KeyIDKey, KeyID)
+ if err != nil {
+ return nil, fmt.Errorf("setting key ID: %w", err)
+ }
+
+ err = set.AddKey(pubKey)
+ if err != nil {
+ return nil, fmt.Errorf("adding public key to key set: %w", err)
+ }
+
+ return &FakeAuthenticator{PrivateKey: privKey, KeySet: set}, nil
+}
+
+// ValidateJWS ensures that the critical JWT claims needed to ensure that we
+// trust the JWT are present and with the correct values.
+func (f *FakeAuthenticator) ValidateJWS(jwsString string) (jwt.Token, error) {
+ return jwt.Parse([]byte(jwsString), jwt.WithKeySet(f.KeySet),
+ jwt.WithAudience(FakeAudience), jwt.WithIssuer(FakeIssuer))
+}
+
+// SignToken takes a JWT and signs it with our private key, returning a JWS.
+func (f *FakeAuthenticator) SignToken(t jwt.Token) ([]byte, error) {
+ hdr := jws.NewHeaders()
+ if err := hdr.Set(jws.AlgorithmKey, jwa.ES256()); err != nil {
+ return nil, fmt.Errorf("setting algorithm: %w", err)
+ }
+ if err := hdr.Set(jws.TypeKey, "JWT"); err != nil {
+ return nil, fmt.Errorf("setting type: %w", err)
+ }
+ if err := hdr.Set(jws.KeyIDKey, KeyID); err != nil {
+ return nil, fmt.Errorf("setting Key ID: %w", err)
+ }
+ return jwt.Sign(t, jwt.WithKey(jwa.ES256(), f.PrivateKey, jws.WithProtectedHeaders(hdr)))
+}
+
+// CreateJWSWithClaims is a helper function to create JWT's with the specified
+// claims.
+func (f *FakeAuthenticator) CreateJWSWithClaims(claims []string) ([]byte, error) {
+ t := jwt.New()
+ err := t.Set(jwt.IssuerKey, FakeIssuer)
+ if err != nil {
+ return nil, fmt.Errorf("setting issuer: %w", err)
+ }
+ err = t.Set(jwt.AudienceKey, FakeAudience)
+ if err != nil {
+ return nil, fmt.Errorf("setting audience: %w", err)
+ }
+ err = t.Set(PermissionsClaim, claims)
+ if err != nil {
+ return nil, fmt.Errorf("setting permissions: %w", err)
+ }
+ return f.SignToken(t)
+}
diff --git a/examples/authenticated-api/stdhttp/server/jwt_authenticator.go b/examples/authenticated-api/stdhttp/server/jwt_authenticator.go
new file mode 100644
index 0000000000..163827e24b
--- /dev/null
+++ b/examples/authenticated-api/stdhttp/server/jwt_authenticator.go
@@ -0,0 +1,132 @@
+package server
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3filter"
+ "github.com/lestrrat-go/jwx/v3/jwt"
+)
+
+// JWSValidator is used to validate JWS payloads and return a JWT if they're
+// valid
+type JWSValidator interface {
+ ValidateJWS(jws string) (jwt.Token, error)
+}
+
+const JWTClaimsContextKey = "jwt_claims"
+
+var (
+ ErrNoAuthHeader = errors.New("authorization header is missing")
+ ErrInvalidAuthHeader = errors.New("authorization header is malformed")
+ ErrClaimsInvalid = errors.New("provided claims do not match expected scopes")
+)
+
+// GetJWSFromRequest extracts a JWS string from an Authorization: Bearer header
+func GetJWSFromRequest(req *http.Request) (string, error) {
+ authHdr := req.Header.Get("Authorization")
+ // Check for the Authorization header.
+ if authHdr == "" {
+ return "", ErrNoAuthHeader
+ }
+ // We expect a header value of the form "Bearer ", with 1 space after
+ // Bearer, per spec.
+ prefix := "Bearer "
+ if !strings.HasPrefix(authHdr, prefix) {
+ return "", ErrInvalidAuthHeader
+ }
+ return strings.TrimPrefix(authHdr, prefix), nil
+}
+
+func NewAuthenticator(v JWSValidator) openapi3filter.AuthenticationFunc {
+ return func(ctx context.Context, input *openapi3filter.AuthenticationInput) error {
+ return Authenticate(v, ctx, input)
+ }
+}
+
+// Authenticate uses the specified validator to ensure a JWT is valid, then makes
+// sure that the claims provided by the JWT match the scopes as required in the API.
+func Authenticate(v JWSValidator, ctx context.Context, input *openapi3filter.AuthenticationInput) error {
+ // Our security scheme is named BearerAuth, ensure this is the case
+ if input.SecuritySchemeName != "BearerAuth" {
+ return fmt.Errorf("security scheme %s != 'BearerAuth'", input.SecuritySchemeName)
+ }
+
+ // Now, we need to get the JWS from the request, to match the request expectations
+ // against request contents.
+ jws, err := GetJWSFromRequest(input.RequestValidationInput.Request)
+ if err != nil {
+ return fmt.Errorf("getting jws: %w", err)
+ }
+
+ // if the JWS is valid, we have a JWT, which will contain a bunch of claims.
+ token, err := v.ValidateJWS(jws)
+ if err != nil {
+ return fmt.Errorf("validating JWS: %w", err)
+ }
+
+ // We've got a valid token now, and we can look into its claims to see whether
+ // they match. Every single scope must be present in the claims.
+ err = CheckTokenClaims(input.Scopes, token)
+
+ if err != nil {
+ return fmt.Errorf("token claims don't match: %w", err)
+ }
+
+ // Set the property on the echo context so the handler is able to
+ // access the claims data we generate in here.
+ // TODO
+ // ctx.Set(JWTClaimsContextKey, token)
+
+ return nil
+}
+
+// GetClaimsFromToken returns a list of claims from the token. We store these
+// as a list under the "perms" claim, short for permissions, to keep the token
+// shorter.
+func GetClaimsFromToken(t jwt.Token) ([]string, error) {
+ if !t.Has(PermissionsClaim) {
+ // If the perms aren't found, it means that the token has none, but it has
+ // passed signature validation by now, so it's a valid token, so we return
+ // the empty list.
+ return make([]string, 0), nil
+ }
+
+ var rawList []interface{}
+ if err := t.Get(PermissionsClaim, &rawList); err != nil {
+ return nil, fmt.Errorf("getting %q claim: %w", PermissionsClaim, err)
+ }
+
+ claims := make([]string, len(rawList))
+ for i, rawClaim := range rawList {
+ claim, ok := rawClaim.(string)
+ if !ok {
+ return nil, fmt.Errorf("%s[%d] is not a string", PermissionsClaim, i)
+ }
+ claims[i] = claim
+ }
+
+ return claims, nil
+}
+
+func CheckTokenClaims(expectedClaims []string, t jwt.Token) error {
+ claims, err := GetClaimsFromToken(t)
+ if err != nil {
+ return fmt.Errorf("getting claims from token: %w", err)
+ }
+ // Put the claims into a map, for quick access.
+ claimsMap := make(map[string]bool, len(claims))
+ for _, c := range claims {
+ claimsMap[c] = true
+ }
+
+ for _, e := range expectedClaims {
+ if !claimsMap[e] {
+ return ErrClaimsInvalid
+ }
+ }
+ return nil
+}
diff --git a/examples/authenticated-api/stdhttp/server/server.go b/examples/authenticated-api/stdhttp/server/server.go
new file mode 100644
index 0000000000..6ed2da28e9
--- /dev/null
+++ b/examples/authenticated-api/stdhttp/server/server.go
@@ -0,0 +1,122 @@
+package server
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "sort"
+ "sync"
+
+ "github.com/getkin/kin-openapi/openapi3filter"
+ middleware "github.com/oapi-codegen/nethttp-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/authenticated-api/stdhttp/api"
+)
+
+type server struct {
+ sync.RWMutex
+ lastID int64
+ things map[int64]api.Thing
+}
+
+func NewServer() *server {
+ return &server{
+ lastID: 0,
+ things: make(map[int64]api.Thing),
+ }
+}
+
+func CreateMiddleware(v JWSValidator) (func(next http.Handler) http.Handler, error) {
+ spec, err := api.GetSpec()
+ if err != nil {
+ return nil, fmt.Errorf("loading spec: %w", err)
+ }
+
+ validator := middleware.OapiRequestValidatorWithOptions(spec,
+ &middleware.Options{
+ Options: openapi3filter.Options{
+ AuthenticationFunc: NewAuthenticator(v),
+ },
+ })
+
+ return validator, nil
+}
+
+// Ensure that we implement the server interface
+var _ api.ServerInterface = (*server)(nil)
+
+func (s *server) ListThings(w http.ResponseWriter, r *http.Request) {
+ // This handler will only be called when a valid JWT is presented for
+ // access.
+ s.RLock()
+
+ thingKeys := make([]int64, 0, len(s.things))
+ for key := range s.things {
+ thingKeys = append(thingKeys, key)
+ }
+ sort.Sort(int64s(thingKeys))
+
+ things := make([]api.ThingWithID, 0, len(s.things))
+
+ for _, key := range thingKeys {
+ thing := s.things[key]
+ things = append(things, api.ThingWithID{
+ Id: key,
+ Name: thing.Name,
+ })
+ }
+
+ s.RUnlock()
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(things)
+}
+
+type int64s []int64
+
+func (in int64s) Len() int {
+ return len(in)
+}
+
+func (in int64s) Less(i, j int) bool {
+ return in[i] < in[j]
+}
+
+func (in int64s) Swap(i, j int) {
+ in[i], in[j] = in[j], in[i]
+}
+
+var _ sort.Interface = (int64s)(nil)
+
+func (s *server) AddThing(w http.ResponseWriter, r *http.Request) {
+ // This handler will only be called when the JWT is valid and the JWT contains
+ // the scopes required.
+ bodyBytes, err := io.ReadAll(r.Body)
+ defer func() { _ = r.Body.Close() }()
+ if err != nil {
+ w.WriteHeader(http.StatusBadRequest)
+ _, _ = w.Write([]byte("could not bind request body"))
+ return
+ }
+
+ var thing api.Thing
+ err = json.Unmarshal(bodyBytes, &thing)
+ if err != nil {
+ w.WriteHeader(http.StatusBadRequest)
+ _, _ = w.Write([]byte("could not bind request body"))
+ return
+ }
+
+ s.Lock()
+ defer s.Unlock()
+
+ s.things[s.lastID] = thing
+ thingWithId := api.ThingWithID{
+ Name: thing.Name,
+ Id: s.lastID,
+ }
+ s.lastID++
+
+ w.WriteHeader(http.StatusCreated)
+ _ = json.NewEncoder(w).Encode(thingWithId)
+}
diff --git a/examples/authenticated-api/stdhttp/server/server_test.go b/examples/authenticated-api/stdhttp/server/server_test.go
new file mode 100644
index 0000000000..cfada646da
--- /dev/null
+++ b/examples/authenticated-api/stdhttp/server/server_test.go
@@ -0,0 +1,63 @@
+package server
+
+import (
+ "net/http"
+ "testing"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/authenticated-api/stdhttp/api"
+ "github.com/oapi-codegen/testutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestAPI(t *testing.T) {
+ r := http.NewServeMux()
+ s := NewServer()
+
+ fa, err := NewFakeAuthenticator()
+ require.NoError(t, err)
+
+ mw, err := CreateMiddleware(fa)
+ require.NoError(t, err)
+
+ h := api.HandlerFromMux(s, r)
+ // wrap the existing handler with our global middleware
+ h = mw(h)
+
+ // Let's create a JWT with no scopes, which allows access to listing things.
+ readerJWT, err := fa.CreateJWSWithClaims([]string{})
+ require.NoError(t, err)
+ t.Logf("reader jwt: %s", string(readerJWT))
+
+ // Now, create a JWT with write permission.
+ writerJWT, err := fa.CreateJWSWithClaims([]string{"things:w"})
+ require.NoError(t, err)
+ t.Logf("writer jwt: %s", string(writerJWT))
+
+ // ListPets should return 401 Unauthorized without credentials
+ response := testutil.NewRequest().Get("/things").GoWithHTTPHandler(t, h)
+ assert.Equal(t, http.StatusUnauthorized, response.Code())
+
+ // Using the writer JWT should allow us to insert a thing.
+ response = testutil.NewRequest().Post("/things").
+ WithJWSAuth(string(writerJWT)).
+ WithAcceptJson().
+ WithJsonBody(api.Thing{Name: "Thing 1"}).GoWithHTTPHandler(t, h)
+ require.Equal(t, http.StatusCreated, response.Code())
+
+ // Using the reader JWT should forbid inserting a thing.
+ response = testutil.NewRequest().Post("/things").
+ WithJWSAuth(string(readerJWT)).
+ WithAcceptJson().
+ WithJsonBody(api.Thing{Name: "Thing 2"}).GoWithHTTPHandler(t, h)
+ require.Equal(t, http.StatusUnauthorized, response.Code())
+
+ // Both JWT's should allow reading the list of things.
+ jwts := []string{string(readerJWT), string(writerJWT)}
+ for _, jwt := range jwts {
+ response := testutil.NewRequest().Get("/things").
+ WithJWSAuth(jwt).
+ WithAcceptJson().GoWithHTTPHandler(t, h)
+ assert.Equal(t, http.StatusOK, response.Code())
+ }
+}
diff --git a/examples/authenticated-api/stdhttp/tools/tools.go b/examples/authenticated-api/stdhttp/tools/tools.go
new file mode 100644
index 0000000000..8615cb4c57
--- /dev/null
+++ b/examples/authenticated-api/stdhttp/tools/tools.go
@@ -0,0 +1,8 @@
+//go:build tools
+// +build tools
+
+package tools
+
+import (
+ _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen"
+)
diff --git a/examples/client/api.yaml b/examples/client/api.yaml
new file mode 100644
index 0000000000..5945b63dd7
--- /dev/null
+++ b/examples/client/api.yaml
@@ -0,0 +1,47 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Generate models
+paths:
+ /client:
+ get:
+ operationId: getClient
+ responses:
+ 200:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ClientType"
+ put:
+ operationId: updateClient
+ responses:
+ 400:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ code:
+ type: string
+ required:
+ - code
+components:
+ schemas:
+ ClientType:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ # NOTE that this is not generated by default because it's not referenced. If you want it, you need to use the following YAML configuration:
+ #
+ # output-options:
+ # skip-prune: true
+ Unreferenced:
+ type: object
+ required:
+ - id
+ properties:
+ id:
+ type: int
diff --git a/examples/client/cfg.yaml b/examples/client/cfg.yaml
new file mode 100644
index 0000000000..d2103b0561
--- /dev/null
+++ b/examples/client/cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../configuration-schema.json
+package: client
+output: client.gen.go
+generate:
+ models: true
+ client: true
diff --git a/examples/client/client.gen.go b/examples/client/client.gen.go
new file mode 100644
index 0000000000..430496de89
--- /dev/null
+++ b/examples/client/client.gen.go
@@ -0,0 +1,383 @@
+// Package client provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package client
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+// ClientType defines model for ClientType.
+type ClientType struct {
+ Name string `json:"name"`
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetClient request
+ GetClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // UpdateClient request
+ UpdateClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetClientRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) UpdateClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewUpdateClientRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetClientRequest generates requests for GetClient
+func NewGetClientRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/client")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewUpdateClientRequest generates requests for UpdateClient
+func NewUpdateClientRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/client")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPut, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetClientWithResponse request
+ GetClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetClientResponse, error)
+
+ // UpdateClientWithResponse request
+ UpdateClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*UpdateClientResponse, error)
+}
+
+type GetClientResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *ClientType
+}
+
+// GetJSON200 returns JSON200
+func (r GetClientResponse) GetJSON200() *ClientType {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetClientResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetClientResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetClientResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetClientResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type UpdateClientResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON400 *struct {
+ Code string `json:"code"`
+ }
+}
+
+// GetJSON400 returns JSON400
+func (r UpdateClientResponse) GetJSON400() *struct {
+ Code string `json:"code"`
+} {
+ return r.JSON400
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r UpdateClientResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r UpdateClientResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r UpdateClientResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r UpdateClientResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetClientWithResponse request returning *GetClientResponse
+func (c *ClientWithResponses) GetClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetClientResponse, error) {
+ rsp, err := c.GetClient(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetClientResponse(rsp)
+}
+
+// UpdateClientWithResponse request returning *UpdateClientResponse
+func (c *ClientWithResponses) UpdateClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*UpdateClientResponse, error) {
+ rsp, err := c.UpdateClient(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseUpdateClientResponse(rsp)
+}
+
+// ParseGetClientResponse parses an HTTP response from a GetClientWithResponse call
+func ParseGetClientResponse(rsp *http.Response) (*GetClientResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetClientResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest ClientType
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseUpdateClientResponse parses an HTTP response from a UpdateClientWithResponse call
+func ParseUpdateClientResponse(rsp *http.Response) (*UpdateClientResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &UpdateClientResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest struct {
+ Code string `json:"code"`
+ }
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
+ }
+
+ return response, nil
+}
diff --git a/examples/client/generate.go b/examples/client/generate.go
new file mode 100644
index 0000000000..e9c9a42f86
--- /dev/null
+++ b/examples/client/generate.go
@@ -0,0 +1,3 @@
+package client
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/clienttypenameclash/api.yaml b/examples/clienttypenameclash/api.yaml
new file mode 100644
index 0000000000..681f9d0b7e
--- /dev/null
+++ b/examples/clienttypenameclash/api.yaml
@@ -0,0 +1,34 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: "Show that generated client boilerplate can clash if schemas are well named i.e. `*Request` and `*Response`"
+paths:
+ /client:
+ put:
+ operationId: updateClient
+ requestBodies:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateClientRequest'
+ responses:
+ 400:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/UpdateClientResponse'
+components:
+ schemas:
+ UpdateClientRequest:
+ type: object
+ properties:
+ code:
+ type: string
+ required:
+ - code
+ UpdateClientResponse:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
diff --git a/examples/clienttypenameclash/cfg.yaml b/examples/clienttypenameclash/cfg.yaml
new file mode 100644
index 0000000000..0723317b4b
--- /dev/null
+++ b/examples/clienttypenameclash/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../configuration-schema.json
+package: client
+output: client.gen.go
+generate:
+ models: true
+ client: true
+output-options:
+ response-type-suffix: Resp
diff --git a/examples/clienttypenameclash/client.gen.go b/examples/clienttypenameclash/client.gen.go
new file mode 100644
index 0000000000..99ab3e36a2
--- /dev/null
+++ b/examples/clienttypenameclash/client.gen.go
@@ -0,0 +1,257 @@
+// Package client provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package client
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+// UpdateClientResponse defines model for UpdateClientResponse.
+type UpdateClientResponse struct {
+ Name string `json:"name"`
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // UpdateClient request
+ UpdateClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) UpdateClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewUpdateClientRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewUpdateClientRequest generates requests for UpdateClient
+func NewUpdateClientRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/client")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPut, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // UpdateClientWithResponse request
+ UpdateClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*UpdateClientResp, error)
+}
+
+type UpdateClientResp struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON400 *UpdateClientResponse
+}
+
+// GetJSON400 returns JSON400
+func (r UpdateClientResp) GetJSON400() *UpdateClientResponse {
+ return r.JSON400
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r UpdateClientResp) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r UpdateClientResp) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r UpdateClientResp) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r UpdateClientResp) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// UpdateClientWithResponse request returning *UpdateClientResp
+func (c *ClientWithResponses) UpdateClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*UpdateClientResp, error) {
+ rsp, err := c.UpdateClient(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseUpdateClientResp(rsp)
+}
+
+// ParseUpdateClientResp parses an HTTP response from a UpdateClientWithResponse call
+func ParseUpdateClientResp(rsp *http.Response) (*UpdateClientResp, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &UpdateClientResp{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest UpdateClientResponse
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
+ }
+
+ return response, nil
+}
diff --git a/examples/clienttypenameclash/generate.go b/examples/clienttypenameclash/generate.go
new file mode 100644
index 0000000000..e9c9a42f86
--- /dev/null
+++ b/examples/clienttypenameclash/generate.go
@@ -0,0 +1,3 @@
+package client
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/custom-client-type/cfg.yaml b/examples/custom-client-type/cfg.yaml
index 6f52fb3db7..7dcbbbc264 100644
--- a/examples/custom-client-type/cfg.yaml
+++ b/examples/custom-client-type/cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../configuration-schema.json
package: customclienttype
output: custom-client-type.gen.go
generate:
diff --git a/examples/custom-client-type/custom-client-type.gen.go b/examples/custom-client-type/custom-client-type.gen.go
index 0b73a09a01..adbb290453 100644
--- a/examples/custom-client-type/custom-client-type.gen.go
+++ b/examples/custom-client-type/custom-client-type.gen.go
@@ -1,6 +1,6 @@
// Package customclienttype provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package customclienttype
import (
@@ -126,7 +126,7 @@ func NewGetClientRequest(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -187,6 +187,16 @@ type GetClientResponse struct {
JSON200 *Client
}
+// GetJSON200 returns JSON200
+func (r GetClientResponse) GetJSON200() *Client {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetClientResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetClientResponse) Status() string {
if r.HTTPResponse != nil {
@@ -203,6 +213,14 @@ func (r GetClientResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetClientResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// GetClientWithResponse request returning *GetClientResponse
func (c *ClientWithResponses) GetClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetClientResponse, error) {
rsp, err := c.GetClient(ctx, reqEditors...)
diff --git a/examples/custom-client-type/doc.go b/examples/custom-client-type/doc.go
index b718ac2cb3..89172d392e 100644
--- a/examples/custom-client-type/doc.go
+++ b/examples/custom-client-type/doc.go
@@ -1,6 +1,6 @@
package customclienttype
// This is an example of how to add a prefix to the name of the generated Client struct
-// See https://github.com/deepmap/oapi-codegen/issues/785 for why this might be necessary
+// See https://github.com/oapi-codegen/oapi-codegen/issues/785 for why this might be necessary
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen -config cfg.yaml api.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/extensions/xdeprecatedreason/api.yaml b/examples/extensions/xdeprecatedreason/api.yaml
new file mode 100644
index 0000000000..c5056dd207
--- /dev/null
+++ b/examples/extensions/xdeprecatedreason/api.yaml
@@ -0,0 +1,32 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-deprecated-reason
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ deprecated: true
+ x-deprecated-reason: Don't use because reasons
+ id:
+ type: number
+ # NOTE that this doesn't generate, as no `deprecated: true` is set
+ x-deprecated-reason: NOTE you shouldn't see this, as you've not deprecated this field
+ deprecated_without_reason:
+ type: string
+ deprecated: true
+ # no `x-deprecated-reason` is set
diff --git a/examples/extensions/xdeprecatedreason/cfg.yaml b/examples/extensions/xdeprecatedreason/cfg.yaml
new file mode 100644
index 0000000000..05ae8c244b
--- /dev/null
+++ b/examples/extensions/xdeprecatedreason/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: xdeprecatedreason
+output: gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
diff --git a/examples/extensions/xdeprecatedreason/gen.go b/examples/extensions/xdeprecatedreason/gen.go
new file mode 100644
index 0000000000..3855905f92
--- /dev/null
+++ b/examples/extensions/xdeprecatedreason/gen.go
@@ -0,0 +1,19 @@
+// Package xdeprecatedreason provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xdeprecatedreason
+
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ // Deprecated: this property has been marked as deprecated upstream, but no `x-deprecated-reason` was set
+ DeprecatedWithoutReason *string `json:"deprecated_without_reason,omitempty"`
+ Id *float32 `json:"id,omitempty"`
+ // Deprecated: Don't use because reasons
+ Name string `json:"name"`
+}
diff --git a/examples/extensions/xdeprecatedreason/generate.go b/examples/extensions/xdeprecatedreason/generate.go
new file mode 100644
index 0000000000..97a610ff37
--- /dev/null
+++ b/examples/extensions/xdeprecatedreason/generate.go
@@ -0,0 +1,3 @@
+package xdeprecatedreason
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/extensions/xenumnames/api.yaml b/examples/extensions/xenumnames/api.yaml
new file mode 100644
index 0000000000..b9c271582d
--- /dev/null
+++ b/examples/extensions/xenumnames/api.yaml
@@ -0,0 +1,27 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-enumNames and x-enum-varnames
+components:
+ schemas:
+ ClientType:
+ type: string
+ enum:
+ - ACT
+ - EXP
+ ClientTypeWithNamesExtension:
+ type: string
+ enum:
+ - ACT
+ - EXP
+ x-enumNames:
+ - Active
+ - Expired
+ ClientTypeWithVarNamesExtension:
+ type: string
+ enum:
+ - ACT
+ - EXP
+ x-enum-varnames:
+ - Active
+ - Expired
diff --git a/examples/extensions/xenumnames/cfg.yaml b/examples/extensions/xenumnames/cfg.yaml
new file mode 100644
index 0000000000..694e667328
--- /dev/null
+++ b/examples/extensions/xenumnames/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: xenumnames
+output: gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
diff --git a/examples/extensions/xenumnames/gen.go b/examples/extensions/xenumnames/gen.go
new file mode 100644
index 0000000000..7d9596d6b4
--- /dev/null
+++ b/examples/extensions/xenumnames/gen.go
@@ -0,0 +1,67 @@
+// Package xenumnames provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xenumnames
+
+// Defines values for ClientType.
+const (
+ ACT ClientType = "ACT"
+ EXP ClientType = "EXP"
+)
+
+// Valid indicates whether the value is a known member of the ClientType enum.
+func (e ClientType) Valid() bool {
+ switch e {
+ case ACT:
+ return true
+ case EXP:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for ClientTypeWithNamesExtension.
+const (
+ ClientTypeWithNamesExtensionActive ClientTypeWithNamesExtension = "ACT"
+ ClientTypeWithNamesExtensionExpired ClientTypeWithNamesExtension = "EXP"
+)
+
+// Valid indicates whether the value is a known member of the ClientTypeWithNamesExtension enum.
+func (e ClientTypeWithNamesExtension) Valid() bool {
+ switch e {
+ case ClientTypeWithNamesExtensionActive:
+ return true
+ case ClientTypeWithNamesExtensionExpired:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for ClientTypeWithVarNamesExtension.
+const (
+ ClientTypeWithVarNamesExtensionActive ClientTypeWithVarNamesExtension = "ACT"
+ ClientTypeWithVarNamesExtensionExpired ClientTypeWithVarNamesExtension = "EXP"
+)
+
+// Valid indicates whether the value is a known member of the ClientTypeWithVarNamesExtension enum.
+func (e ClientTypeWithVarNamesExtension) Valid() bool {
+ switch e {
+ case ClientTypeWithVarNamesExtensionActive:
+ return true
+ case ClientTypeWithVarNamesExtensionExpired:
+ return true
+ default:
+ return false
+ }
+}
+
+// ClientType defines model for ClientType.
+type ClientType string
+
+// ClientTypeWithNamesExtension defines model for ClientTypeWithNamesExtension.
+type ClientTypeWithNamesExtension string
+
+// ClientTypeWithVarNamesExtension defines model for ClientTypeWithVarNamesExtension.
+type ClientTypeWithVarNamesExtension string
diff --git a/examples/extensions/xenumnames/generate.go b/examples/extensions/xenumnames/generate.go
new file mode 100644
index 0000000000..599d6f3f91
--- /dev/null
+++ b/examples/extensions/xenumnames/generate.go
@@ -0,0 +1,3 @@
+package xenumnames
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/extensions/xgojsonignore/api.yaml b/examples/extensions/xgojsonignore/api.yaml
new file mode 100644
index 0000000000..31af087f3e
--- /dev/null
+++ b/examples/extensions/xgojsonignore/api.yaml
@@ -0,0 +1,37 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-go-json-ignore
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ complexField:
+ type: object
+ properties:
+ name:
+ type: string
+ accountName:
+ type: string
+ # ...
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ complexField:
+ type: object
+ properties:
+ name:
+ type: string
+ accountName:
+ type: string
+ # ...
+ x-go-json-ignore: true
diff --git a/examples/extensions/xgojsonignore/cfg.yaml b/examples/extensions/xgojsonignore/cfg.yaml
new file mode 100644
index 0000000000..2e8300b09e
--- /dev/null
+++ b/examples/extensions/xgojsonignore/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: xgojsonignore
+output: gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
diff --git a/examples/extensions/xgojsonignore/gen.go b/examples/extensions/xgojsonignore/gen.go
new file mode 100644
index 0000000000..17c21373da
--- /dev/null
+++ b/examples/extensions/xgojsonignore/gen.go
@@ -0,0 +1,22 @@
+// Package xgojsonignore provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xgojsonignore
+
+// Client defines model for Client.
+type Client struct {
+ ComplexField *struct {
+ AccountName *string `json:"accountName,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"complexField,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ ComplexField *struct {
+ AccountName *string `json:"accountName,omitempty"`
+ Name *string `json:"name,omitempty"`
+ } `json:"-"`
+ Name string `json:"name"`
+}
diff --git a/examples/extensions/xgojsonignore/generate.go b/examples/extensions/xgojsonignore/generate.go
new file mode 100644
index 0000000000..0d8488e438
--- /dev/null
+++ b/examples/extensions/xgojsonignore/generate.go
@@ -0,0 +1,3 @@
+package xgojsonignore
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/extensions/xgoname/api.yaml b/examples/extensions/xgoname/api.yaml
new file mode 100644
index 0000000000..579412c918
--- /dev/null
+++ b/examples/extensions/xgoname/api.yaml
@@ -0,0 +1,27 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-go-name
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ x-go-name: ClientRenamedByExtension
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ # maybe we want to be intentionally verbose here?
+ x-go-name: AccountIdentifier
diff --git a/examples/extensions/xgoname/cfg.yaml b/examples/extensions/xgoname/cfg.yaml
new file mode 100644
index 0000000000..7dc65386df
--- /dev/null
+++ b/examples/extensions/xgoname/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: xgoname
+output: gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
diff --git a/examples/extensions/xgoname/gen.go b/examples/extensions/xgoname/gen.go
new file mode 100644
index 0000000000..c7831379a1
--- /dev/null
+++ b/examples/extensions/xgoname/gen.go
@@ -0,0 +1,16 @@
+// Package xgoname provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xgoname
+
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientRenamedByExtension defines model for ClientWithExtension.
+type ClientRenamedByExtension struct {
+ AccountIdentifier *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
diff --git a/examples/extensions/xgoname/generate.go b/examples/extensions/xgoname/generate.go
new file mode 100644
index 0000000000..5462114199
--- /dev/null
+++ b/examples/extensions/xgoname/generate.go
@@ -0,0 +1,3 @@
+package xgoname
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/extensions/xgotype/api.yaml b/examples/extensions/xgotype/api.yaml
new file mode 100644
index 0000000000..5efdb02722
--- /dev/null
+++ b/examples/extensions/xgotype/api.yaml
@@ -0,0 +1,36 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-go-type
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ # this is a bit of a contrived example, as you could instead use
+ # `format: uuid` but it explains how you'd do this when there may be
+ # a clash, for instance if you already had a `uuid` package that was
+ # being imported, or ...
+ x-go-type: googleuuid.UUID
+ x-go-type-import:
+ path: github.com/google/uuid
+ name: googleuuid
+ id:
+ type: number
+ # ... this is also a bit of a contrived example, as you could use
+ # `type: integer` but in the case that you know better than what
+ # oapi-codegen is generating, like so:
+ x-go-type: int64
diff --git a/examples/extensions/xgotype/cfg.yaml b/examples/extensions/xgotype/cfg.yaml
new file mode 100644
index 0000000000..afc39fcd7a
--- /dev/null
+++ b/examples/extensions/xgotype/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: xgotype
+output: gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
diff --git a/examples/extensions/xgotype/gen.go b/examples/extensions/xgotype/gen.go
new file mode 100644
index 0000000000..376c1fdbff
--- /dev/null
+++ b/examples/extensions/xgotype/gen.go
@@ -0,0 +1,20 @@
+// Package xgotype provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xgotype
+
+import (
+ googleuuid "github.com/google/uuid"
+)
+
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id *int64 `json:"id,omitempty"`
+ Name googleuuid.UUID `json:"name"`
+}
diff --git a/examples/extensions/xgotype/generate.go b/examples/extensions/xgotype/generate.go
new file mode 100644
index 0000000000..fc28c53de8
--- /dev/null
+++ b/examples/extensions/xgotype/generate.go
@@ -0,0 +1,3 @@
+package xgotype
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/extensions/xgotypename/api.yaml b/examples/extensions/xgotypename/api.yaml
new file mode 100644
index 0000000000..6c1146a5c8
--- /dev/null
+++ b/examples/extensions/xgotypename/api.yaml
@@ -0,0 +1,42 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-go-type-name
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ x-go-type-name: ClientRenamedByExtension
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ # NOTE attempting a `x-go-type-name` here is a no-op, as we're not producing a _type_ only a _field_
+ x-go-type-name: ThisWillNotBeUsed
+paths:
+ /example:
+ get:
+ operationId: exampleGet
+ responses:
+ '200':
+ description: "OK"
+ content:
+ 'application/json':
+ schema:
+ type: object
+ x-go-type-name: ResponseRenamed
+ properties:
+ name:
+ type: string
diff --git a/examples/extensions/xgotypename/cfg.yaml b/examples/extensions/xgotypename/cfg.yaml
new file mode 100644
index 0000000000..3a903b657f
--- /dev/null
+++ b/examples/extensions/xgotypename/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: xgotypename
+output: gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
diff --git a/examples/extensions/xgotypename/gen.go b/examples/extensions/xgotypename/gen.go
new file mode 100644
index 0000000000..aa3fe0b762
--- /dev/null
+++ b/examples/extensions/xgotypename/gen.go
@@ -0,0 +1,24 @@
+// Package xgotypename provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xgotypename
+
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension = ClientRenamedByExtension
+
+// ClientRenamedByExtension defines model for .
+type ClientRenamedByExtension struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ResponseRenamed defines parameters for ExampleGet.
+type ResponseRenamed struct {
+ Name *string `json:"name,omitempty"`
+}
diff --git a/examples/extensions/xgotypename/generate.go b/examples/extensions/xgotypename/generate.go
new file mode 100644
index 0000000000..787661180b
--- /dev/null
+++ b/examples/extensions/xgotypename/generate.go
@@ -0,0 +1,3 @@
+package xgotypename
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/extensions/xgotypeskipoptionalpointer/api.yaml b/examples/extensions/xgotypeskipoptionalpointer/api.yaml
new file mode 100644
index 0000000000..5dac5532b4
--- /dev/null
+++ b/examples/extensions/xgotypeskipoptionalpointer/api.yaml
@@ -0,0 +1,25 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-go-type-skip-optional-pointer
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ x-go-type-skip-optional-pointer: true
diff --git a/examples/extensions/xgotypeskipoptionalpointer/cfg.yaml b/examples/extensions/xgotypeskipoptionalpointer/cfg.yaml
new file mode 100644
index 0000000000..bb01706cf9
--- /dev/null
+++ b/examples/extensions/xgotypeskipoptionalpointer/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: xgotypeskipoptionalpointer
+output: gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
diff --git a/examples/extensions/xgotypeskipoptionalpointer/gen.go b/examples/extensions/xgotypeskipoptionalpointer/gen.go
new file mode 100644
index 0000000000..ddb1df8436
--- /dev/null
+++ b/examples/extensions/xgotypeskipoptionalpointer/gen.go
@@ -0,0 +1,16 @@
+// Package xgotypeskipoptionalpointer provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xgotypeskipoptionalpointer
+
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
diff --git a/examples/extensions/xgotypeskipoptionalpointer/generate.go b/examples/extensions/xgotypeskipoptionalpointer/generate.go
new file mode 100644
index 0000000000..582ec97fdd
--- /dev/null
+++ b/examples/extensions/xgotypeskipoptionalpointer/generate.go
@@ -0,0 +1,3 @@
+package xgotypeskipoptionalpointer
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/extensions/xoapicodegenextratags/api.yaml b/examples/extensions/xoapicodegenextratags/api.yaml
new file mode 100644
index 0000000000..34771334a4
--- /dev/null
+++ b/examples/extensions/xoapicodegenextratags/api.yaml
@@ -0,0 +1,30 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-oapi-codegen-extra-tags
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ - id
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ - id
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ x-oapi-codegen-extra-tags:
+ validate: "required,min=1,max=256"
+ safe-to-log: "true"
+ gorm: primarykey
diff --git a/examples/extensions/xoapicodegenextratags/cfg.yaml b/examples/extensions/xoapicodegenextratags/cfg.yaml
new file mode 100644
index 0000000000..582d1932a9
--- /dev/null
+++ b/examples/extensions/xoapicodegenextratags/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: xoapicodegenextratags
+output: gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
diff --git a/examples/extensions/xoapicodegenextratags/gen.go b/examples/extensions/xoapicodegenextratags/gen.go
new file mode 100644
index 0000000000..25f950e3d4
--- /dev/null
+++ b/examples/extensions/xoapicodegenextratags/gen.go
@@ -0,0 +1,16 @@
+// Package xoapicodegenextratags provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xoapicodegenextratags
+
+// Client defines model for Client.
+type Client struct {
+ Id float32 `json:"id"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id float32 `gorm:"primarykey" json:"id" safe-to-log:"true" validate:"required,min=1,max=256"`
+ Name string `json:"name"`
+}
diff --git a/examples/extensions/xoapicodegenextratags/generate.go b/examples/extensions/xoapicodegenextratags/generate.go
new file mode 100644
index 0000000000..6906128b00
--- /dev/null
+++ b/examples/extensions/xoapicodegenextratags/generate.go
@@ -0,0 +1,3 @@
+package xoapicodegenextratags
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/extensions/xoapicodegenonlyhonourgoname/api.yaml b/examples/extensions/xoapicodegenonlyhonourgoname/api.yaml
new file mode 100644
index 0000000000..7a1fc9e3ce
--- /dev/null
+++ b/examples/extensions/xoapicodegenonlyhonourgoname/api.yaml
@@ -0,0 +1,18 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-oapi-codegen-only-honour-go-name
+components:
+ schemas:
+ TypeWithUnexportedField:
+ description: A struct will be output where one of the fields is not exported
+ properties:
+ name:
+ type: string
+ id:
+ type: string
+ # NOTE that there is an explicit usage of a lowercase character
+ x-go-name: accountIdentifier
+ x-oapi-codegen-extra-tags:
+ json: "-"
+ x-oapi-codegen-only-honour-go-name: true
diff --git a/examples/extensions/xoapicodegenonlyhonourgoname/cfg.yaml b/examples/extensions/xoapicodegenonlyhonourgoname/cfg.yaml
new file mode 100644
index 0000000000..222b37e2ef
--- /dev/null
+++ b/examples/extensions/xoapicodegenonlyhonourgoname/cfg.yaml
@@ -0,0 +1,10 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: xoapicodegenonlyhonourgoname
+output: gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
+compatibility:
+ allow-unexported-struct-field-names: true
diff --git a/examples/extensions/xoapicodegenonlyhonourgoname/gen.go b/examples/extensions/xoapicodegenonlyhonourgoname/gen.go
new file mode 100644
index 0000000000..71e3cca4b5
--- /dev/null
+++ b/examples/extensions/xoapicodegenonlyhonourgoname/gen.go
@@ -0,0 +1,10 @@
+// Package xoapicodegenonlyhonourgoname provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xoapicodegenonlyhonourgoname
+
+// TypeWithUnexportedField A struct will be output where one of the fields is not exported
+type TypeWithUnexportedField struct {
+ accountIdentifier *string `json:"-"`
+ Name *string `json:"name,omitempty"`
+}
diff --git a/examples/extensions/xoapicodegenonlyhonourgoname/gen_test.go b/examples/extensions/xoapicodegenonlyhonourgoname/gen_test.go
new file mode 100644
index 0000000000..3e616bf99c
--- /dev/null
+++ b/examples/extensions/xoapicodegenonlyhonourgoname/gen_test.go
@@ -0,0 +1,18 @@
+package xoapicodegenonlyhonourgoname
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestTypeWithUnexportedField(t *testing.T) {
+ var v TypeWithUnexportedField
+
+ err := json.Unmarshal([]byte(`{"id": "some-id"}`), &v)
+ require.NoError(t, err)
+
+ // this field will never be unmarshaled
+ require.Nil(t, v.accountIdentifier)
+}
diff --git a/examples/extensions/xoapicodegenonlyhonourgoname/generate.go b/examples/extensions/xoapicodegenonlyhonourgoname/generate.go
new file mode 100644
index 0000000000..938d489126
--- /dev/null
+++ b/examples/extensions/xoapicodegenonlyhonourgoname/generate.go
@@ -0,0 +1,3 @@
+package xoapicodegenonlyhonourgoname
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/extensions/xomitempty/api.yaml b/examples/extensions/xomitempty/api.yaml
new file mode 100644
index 0000000000..d01919942d
--- /dev/null
+++ b/examples/extensions/xomitempty/api.yaml
@@ -0,0 +1,26 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-omitempty
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ # for some reason, you may want this behaviour, even though it's a required field
+ x-omitempty: true
+ id:
+ type: number
diff --git a/examples/extensions/xomitempty/cfg.yaml b/examples/extensions/xomitempty/cfg.yaml
new file mode 100644
index 0000000000..fe8c985087
--- /dev/null
+++ b/examples/extensions/xomitempty/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: xomitempty
+output: gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
diff --git a/examples/extensions/xomitempty/gen.go b/examples/extensions/xomitempty/gen.go
new file mode 100644
index 0000000000..a4a06f97e6
--- /dev/null
+++ b/examples/extensions/xomitempty/gen.go
@@ -0,0 +1,16 @@
+// Package xomitempty provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xomitempty
+
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name,omitempty"`
+}
diff --git a/examples/extensions/xomitempty/generate.go b/examples/extensions/xomitempty/generate.go
new file mode 100644
index 0000000000..c6c48c4fed
--- /dev/null
+++ b/examples/extensions/xomitempty/generate.go
@@ -0,0 +1,3 @@
+package xomitempty
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/extensions/xomitzero/api.yaml b/examples/extensions/xomitzero/api.yaml
new file mode 100644
index 0000000000..63b9b24c2b
--- /dev/null
+++ b/examples/extensions/xomitzero/api.yaml
@@ -0,0 +1,53 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-omitempty
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ id:
+ type: number
+ x-omitzero: true
+ ContainerTypeWithRequired:
+ type: object
+ properties:
+ has_is_zero:
+ $ref: "#/components/schemas/FieldWithCustomIsZeroMethod"
+ required:
+ - has_is_zero
+ ContainerTypeWithOptional:
+ type: object
+ properties:
+ has_is_zero:
+ $ref: "#/components/schemas/FieldWithCustomIsZeroMethod"
+ FieldWithCustomIsZeroMethod:
+ type: object
+ properties:
+ id:
+ type: string
+ value:
+ type: number
+ x-omitzero: true
+ FieldWithOmitZeroOnRequiredField:
+ type: object
+ properties:
+ id:
+ type: string
+ x-omitzero: true
+ required:
+ - id
diff --git a/examples/extensions/xomitzero/cfg.yaml b/examples/extensions/xomitzero/cfg.yaml
new file mode 100644
index 0000000000..bcec1dd3c6
--- /dev/null
+++ b/examples/extensions/xomitzero/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: xomitzero
+output: types.gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
diff --git a/examples/extensions/xomitzero/generate.go b/examples/extensions/xomitzero/generate.go
new file mode 100644
index 0000000000..70b6c27164
--- /dev/null
+++ b/examples/extensions/xomitzero/generate.go
@@ -0,0 +1,3 @@
+package xomitzero
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/extensions/xomitzero/tools/tools.go b/examples/extensions/xomitzero/tools/tools.go
new file mode 100644
index 0000000000..8615cb4c57
--- /dev/null
+++ b/examples/extensions/xomitzero/tools/tools.go
@@ -0,0 +1,8 @@
+//go:build tools
+// +build tools
+
+package tools
+
+import (
+ _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen"
+)
diff --git a/examples/extensions/xomitzero/types.gen.go b/examples/extensions/xomitzero/types.gen.go
new file mode 100644
index 0000000000..fe5e927d95
--- /dev/null
+++ b/examples/extensions/xomitzero/types.gen.go
@@ -0,0 +1,37 @@
+// Package xomitzero provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xomitzero
+
+// Client defines model for Client.
+type Client struct {
+ Id *float32 `json:"id,omitempty"`
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id *float32 `json:"id,omitempty,omitzero"`
+ Name string `json:"name"`
+}
+
+// ContainerTypeWithOptional defines model for ContainerTypeWithOptional.
+type ContainerTypeWithOptional struct {
+ HasIsZero *FieldWithCustomIsZeroMethod `json:"has_is_zero,omitempty,omitzero"`
+}
+
+// ContainerTypeWithRequired defines model for ContainerTypeWithRequired.
+type ContainerTypeWithRequired struct {
+ HasIsZero FieldWithCustomIsZeroMethod `json:"has_is_zero,omitzero"`
+}
+
+// FieldWithCustomIsZeroMethod defines model for FieldWithCustomIsZeroMethod.
+type FieldWithCustomIsZeroMethod struct {
+ Id *string `json:"id,omitempty"`
+ Value *float32 `json:"value,omitempty"`
+}
+
+// FieldWithOmitZeroOnRequiredField defines model for FieldWithOmitZeroOnRequiredField.
+type FieldWithOmitZeroOnRequiredField struct {
+ Id string `json:"id,omitzero"`
+}
diff --git a/examples/extensions/xomitzero/types.go b/examples/extensions/xomitzero/types.go
new file mode 100644
index 0000000000..fed32fb8f0
--- /dev/null
+++ b/examples/extensions/xomitzero/types.go
@@ -0,0 +1,20 @@
+package xomitzero
+
+type isZero interface {
+ IsZero() bool
+}
+
+var _ isZero = (*FieldWithCustomIsZeroMethod)(nil)
+
+func (z FieldWithCustomIsZeroMethod) IsZero() bool {
+ // NOTE that this is intentionally not a "normal" use of the function, but is a way to indicate that the `IsZero` used here can be anything arbitrary
+ if z.Id == nil {
+ return false
+ }
+
+ if *z.Id != "this is a zero value, for some weird reason!" {
+ return false
+ }
+
+ return true
+}
diff --git a/examples/extensions/xomitzero/types_test.go b/examples/extensions/xomitzero/types_test.go
new file mode 100644
index 0000000000..496d345d3c
--- /dev/null
+++ b/examples/extensions/xomitzero/types_test.go
@@ -0,0 +1,236 @@
+package xomitzero
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestClient_WithOmitEmpty(t *testing.T) {
+ t.Run("with a `string`, without `omitempty`", func(t *testing.T) {
+ t.Run("zero value Name does not get omitted", func(t *testing.T) {
+ client := Client{
+ Name: "",
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "name"))
+ })
+
+ t.Run("value Name does not get omitted", func(t *testing.T) {
+ client := Client{
+ Name: "some value",
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "name"))
+ })
+ })
+
+ t.Run("with a `*float32` with `omitempty`", func(t *testing.T) {
+ var zeroValue float32
+
+ t.Run("nil pointer ID gets omitted", func(t *testing.T) {
+ client := Client{
+ Id: nil,
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.False(t, jsonContainsKey(b, "id"))
+ })
+
+ t.Run("pointer to zero value ID does not get omitted", func(t *testing.T) {
+ client := Client{
+ Id: &zeroValue,
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "id"))
+ })
+
+ t.Run("pointer to value ID does not get omitted", func(t *testing.T) {
+ client := Client{
+ Id: &zeroValue,
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "id"))
+ })
+ })
+}
+
+func TestClientWithExtension_WithOmitZero(t *testing.T) {
+ t.Run("with a `string`, without `omitzero`", func(t *testing.T) {
+ t.Run("zero value Name does not get omitted", func(t *testing.T) {
+ client := ClientWithExtension{
+ Name: "",
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "name"))
+ })
+
+ t.Run("value Name does not get omitted", func(t *testing.T) {
+ client := ClientWithExtension{
+ Name: "some value",
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "name"))
+ })
+ })
+
+ t.Run("with a `*float32` with `omitzero`", func(t *testing.T) {
+ var zeroValue float32
+
+ t.Run("nil pointer ID gets omitted", func(t *testing.T) {
+ client := ClientWithExtension{
+ Id: nil,
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.False(t, jsonContainsKey(b, "id"))
+ })
+
+ t.Run("pointer to zero value ID does not get omitted", func(t *testing.T) {
+ client := ClientWithExtension{
+ Id: &zeroValue,
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "id"))
+ })
+
+ t.Run("pointer to value ID does not get omitted", func(t *testing.T) {
+ client := ClientWithExtension{
+ Id: &zeroValue,
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "id"))
+ })
+ })
+}
+
+func TestContainerTypeWithRequired(t *testing.T) {
+ t.Run("zero value on HasIsZero does not get omitted", func(t *testing.T) {
+ container := ContainerTypeWithRequired{
+ HasIsZero: FieldWithCustomIsZeroMethod{},
+ }
+
+ b, err := json.Marshal(container)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "has_is_zero"))
+ })
+
+ t.Run("value defined as zero value by IsZero on HasIsZero gets omitted", func(t *testing.T) {
+ magicIDValue := "this is a zero value, for some weird reason!"
+
+ container := ContainerTypeWithRequired{
+ HasIsZero: FieldWithCustomIsZeroMethod{
+ Id: &magicIDValue,
+ },
+ }
+
+ b, err := json.Marshal(container)
+ require.NoError(t, err)
+
+ assert.False(t, jsonContainsKey(b, "has_is_zero"))
+ })
+}
+
+func TestContainerTypeWithOptional(t *testing.T) {
+ t.Run("zero value (nil pointer) on HasIsZero gets omitted", func(t *testing.T) {
+ container := ContainerTypeWithOptional{
+ HasIsZero: nil,
+ }
+
+ b, err := json.Marshal(container)
+ require.NoError(t, err)
+
+ assert.False(t, jsonContainsKey(b, "has_is_zero"))
+ })
+
+ t.Run("value (pointer to zero value of FieldWithCustomIsZeroMethod) on HasIsZero does not get omitted", func(t *testing.T) {
+ container := ContainerTypeWithOptional{
+ HasIsZero: &FieldWithCustomIsZeroMethod{},
+ }
+
+ b, err := json.Marshal(container)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "has_is_zero"))
+ })
+
+ t.Run("value defined as zero value by IsZero on HasIsZero gets omitted", func(t *testing.T) {
+ magicIDValue := "this is a zero value, for some weird reason!"
+
+ container := ContainerTypeWithOptional{
+ HasIsZero: &FieldWithCustomIsZeroMethod{
+ Id: &magicIDValue,
+ },
+ }
+
+ b, err := json.Marshal(container)
+ require.NoError(t, err)
+
+ assert.False(t, jsonContainsKey(b, "has_is_zero"))
+ })
+}
+
+func TestFieldWithOmitZeroOnRequiredField(t *testing.T) {
+ t.Run("zero value (empty string) on Id gets omitted", func(t *testing.T) {
+ field := FieldWithOmitZeroOnRequiredField{
+ Id: "",
+ }
+
+ b, err := json.Marshal(field)
+ require.NoError(t, err)
+
+ assert.False(t, jsonContainsKey(b, "id"))
+ })
+
+ t.Run("value for Id not get omitted", func(t *testing.T) {
+ field := FieldWithOmitZeroOnRequiredField{
+ Id: "value",
+ }
+
+ b, err := json.Marshal(field)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "id"))
+ })
+}
+
+// jsonContainsKey checks if the given JSON object contains the specified key at the top level.
+func jsonContainsKey(b []byte, key string) bool {
+ var m map[string]any
+ if err := json.Unmarshal(b, &m); err != nil {
+ return false
+ }
+ _, ok := m[key]
+ return ok
+}
diff --git a/examples/extensions/xorder/api.yaml b/examples/extensions/xorder/api.yaml
new file mode 100644
index 0000000000..5171a0def1
--- /dev/null
+++ b/examples/extensions/xorder/api.yaml
@@ -0,0 +1,26 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: x-order
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ a_name:
+ type: string
+ id:
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ a_name:
+ type: string
+ x-order: 2
+ id:
+ type: number
+ x-order: 1
diff --git a/examples/extensions/xorder/cfg.yaml b/examples/extensions/xorder/cfg.yaml
new file mode 100644
index 0000000000..0d3851f478
--- /dev/null
+++ b/examples/extensions/xorder/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: xorder
+output: gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
diff --git a/examples/extensions/xorder/gen.go b/examples/extensions/xorder/gen.go
new file mode 100644
index 0000000000..bb5841d564
--- /dev/null
+++ b/examples/extensions/xorder/gen.go
@@ -0,0 +1,16 @@
+// Package xorder provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xorder
+
+// Client defines model for Client.
+type Client struct {
+ AName *string `json:"a_name,omitempty"`
+ Id *float32 `json:"id,omitempty"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ Id *float32 `json:"id,omitempty"`
+ AName *string `json:"a_name,omitempty"`
+}
diff --git a/examples/extensions/xorder/generate.go b/examples/extensions/xorder/generate.go
new file mode 100644
index 0000000000..9b9d46563e
--- /dev/null
+++ b/examples/extensions/xorder/generate.go
@@ -0,0 +1,3 @@
+package xorder
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/generate/serverurls/api.yaml b/examples/generate/serverurls/api.yaml
new file mode 100644
index 0000000000..53a5d807f8
--- /dev/null
+++ b/examples/generate/serverurls/api.yaml
@@ -0,0 +1,86 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Server URLs can be optionally generated
+servers:
+# adapted from https://spec.openapis.org/oas/v3.0.3#server-object
+- url: https://development.gigantic-server.com/v1
+ description: Development server
+- url: https://staging.gigantic-server.com/v1
+ description: Staging server
+- url: https://api.gigantic-server.com/v1
+ description: Production server
+# adapted from https://spec.openapis.org/oas/v3.0.3#server-object
+- url: https://{username}.gigantic-server.com:{port}/{basePath}
+ description: The production API server
+ variables:
+ username:
+ # note! no enum here means it is an open value
+ default: demo
+ description: this value is assigned by the service provider, in this example `gigantic-server.com`
+ port:
+ enum:
+ - '8443'
+ - '443'
+ default: '8443'
+ basePath:
+ # open meaning there is the opportunity to use special base paths as assigned by the provider, default is `v2`
+ default: v2
+ # an example of a variable declared but NOT referenced in the URL.
+ # `oapi-codegen` filters these out so they don't pollute the
+ # generated function signature with no-op parameters
+ # (https://github.com/oapi-codegen/oapi-codegen/issues/2004).
+ noDefault: {}
+# A server whose `port` enum literally includes the string `default`.
+# The previous codegen tripped over this because the enum constant for
+# the value `default` collided with the named default-pointer constant
+# (https://github.com/oapi-codegen/oapi-codegen/issues/2003); the fix
+# routes server-URL enums through the generic enum path and renames
+# the default-pointer constant to `…VariableDefaultValue`.
+- url: https://api.example.com/{port}
+ description: Conflicting default enum
+ variables:
+ port:
+ enum:
+ - 'default'
+ - '443'
+ default: 'default'
+# A server whose URL contains a `{token}` placeholder for which there
+# is no entry in `variables`. The previous codegen happily emitted a
+# function that left `{token}` in the URL, which then tripped the
+# trailing `{`/`}` runtime check on every call
+# (https://github.com/oapi-codegen/oapi-codegen/issues/2005). The fix
+# emits the undeclared placeholder as a plain `string` parameter so
+# callers can fill it in.
+- url: https://{tenant}.api.example.com
+ description: Undeclared placeholder server
+# A server whose enum has two values that fold to the same Go
+# identifier suffix (`foo` and `Foo` both `ucFirst` to `Foo`). The
+# previous codegen would have emitted two `const ...VariableFoo`
+# declarations and failed to compile; the synthesizer now appends a
+# numeric suffix to disambiguate, and the typed default-pointer
+# references the correct (post-suffix) enum constant — addressing the
+# concern raised in PR #2358 review.
+- url: https://api.example.com/{mode}
+ description: Case-only enum collision
+ variables:
+ mode:
+ enum:
+ - 'foo'
+ - 'Foo'
+ default: 'Foo'
+# clash with the previous definition of `Development server` to trigger a new name
+- url: http://localhost:80
+ description: Development server
+# clash with the previous definition of `Development server` to trigger a new name (again)
+- url: http://localhost:81
+ description: Development server
+# make sure that the lowercase `description` gets converted to an uppercase
+- url: http://localhost:82
+ description: some lowercase name
+# there may be URLs on their own, without a `description`
+- url: http://localhost:443
+# x-go-name overrides the auto-generated Go name
+- url: https://api.example.com/v2
+ description: Custom named server
+ x-go-name: MyCustomAPIServer
diff --git a/examples/generate/serverurls/cfg.yaml b/examples/generate/serverurls/cfg.yaml
new file mode 100644
index 0000000000..8815cb6a68
--- /dev/null
+++ b/examples/generate/serverurls/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: serverurls
+output: gen.go
+generate:
+ server-urls: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
diff --git a/examples/generate/serverurls/gen.go b/examples/generate/serverurls/gen.go
new file mode 100644
index 0000000000..5f0feea91b
--- /dev/null
+++ b/examples/generate/serverurls/gen.go
@@ -0,0 +1,184 @@
+// Package serverurls provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package serverurls
+
+import (
+ "fmt"
+ "strings"
+)
+
+// ServerUrlCaseOnlyEnumCollisionModeVariable defines model for mode.
+type ServerUrlCaseOnlyEnumCollisionModeVariable string
+
+// ServerUrlConflictingDefaultEnumPortVariable defines model for port.
+type ServerUrlConflictingDefaultEnumPortVariable string
+
+// ServerUrlTheProductionAPIServerPortVariable defines model for port.
+type ServerUrlTheProductionAPIServerPortVariable string
+
+// Defines values for ServerUrlCaseOnlyEnumCollisionModeVariable.
+const (
+ ServerUrlCaseOnlyEnumCollisionModeVariableFoo ServerUrlCaseOnlyEnumCollisionModeVariable = "foo"
+ ServerUrlCaseOnlyEnumCollisionModeVariableFoo1 ServerUrlCaseOnlyEnumCollisionModeVariable = "Foo"
+)
+
+// Valid indicates whether the value is a known member of the ServerUrlCaseOnlyEnumCollisionModeVariable enum.
+func (e ServerUrlCaseOnlyEnumCollisionModeVariable) Valid() bool {
+ switch e {
+ case ServerUrlCaseOnlyEnumCollisionModeVariableFoo:
+ return true
+ case ServerUrlCaseOnlyEnumCollisionModeVariableFoo1:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for ServerUrlConflictingDefaultEnumPortVariable.
+const (
+ ServerUrlConflictingDefaultEnumPortVariable443 ServerUrlConflictingDefaultEnumPortVariable = "443"
+ ServerUrlConflictingDefaultEnumPortVariableDefault ServerUrlConflictingDefaultEnumPortVariable = "default"
+)
+
+// Valid indicates whether the value is a known member of the ServerUrlConflictingDefaultEnumPortVariable enum.
+func (e ServerUrlConflictingDefaultEnumPortVariable) Valid() bool {
+ switch e {
+ case ServerUrlConflictingDefaultEnumPortVariable443:
+ return true
+ case ServerUrlConflictingDefaultEnumPortVariableDefault:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for ServerUrlTheProductionAPIServerPortVariable.
+const (
+ ServerUrlTheProductionAPIServerPortVariable443 ServerUrlTheProductionAPIServerPortVariable = "443"
+ ServerUrlTheProductionAPIServerPortVariable8443 ServerUrlTheProductionAPIServerPortVariable = "8443"
+)
+
+// Valid indicates whether the value is a known member of the ServerUrlTheProductionAPIServerPortVariable enum.
+func (e ServerUrlTheProductionAPIServerPortVariable) Valid() bool {
+ switch e {
+ case ServerUrlTheProductionAPIServerPortVariable443:
+ return true
+ case ServerUrlTheProductionAPIServerPortVariable8443:
+ return true
+ default:
+ return false
+ }
+}
+
+// MyCustomAPIServer defines the Server URL for Custom named server
+const MyCustomAPIServer = "https://api.example.com/v2"
+
+// ServerUrlCaseOnlyEnumCollisionModeVariableDefault is the default choice, for the accepted values for the `mode` variable
+const ServerUrlCaseOnlyEnumCollisionModeVariableDefault ServerUrlCaseOnlyEnumCollisionModeVariable = ServerUrlCaseOnlyEnumCollisionModeVariableFoo1
+
+// NewServerUrlCaseOnlyEnumCollision constructs the Server URL for Case-only enum collision, with the provided variables.
+func NewServerUrlCaseOnlyEnumCollision(mode ServerUrlCaseOnlyEnumCollisionModeVariable) (string, error) {
+ if !mode.Valid() {
+ return "", fmt.Errorf("`%v` is not one of the accepted values for the `mode` variable", mode)
+ }
+
+ u := "https://api.example.com/{mode}"
+
+ u = strings.ReplaceAll(u, "{mode}", string(mode))
+
+ if strings.Contains(u, "{") || strings.Contains(u, "}") {
+ return "", fmt.Errorf("after mapping variables, there were still `{` or `}` characters in the string: %#v", u)
+ }
+
+ return u, nil
+}
+
+// ServerUrlConflictingDefaultEnumPortVariableDefaultValue is the default choice, for the accepted values for the `port` variable
+const ServerUrlConflictingDefaultEnumPortVariableDefaultValue ServerUrlConflictingDefaultEnumPortVariable = ServerUrlConflictingDefaultEnumPortVariableDefault
+
+// NewServerUrlConflictingDefaultEnum constructs the Server URL for Conflicting default enum, with the provided variables.
+func NewServerUrlConflictingDefaultEnum(port ServerUrlConflictingDefaultEnumPortVariable) (string, error) {
+ if !port.Valid() {
+ return "", fmt.Errorf("`%v` is not one of the accepted values for the `port` variable", port)
+ }
+
+ u := "https://api.example.com/{port}"
+
+ u = strings.ReplaceAll(u, "{port}", string(port))
+
+ if strings.Contains(u, "{") || strings.Contains(u, "}") {
+ return "", fmt.Errorf("after mapping variables, there were still `{` or `}` characters in the string: %#v", u)
+ }
+
+ return u, nil
+}
+
+// ServerUrlDevelopmentServer defines the Server URL for Development server
+const ServerUrlDevelopmentServer = "https://development.gigantic-server.com/v1"
+
+// ServerUrlDevelopmentServer1 defines the Server URL for Development server
+const ServerUrlDevelopmentServer1 = "http://localhost:80"
+
+// ServerUrlDevelopmentServer2 defines the Server URL for Development server
+const ServerUrlDevelopmentServer2 = "http://localhost:81"
+
+// ServerUrlHttplocalhost443 defines the Server URL for http://localhost:443
+const ServerUrlHttplocalhost443 = "http://localhost:443"
+
+// ServerUrlProductionServer defines the Server URL for Production server
+const ServerUrlProductionServer = "https://api.gigantic-server.com/v1"
+
+// ServerUrlSomeLowercaseName defines the Server URL for some lowercase name
+const ServerUrlSomeLowercaseName = "http://localhost:82"
+
+// ServerUrlStagingServer defines the Server URL for Staging server
+const ServerUrlStagingServer = "https://staging.gigantic-server.com/v1"
+
+// ServerUrlTheProductionAPIServerBasePathVariable is the `basePath` variable for ServerUrlTheProductionAPIServer
+type ServerUrlTheProductionAPIServerBasePathVariable string
+
+// ServerUrlTheProductionAPIServerBasePathVariableDefault is the default value for the `basePath` variable for ServerUrlTheProductionAPIServer
+const ServerUrlTheProductionAPIServerBasePathVariableDefault = "v2"
+
+// ServerUrlTheProductionAPIServerUsernameVariable is the `username` variable for ServerUrlTheProductionAPIServer
+type ServerUrlTheProductionAPIServerUsernameVariable string
+
+// ServerUrlTheProductionAPIServerUsernameVariableDefault is the default value for the `username` variable for ServerUrlTheProductionAPIServer
+const ServerUrlTheProductionAPIServerUsernameVariableDefault = "demo"
+
+// ServerUrlTheProductionAPIServerPortVariableDefault is the default choice, for the accepted values for the `port` variable
+const ServerUrlTheProductionAPIServerPortVariableDefault ServerUrlTheProductionAPIServerPortVariable = ServerUrlTheProductionAPIServerPortVariable8443
+
+// NewServerUrlTheProductionAPIServer constructs the Server URL for The production API server, with the provided variables.
+func NewServerUrlTheProductionAPIServer(basePath ServerUrlTheProductionAPIServerBasePathVariable, port ServerUrlTheProductionAPIServerPortVariable, username ServerUrlTheProductionAPIServerUsernameVariable) (string, error) {
+ if !port.Valid() {
+ return "", fmt.Errorf("`%v` is not one of the accepted values for the `port` variable", port)
+ }
+
+ u := "https://{username}.gigantic-server.com:{port}/{basePath}"
+
+ u = strings.ReplaceAll(u, "{basePath}", string(basePath))
+ u = strings.ReplaceAll(u, "{port}", string(port))
+ u = strings.ReplaceAll(u, "{username}", string(username))
+
+ if strings.Contains(u, "{") || strings.Contains(u, "}") {
+ return "", fmt.Errorf("after mapping variables, there were still `{` or `}` characters in the string: %#v", u)
+ }
+
+ return u, nil
+}
+
+// NewServerUrlUndeclaredPlaceholderServer constructs the Server URL for Undeclared placeholder server, with the provided variables.
+func NewServerUrlUndeclaredPlaceholderServer(tenant string) (string, error) {
+
+ u := "https://{tenant}.api.example.com"
+
+ u = strings.ReplaceAll(u, "{tenant}", tenant)
+
+ if strings.Contains(u, "{") || strings.Contains(u, "}") {
+ return "", fmt.Errorf("after mapping variables, there were still `{` or `}` characters in the string: %#v", u)
+ }
+
+ return u, nil
+}
diff --git a/examples/generate/serverurls/gen_test.go b/examples/generate/serverurls/gen_test.go
new file mode 100644
index 0000000000..6968ed3fe2
--- /dev/null
+++ b/examples/generate/serverurls/gen_test.go
@@ -0,0 +1,132 @@
+package serverurls
+
+import (
+ "net/url"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestServerUrlTheProductionAPIServer(t *testing.T) {
+ t.Run("when an empty value is provided for an enum-typed variable, it errors", func(t *testing.T) {
+ // `port` is enum-typed; the empty string is not in {"443", "8443"}.
+ _, err := NewServerUrlTheProductionAPIServer("", "", "")
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "port")
+ })
+
+ t.Run("when a value not in the enum is provided, it errors", func(t *testing.T) {
+ invalidPort := ServerUrlTheProductionAPIServerPortVariable("12345")
+ _, err := NewServerUrlTheProductionAPIServer(
+ ServerUrlTheProductionAPIServerBasePathVariableDefault,
+ invalidPort,
+ ServerUrlTheProductionAPIServerUsernameVariableDefault,
+ )
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "port")
+ })
+
+ t.Run("when default values are provided, it does not error", func(t *testing.T) {
+ // The default-pointer keeps its historical name on this server
+ // because the enum doesn't collide (no enum value folds to
+ // "Default") — the asymmetric rename for #2003 only kicks in
+ // when collision is detected.
+ serverUrl, err := NewServerUrlTheProductionAPIServer(
+ ServerUrlTheProductionAPIServerBasePathVariableDefault,
+ ServerUrlTheProductionAPIServerPortVariableDefault,
+ ServerUrlTheProductionAPIServerUsernameVariableDefault,
+ )
+ require.NoError(t, err)
+
+ assert.Equal(t, "https://demo.gigantic-server.com:8443/v2", serverUrl)
+
+ _, err = url.Parse(serverUrl)
+ require.NoError(t, err)
+ })
+
+ t.Run("a valid non-default enum value is accepted", func(t *testing.T) {
+ serverUrl, err := NewServerUrlTheProductionAPIServer(
+ ServerUrlTheProductionAPIServerBasePathVariableDefault,
+ ServerUrlTheProductionAPIServerPortVariable443,
+ ServerUrlTheProductionAPIServerUsernameVariableDefault,
+ )
+ require.NoError(t, err)
+
+ assert.Equal(t, "https://demo.gigantic-server.com:443/v2", serverUrl)
+ })
+}
+
+func TestXGoName(t *testing.T) {
+ t.Run("x-go-name overrides the auto-generated server name", func(t *testing.T) {
+ assert.Equal(t, "https://api.example.com/v2", MyCustomAPIServer)
+ })
+}
+
+// Regression test for #2003: an `enum` value `default` no longer
+// collides with the default-pointer constant — both are emitted and
+// the typed default-pointer correctly references the enum constant.
+func TestServerUrlConflictingDefaultEnum(t *testing.T) {
+ t.Run("the default-pointer references the enum constant for `default`", func(t *testing.T) {
+ assert.Equal(t,
+ ServerUrlConflictingDefaultEnumPortVariable("default"),
+ ServerUrlConflictingDefaultEnumPortVariableDefaultValue,
+ )
+ })
+
+ t.Run("New… accepts the default and the other enum value, errors on others", func(t *testing.T) {
+ got, err := NewServerUrlConflictingDefaultEnum(ServerUrlConflictingDefaultEnumPortVariableDefaultValue)
+ require.NoError(t, err)
+ assert.Equal(t, "https://api.example.com/default", got)
+
+ got, err = NewServerUrlConflictingDefaultEnum(ServerUrlConflictingDefaultEnumPortVariable443)
+ require.NoError(t, err)
+ assert.Equal(t, "https://api.example.com/443", got)
+
+ _, err = NewServerUrlConflictingDefaultEnum("nope")
+ require.Error(t, err)
+ })
+}
+
+// Regression test for #2005: a `{placeholder}` in the URL with no
+// matching entry in `variables` is generated as a plain `string`
+// parameter so the function returns a usable URL instead of always
+// erroring on the trailing `{` / `}` check.
+func TestServerUrlUndeclaredPlaceholderServer(t *testing.T) {
+ got, err := NewServerUrlUndeclaredPlaceholderServer("acme")
+ require.NoError(t, err)
+ assert.Equal(t, "https://acme.api.example.com", got)
+}
+
+// Regression test for the case-only-different-enum scenario raised in
+// PR #2358 review: `enum: [foo, Foo]` produces two values that
+// `ucFirst`-fold to the same identifier `Foo`. The synthesizer dedups
+// with a numeric suffix (`Foo` and `Foo1`) and the typed default-pointer
+// references the post-suffix const that actually exists. Under the old
+// codegen this would have emitted two `const ...VariableFoo`
+// declarations and failed to compile.
+func TestServerUrlCaseOnlyEnumCollision(t *testing.T) {
+ t.Run("default-pointer references the post-dedup constant", func(t *testing.T) {
+ // The spec sets default: "Foo"; the post-dedup const is
+ // ...VariableFoo1, which is exactly what the pointer must
+ // resolve to.
+ assert.Equal(t,
+ ServerUrlCaseOnlyEnumCollisionModeVariable("Foo"),
+ ServerUrlCaseOnlyEnumCollisionModeVariableDefault,
+ )
+ assert.Equal(t,
+ ServerUrlCaseOnlyEnumCollisionModeVariableDefault,
+ ServerUrlCaseOnlyEnumCollisionModeVariableFoo1,
+ )
+ })
+
+ t.Run("both case-variant constants are distinct and accepted", func(t *testing.T) {
+ got, err := NewServerUrlCaseOnlyEnumCollision(ServerUrlCaseOnlyEnumCollisionModeVariableFoo)
+ require.NoError(t, err)
+ assert.Equal(t, "https://api.example.com/foo", got)
+
+ got, err = NewServerUrlCaseOnlyEnumCollision(ServerUrlCaseOnlyEnumCollisionModeVariableFoo1)
+ require.NoError(t, err)
+ assert.Equal(t, "https://api.example.com/Foo", got)
+ })
+}
diff --git a/examples/generate/serverurls/generate.go b/examples/generate/serverurls/generate.go
new file mode 100644
index 0000000000..68ad5cfab5
--- /dev/null
+++ b/examples/generate/serverurls/generate.go
@@ -0,0 +1,3 @@
+package serverurls
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/go.mod b/examples/go.mod
index 8672df1dd8..909480902e 100644
--- a/examples/go.mod
+++ b/examples/go.mod
@@ -1,115 +1,129 @@
-module github.com/deepmap/oapi-codegen/examples
+module github.com/oapi-codegen/oapi-codegen/v2/examples
-go 1.20
+go 1.25.9
-replace github.com/deepmap/oapi-codegen => ../
+replace github.com/oapi-codegen/oapi-codegen/v2 => ../
require (
- github.com/deepmap/oapi-codegen v0.0.0-00010101000000-000000000000
- github.com/getkin/kin-openapi v0.118.0
- github.com/gin-gonic/gin v1.9.1
- github.com/go-chi/chi/v5 v5.0.10
- github.com/gofiber/fiber/v2 v2.49.1
- github.com/gorilla/mux v1.8.0
- github.com/kataras/iris/v12 v12.2.6-0.20230908161203-24ba4e8933b9
- github.com/labstack/echo/v4 v4.11.1
- github.com/lestrrat-go/jwx v1.2.26
- github.com/oapi-codegen/echo-middleware v1.0.1
- github.com/oapi-codegen/fiber-middleware v1.0.1
- github.com/oapi-codegen/gin-middleware v1.0.1
- github.com/oapi-codegen/iris-middleware v1.0.4
- github.com/oapi-codegen/nethttp-middleware v1.0.1
- github.com/oapi-codegen/runtime v1.0.0
- github.com/stretchr/testify v1.8.4
- golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
+ github.com/getkin/kin-openapi v0.140.0
+ github.com/gin-gonic/gin v1.12.0
+ github.com/go-chi/chi/v5 v5.2.5
+ github.com/gofiber/fiber/v2 v2.52.13
+ github.com/google/uuid v1.6.0
+ github.com/gorilla/mux v1.8.1
+ github.com/kataras/iris/v12 v12.2.11
+ github.com/labstack/echo/v4 v4.15.1
+ github.com/labstack/echo/v5 v5.1.0
+ github.com/lestrrat-go/jwx/v3 v3.1.0
+ github.com/oapi-codegen/echo-middleware v1.0.2
+ github.com/oapi-codegen/fiber-middleware v1.0.2
+ github.com/oapi-codegen/gin-middleware v1.0.2
+ github.com/oapi-codegen/iris-middleware v1.0.5
+ github.com/oapi-codegen/nethttp-middleware v1.1.2
+ github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000
+ github.com/oapi-codegen/runtime v1.4.1
+ github.com/oapi-codegen/testutil v1.1.0
+ github.com/stretchr/testify v1.11.1
+ golang.org/x/lint v0.0.0-20241112194109-818c5a804067
)
require (
- github.com/BurntSushi/toml v1.3.2 // indirect
- github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 // indirect
- github.com/CloudyKit/jet/v6 v6.2.0 // indirect
+ github.com/BurntSushi/toml v1.6.0 // indirect
+ github.com/CloudyKit/fastprinter v0.0.0-20251202014920-1725d2651bd4 // indirect
+ github.com/CloudyKit/jet/v6 v6.3.2 // indirect
github.com/Joker/jade v1.1.3 // indirect
- github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect
- github.com/andybalholm/brotli v1.0.5 // indirect
+ github.com/Shopify/goreferrer v0.0.0-20250617153402-88c1d9a79b05 // indirect
+ github.com/andybalholm/brotli v1.2.1 // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
- github.com/bytedance/sonic v1.10.0-rc3 // indirect
- github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
- github.com/chenzhuoyu/iasm v0.9.0 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
+ github.com/bytedance/gopkg v0.1.4 // indirect
+ github.com/bytedance/sonic v1.15.1 // indirect
+ github.com/bytedance/sonic/loader v0.5.1 // indirect
+ github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
+ github.com/cloudwego/base64x v0.1.7 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+ github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 // indirect
+ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/flosch/pongo2/v4 v4.0.2 // indirect
- github.com/gabriel-vasile/mimetype v1.4.2 // indirect
- github.com/gin-contrib/sse v0.1.0 // indirect
- github.com/go-openapi/jsonpointer v0.20.0 // indirect
- github.com/go-openapi/swag v0.22.4 // indirect
+ github.com/gabriel-vasile/mimetype v1.4.13 // indirect
+ github.com/gin-contrib/sse v1.1.1 // indirect
+ github.com/go-openapi/jsonpointer v0.23.1 // indirect
+ github.com/go-openapi/swag/jsonname v0.26.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
- github.com/go-playground/validator/v10 v10.14.1 // indirect
- github.com/goccy/go-json v0.10.2 // indirect
- github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
- github.com/golang/snappy v0.0.4 // indirect
- github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 // indirect
- github.com/google/uuid v1.3.1 // indirect
- github.com/gorilla/css v1.0.0 // indirect
- github.com/invopop/yaml v0.2.0 // indirect
+ github.com/go-playground/validator/v10 v10.30.2 // indirect
+ github.com/goccy/go-json v0.10.6 // indirect
+ github.com/goccy/go-yaml v1.19.2 // indirect
+ github.com/golang/snappy v1.0.0 // indirect
+ github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df // indirect
+ github.com/gorilla/css v1.0.1 // indirect
github.com/iris-contrib/schema v0.0.6 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
- github.com/kataras/blocks v0.0.7 // indirect
- github.com/kataras/golog v0.1.9 // indirect
- github.com/kataras/pio v0.0.12 // indirect
+ github.com/kataras/blocks v0.0.12 // indirect
+ github.com/kataras/golog v0.1.11 // indirect
+ github.com/kataras/pio v0.0.13 // indirect
github.com/kataras/sitemap v0.0.6 // indirect
github.com/kataras/tunnel v0.0.4 // indirect
- github.com/klauspost/compress v1.16.7 // indirect
- github.com/klauspost/cpuid/v2 v2.2.5 // indirect
- github.com/labstack/gommon v0.4.0 // indirect
- github.com/leodido/go-urn v1.2.4 // indirect
- github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
- github.com/lestrrat-go/blackmagic v1.0.1 // indirect
+ github.com/klauspost/compress v1.18.6 // indirect
+ github.com/klauspost/cpuid/v2 v2.3.0 // indirect
+ github.com/labstack/gommon v0.5.0 // indirect
+ github.com/leodido/go-urn v1.4.0 // indirect
+ github.com/lestrrat-go/blackmagic v1.0.4 // indirect
+ github.com/lestrrat-go/dsig v1.3.0 // indirect
+ github.com/lestrrat-go/dsig-secp256k1 v1.0.0 // indirect
github.com/lestrrat-go/httpcc v1.0.1 // indirect
- github.com/lestrrat-go/iter v1.0.2 // indirect
- github.com/lestrrat-go/option v1.0.1 // indirect
+ github.com/lestrrat-go/httprc/v3 v3.0.5 // indirect
+ github.com/lestrrat-go/option/v2 v2.0.0 // indirect
github.com/mailgun/raymond/v2 v2.0.48 // indirect
- github.com/mailru/easyjson v0.7.7 // indirect
- github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.19 // indirect
- github.com/mattn/go-runewidth v0.0.15 // indirect
- github.com/microcosm-cc/bluemonday v1.0.25 // indirect
+ github.com/mailru/easyjson v0.9.2 // indirect
+ github.com/mattn/go-colorable v0.1.14 // indirect
+ github.com/mattn/go-isatty v0.0.22 // indirect
+ github.com/mattn/go-runewidth v0.0.23 // indirect
+ github.com/microcosm-cc/bluemonday v1.0.27 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
- github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
- github.com/pelletier/go-toml/v2 v2.0.9 // indirect
- github.com/perimeterx/marshmallow v1.1.5 // indirect
- github.com/pkg/errors v0.9.1 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/rivo/uniseg v0.4.4 // indirect
- github.com/rogpeppe/go-internal v1.11.0 // indirect
+ github.com/oasdiff/yaml v0.1.0 // indirect
+ github.com/oasdiff/yaml3 v0.0.13 // indirect
+ github.com/pelletier/go-toml/v2 v2.3.0 // indirect
+ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
+ github.com/quic-go/qpack v0.6.0 // indirect
+ github.com/quic-go/quic-go v0.59.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
+ github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
github.com/schollz/closestmatch v2.1.0+incompatible // indirect
- github.com/sirupsen/logrus v1.8.1 // indirect
- github.com/tdewolff/minify/v2 v2.12.9 // indirect
- github.com/tdewolff/parse/v2 v2.6.8 // indirect
+ github.com/segmentio/asm v1.2.1 // indirect
+ github.com/sirupsen/logrus v1.9.4 // indirect
+ github.com/speakeasy-api/jsonpath v0.6.3 // indirect
+ github.com/speakeasy-api/openapi v1.23.0 // indirect
+ github.com/tdewolff/minify/v2 v2.24.13 // indirect
+ github.com/tdewolff/parse/v2 v2.8.12 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
- github.com/ugorji/go/codec v1.2.11 // indirect
+ github.com/ugorji/go/codec v1.3.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
- github.com/valyala/fasthttp v1.49.0 // indirect
+ github.com/valyala/fasthttp v1.70.0 // indirect
+ github.com/valyala/fastjson v1.6.10 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
- github.com/valyala/tcplisten v1.0.0 // indirect
- github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
+ github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
+ github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
github.com/yosssi/ace v0.0.5 // indirect
- golang.org/x/arch v0.4.0 // indirect
- golang.org/x/crypto v0.13.0 // indirect
- golang.org/x/mod v0.12.0 // indirect
- golang.org/x/net v0.15.0 // indirect
- golang.org/x/sys v0.12.0 // indirect
- golang.org/x/text v0.13.0 // indirect
- golang.org/x/time v0.3.0 // indirect
- golang.org/x/tools v0.12.0 // indirect
- google.golang.org/protobuf v1.31.0 // indirect
- gopkg.in/ini.v1 v1.67.0 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
+ go.mongodb.org/mongo-driver/v2 v2.6.0 // indirect
+ go.yaml.in/yaml/v3 v3.0.4 // indirect
+ golang.org/x/arch v0.26.0 // indirect
+ golang.org/x/crypto v0.51.0 // indirect
+ golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect
+ golang.org/x/mod v0.36.0 // indirect
+ golang.org/x/net v0.54.0 // indirect
+ golang.org/x/sync v0.20.0 // indirect
+ golang.org/x/sys v0.44.0 // indirect
+ golang.org/x/text v0.37.0 // indirect
+ golang.org/x/time v0.15.0 // indirect
+ golang.org/x/tools v0.45.0 // indirect
+ google.golang.org/protobuf v1.36.11 // indirect
+ gopkg.in/ini.v1 v1.67.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
+
+tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen
diff --git a/examples/go.sum b/examples/go.sum
index a6878a2207..0468e46daf 100644
--- a/examples/go.sum
+++ b/examples/go.sum
@@ -1,98 +1,130 @@
-github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
-github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
-github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c=
+github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
+github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
-github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME=
-github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4=
+github.com/CloudyKit/fastprinter v0.0.0-20251202014920-1725d2651bd4 h1:DQ1+lDdBve+u+aovjh4wV6sYnvZKH0Hx8GaQOi4vYl8=
+github.com/CloudyKit/fastprinter v0.0.0-20251202014920-1725d2651bd4/go.mod h1:eauGmjfZG874MOAEPVeqg21mZCbTOLW+tFe8F7NpfnY=
+github.com/CloudyKit/jet/v6 v6.3.2 h1:BPaX0lnXTZ9TniICiiK/0iJqzeGJ2ibvB4DjAqLMBSM=
+github.com/CloudyKit/jet/v6 v6.3.2/go.mod h1:lf8ksdNsxZt7/yH/3n4vJQWA9RUq4wpaHtArHhGVMOw=
github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc=
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk=
github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM=
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
-github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0=
-github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM=
+github.com/Shopify/goreferrer v0.0.0-20250617153402-88c1d9a79b05 h1:dG7/gLroJGht/jSQtHiLvT48Hxn+crbmvyItZC8cWOs=
+github.com/Shopify/goreferrer v0.0.0-20250617153402-88c1d9a79b05/go.mod h1:NYezi6wtnJtBm5btoprXc5SvAdqH0XTXWnUup0MptAI=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
-github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
-github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
+github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
+github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro=
+github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
-github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
-github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
-github.com/bytedance/sonic v1.10.0-rc3 h1:uNSnscRapXTwUgTyOF0GVljYD08p9X/Lbr9MweSV3V0=
-github.com/bytedance/sonic v1.10.0-rc3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
-github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
-github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
-github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
-github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
-github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
-github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
+github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM=
+github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4=
+github.com/bytedance/sonic v1.15.1 h1:nJD5PmM0vY7J8CT6MxoqbVAAMhkSmV2HgRAUrrpLoOw=
+github.com/bytedance/sonic v1.15.1/go.mod h1:mT2NbXunuaEbnZ+mRIX/vYqKISmgEuHFDI4UzmKx2SA=
+github.com/bytedance/sonic/loader v0.5.1 h1:Ygpfa9zwRCCKSlrp5bBP/b/Xzc3VxsAW+5NIYXrOOpI=
+github.com/bytedance/sonic/loader v0.5.1/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
+github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
+github.com/cloudwego/base64x v0.1.7 h1:NppS+Fgzg5ovhn4NkUXaDT3x9jldgH5ToMCqzBSi2zI=
+github.com/cloudwego/base64x v0.1.7/go.mod h1:Cu1PV9zfrSf7ET2tIbWbbEy7jO7HHJ13q4X2SQ8aWYg=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs=
-github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 h1:5RVFMOWjMyRy8cARdy79nAmgYw3hK/4HUq48LQ6Wwqo=
+github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1/go.mod h1:ZXNYxsqcloTdSy/rNShjYzMhyjf0LaoftYK0p+A3h40=
+github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
+github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58=
+github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w=
+github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
+github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw=
github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
-github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
-github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
-github.com/getkin/kin-openapi v0.118.0 h1:z43njxPmJ7TaPpMSCQb7PN0dEYno4tyBPQcrFdHoLuM=
-github.com/getkin/kin-openapi v0.118.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc=
-github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
-github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
-github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
-github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
-github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
-github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
-github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
-github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
-github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
-github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
-github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
+github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
+github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
+github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
+github.com/getkin/kin-openapi v0.140.0 h1:JFn675aXRFjyiZKa/BFWploGldQlI0gobp4J5k0EZ2g=
+github.com/getkin/kin-openapi v0.140.0/go.mod h1:lISrB64F0CPcuDJ3LdtPTMJBY8VENjR9wJBdrcT6J3g=
+github.com/gin-contrib/sse v1.1.1 h1:uGYpNwTacv5R68bSGMapo62iLTRa9l5zxGCps4hK6ko=
+github.com/gin-contrib/sse v1.1.1/go.mod h1:QXzuVkA0YO7o/gun03UI1Q+FTI8ZV/n5t03kIQAI89s=
+github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
+github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc=
+github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
+github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
+github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4=
+github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY=
+github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w=
+github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M=
+github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4=
+github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
-github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
-github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
-github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
+github.com/go-playground/validator/v10 v10.30.2 h1:JiFIMtSSHb2/XBUbWM4i/MpeQm9ZK2xqPNk8vgvu5JQ=
+github.com/go-playground/validator/v10 v10.30.2/go.mod h1:mAf2pIOVXjTEBrwUMGKkCWKKPs9NheYGabeB04txQSc=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
-github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
-github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
-github.com/gofiber/fiber/v2 v2.49.1 h1:0W2DRWevSirc8pJl4o8r8QejDR8TV6ZUCawHxwbIdOk=
-github.com/gofiber/fiber/v2 v2.49.1/go.mod h1:nPUeEBUeeYGgwbDm59Gp7vS8MDyScL6ezr/Np9A13WU=
-github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
-github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
+github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
+github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
+github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
+github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
+github.com/gofiber/fiber/v2 v2.52.13 h1:TOKP64iqC9b5P49VrBW5tHhUOvDyrtJ0xePEfzJbCbk=
+github.com/gofiber/fiber/v2 v2.52.13/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
-github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 h1:uK3X/2mt4tbSGoHvbLBHUny7CKiuwUip3MArtukol4E=
-github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
+github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df h1:Mwihr/o+v4L5h56rwHLOE20+hh7Okhwno5BHz3zDuao=
+github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
-github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
-github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
-github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
-github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
-github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
+github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
+github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
-github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
-github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
-github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
+github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/iris-contrib/httpexpect/v2 v2.15.2 h1:T9THsdP1woyAqKHwjkEsbCnMefsAFvk8iJJKokcJ3Go=
+github.com/iris-contrib/httpexpect/v2 v2.15.2/go.mod h1:JLDgIqnFy5loDSUv1OA2j0mb6p/rDhiCqigP22Uq9xE=
github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw=
github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -100,251 +132,303 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
-github.com/kataras/blocks v0.0.7 h1:cF3RDY/vxnSRezc7vLFlQFTYXG/yAr1o7WImJuZbzC4=
-github.com/kataras/blocks v0.0.7/go.mod h1:UJIU97CluDo0f+zEjbnbkeMRlvYORtmc1304EeyXf4I=
-github.com/kataras/golog v0.1.9 h1:vLvSDpP7kihFGKFAvBSofYo7qZNULYSHOH2D7rPTKJk=
-github.com/kataras/golog v0.1.9/go.mod h1:jlpk/bOaYCyqDqH18pgDHdaJab72yBE6i0O3s30hpWY=
-github.com/kataras/iris/v12 v12.2.6-0.20230908161203-24ba4e8933b9 h1:Vx8kDVhO2qepK8w44lBtp+RzN3ld743i+LYPzODJSpQ=
-github.com/kataras/iris/v12 v12.2.6-0.20230908161203-24ba4e8933b9/go.mod h1:ldkoR3iXABBeqlTibQ3MYaviA1oSlPvim6f55biwBh4=
-github.com/kataras/pio v0.0.12 h1:o52SfVYauS3J5X08fNjlGS5arXHjW/ItLkyLcKjoH6w=
-github.com/kataras/pio v0.0.12/go.mod h1:ODK/8XBhhQ5WqrAhKy+9lTPS7sBf6O3KcLhc9klfRcY=
+github.com/kataras/blocks v0.0.12 h1:2OnEYFcLtYPjyEMhyDk1pdHm+b75hay5uobuPTacnIc=
+github.com/kataras/blocks v0.0.12/go.mod h1:CtCOQ+YDdd0NJTMW019YPV9D+q6dWO2b9d2cSRgifpk=
+github.com/kataras/golog v0.1.11 h1:dGkcCVsIpqiAMWTlebn/ZULHxFvfG4K43LF1cNWSh20=
+github.com/kataras/golog v0.1.11/go.mod h1:mAkt1vbPowFUuUGvexyQ5NFW6djEgGyxQBIARJ0AH4A=
+github.com/kataras/iris/v12 v12.2.11 h1:sGgo43rMPfzDft8rjVhPs6L3qDJy3TbBrMD/zGL1pzk=
+github.com/kataras/iris/v12 v12.2.11/go.mod h1:uMAeX8OqG9vqdhyrIPv8Lajo/wXTtAF43wchP9WHt2w=
+github.com/kataras/pio v0.0.13 h1:x0rXVX0fviDTXOOLOmr4MUxOabu1InVSTu5itF8CXCM=
+github.com/kataras/pio v0.0.13/go.mod h1:k3HNuSw+eJ8Pm2lA4lRhg3DiCjVgHlP8hmXApSej3oM=
github.com/kataras/sitemap v0.0.6 h1:w71CRMMKYMJh6LR2wTgnk5hSgjVNB9KL60n5e2KHvLY=
github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4=
github.com/kataras/tunnel v0.0.4 h1:sCAqWuJV7nPzGrlb0os3j49lk2JhILT0rID38NHNLpA=
github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw=
-github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
-github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
-github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
-github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
-github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
+github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
+github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
+github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
+github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4=
-github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ=
-github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
-github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
-github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
-github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
-github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A=
-github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y=
-github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80=
-github.com/lestrrat-go/blackmagic v1.0.1/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/labstack/echo/v4 v4.15.1 h1:S9keusg26gZpjMmPqB5hOEvNKnmd1lNmcHrbbH2lnFs=
+github.com/labstack/echo/v4 v4.15.1/go.mod h1:xmw1clThob0BSVRX1CRQkGQ/vjwcpOMjQZSZa9fKA/c=
+github.com/labstack/echo/v5 v5.1.0 h1:MvIRydoN+p9cx/zq8Lff6YXqUW2ZaEsOMISzEGSMrBI=
+github.com/labstack/echo/v5 v5.1.0/go.mod h1:SyvlSdObGjRXeQfCCXW/sybkZdOOQZBmpKF0bvALaeo=
+github.com/labstack/gommon v0.5.0 h1:6VSQ2NOzsnEJ5W6+84E0RbcaDDmgB6NIAzWCczTEe6c=
+github.com/labstack/gommon v0.5.0/go.mod h1:Rzlg7HHy1maLfzBYGg9NZcVuz1sA68HHhLjhcEllYE0=
+github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
+github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
+github.com/lestrrat-go/blackmagic v1.0.4 h1:IwQibdnf8l2KoO+qC3uT4OaTWsW7tuRQXy9TRN9QanA=
+github.com/lestrrat-go/blackmagic v1.0.4/go.mod h1:6AWFyKNNj0zEXQYfTMPfZrAXUWUfTIZ5ECEUEJaijtw=
+github.com/lestrrat-go/dsig v1.3.0 h1:phjMOCXvYzhuIgn7Voe2rex8z166vGfxRxmqM25P9/Q=
+github.com/lestrrat-go/dsig v1.3.0/go.mod h1:RD2eOaidyPvpc7IJQoO3Qq52RWdy8ZcJs8lrOnoa1Kc=
+github.com/lestrrat-go/dsig-secp256k1 v1.0.0 h1:JpDe4Aybfl0soBvoVwjqDbp+9S1Y2OM7gcrVVMFPOzY=
+github.com/lestrrat-go/dsig-secp256k1 v1.0.0/go.mod h1:CxUgAhssb8FToqbL8NjSPoGQlnO4w3LG1P0qPWQm/NU=
github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE=
github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E=
-github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI=
-github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4=
-github.com/lestrrat-go/jwx v1.2.26 h1:4iFo8FPRZGDYe1t19mQP0zTRqA7n8HnJ5lkIiDvJcB0=
-github.com/lestrrat-go/jwx v1.2.26/go.mod h1:MaiCdGbn3/cckbOFSCluJlJMmp9dmZm5hDuIkx8ftpQ=
-github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
-github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU=
-github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I=
+github.com/lestrrat-go/httprc/v3 v3.0.5 h1:S+Mb4L2I+bM6JGTibLmxExhyTOqnXjqx+zi9MoXw/TM=
+github.com/lestrrat-go/httprc/v3 v3.0.5/go.mod h1:mSMtkZW92Z98M5YoNNztbRGxbXHql7tSitCvaxvo9l0=
+github.com/lestrrat-go/jwx/v3 v3.1.0 h1:AyyLtxc0QM75F75JroWgt1phwC7X+wOb3XKhH7XBZWw=
+github.com/lestrrat-go/jwx/v3 v3.1.0/go.mod h1:uw/MN2M/Xiu4FhwcIwH11Zsh9JWx9SWzgALl7/uIEkU=
+github.com/lestrrat-go/option/v2 v2.0.0 h1:XxrcaJESE1fokHy3FpaQ/cXW8ZsIdWcdFzzLOcID3Ss=
+github.com/lestrrat-go/option/v2 v2.0.0/go.mod h1:oSySsmzMoR0iRzCDCaUfsCzxQHUEuhOViQObyy7S6Vg=
github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw=
github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18=
-github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
-github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
-github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
-github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
-github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
-github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
-github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg=
-github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE=
+github.com/mailru/easyjson v0.9.2 h1:dX8U45hQsZpxd80nLvDGihsQ/OxlvTkVUXH2r/8cb2M=
+github.com/mailru/easyjson v0.9.2/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
+github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
+github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
+github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
+github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
+github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw=
+github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
+github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
+github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
-github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/oapi-codegen/echo-middleware v1.0.1 h1:edYGScq1phCcuDoz9AqA9eHX+tEI1LNL5PL1lkkQh1k=
-github.com/oapi-codegen/echo-middleware v1.0.1/go.mod h1:DBQKRn+D/vfXOFbaX5GRwFttoJY64JH6yu+pdt7wU3o=
-github.com/oapi-codegen/fiber-middleware v1.0.1 h1:DZQA+tEsqEMox4pPmc6SJXvDriiWSxc3QiA4UuMwGq4=
-github.com/oapi-codegen/fiber-middleware v1.0.1/go.mod h1:UUVrHLPT4Zv7S2U2TCGLXpTx6mfMb613UI+Z6F8S5Vk=
-github.com/oapi-codegen/gin-middleware v1.0.1 h1:903hkcyMcM/h6ooHS7t/2ad973BY0xvsRNP0EN1B65g=
-github.com/oapi-codegen/gin-middleware v1.0.1/go.mod h1:JDMxGX/rErQs2VV0XAVo1sD6sA0EVUMvFSPhgOLt9mE=
-github.com/oapi-codegen/iris-middleware v1.0.4 h1:+Eoqqbc90qCeBz3Zlzf1xb5xn+wfwQihndHlvU/4Meo=
-github.com/oapi-codegen/iris-middleware v1.0.4/go.mod h1:D1IAqYMgm5QKbD9R+y0j8m+xUtiPLMG92iY+oos/NXc=
-github.com/oapi-codegen/nethttp-middleware v1.0.1 h1:ZWvwfnMU0eloHX1VEJmQscQm3741t0vCm0eSIie1NIo=
-github.com/oapi-codegen/nethttp-middleware v1.0.1/go.mod h1:P7xtAvpoqNB+5obR9qRCeefH7YlXWSK3KgPs/9WB8tE=
-github.com/oapi-codegen/runtime v1.0.0 h1:P4rqFX5fMFWqRzY9M/3YF9+aPSPPB06IzP2P7oOxrWo=
-github.com/oapi-codegen/runtime v1.0.0/go.mod h1:LmCUMQuPB4M/nLXilQXhHw+BLZdDb18B34OO356yJ/A=
-github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
-github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
-github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
-github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
-github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
-github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
-github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
+github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
+github.com/oapi-codegen/echo-middleware v1.0.2 h1:oNBqiE7jd/9bfGNk/bpbX2nqWrtPc+LL4Boya8Wl81U=
+github.com/oapi-codegen/echo-middleware v1.0.2/go.mod h1:5J6MFcGqrpWLXpbKGZtRPZViLIHyyyUHlkqg6dT2R4E=
+github.com/oapi-codegen/fiber-middleware v1.0.2 h1:f4KPdjyRTYh2GyAv9wsDP+Q9akOND17wuMSbmMwDkJI=
+github.com/oapi-codegen/fiber-middleware v1.0.2/go.mod h1:+lGj+802Ajp/+fQG9d8t1SuYP8r7lnOc6wnOwwRArYg=
+github.com/oapi-codegen/gin-middleware v1.0.2 h1:/H99UzvHQAUxXK8pzdcGAZgjCVeXdFDAUUWaJT0k0eI=
+github.com/oapi-codegen/gin-middleware v1.0.2/go.mod h1:2HJDQjH8jzK2/k/VKcWl+/T41H7ai2bKa6dN3AA2GpA=
+github.com/oapi-codegen/iris-middleware v1.0.5 h1:eO33pCvapaf1Xa0esEP0PYcdqPZSeq1eze4mamhT5hU=
+github.com/oapi-codegen/iris-middleware v1.0.5/go.mod h1:/ysgvbjWyhfDAouIeUOjzIv+zsXfaIXlAQrsOU9/Kyo=
+github.com/oapi-codegen/nethttp-middleware v1.1.2 h1:TQwEU3WM6ifc7ObBEtiJgbRPaCe513tvJpiMJjypVPA=
+github.com/oapi-codegen/nethttp-middleware v1.1.2/go.mod h1:5qzjxMSiI8HjLljiOEjvs4RdrWyMPKnExeFS2kr8om4=
+github.com/oapi-codegen/nullable v1.1.0 h1:eAh8JVc5430VtYVnq00Hrbpag9PFRGWLjxR1/3KntMs=
+github.com/oapi-codegen/nullable v1.1.0/go.mod h1:KUZ3vUzkmEKY90ksAmit2+5juDIhIZhfDl+0PwOQlFY=
+github.com/oapi-codegen/runtime v1.4.1 h1:9nwLoI+KrWxzbBcp0jO/R8uXqbik/HUyCvPeU68Y/qo=
+github.com/oapi-codegen/runtime v1.4.1/go.mod h1:GwV7hC2hviaMzj+ITfHVRESK5J2W/GefVwIND/bMGvU=
+github.com/oapi-codegen/testutil v1.1.0 h1:EufqpNg43acR3qzr3ObhXmWg3Sl2kwtRnUN5GYY4d5g=
+github.com/oapi-codegen/testutil v1.1.0/go.mod h1:ttCaYbHvJtHuiyeBF0tPIX+4uhEPTeizXKx28okijLw=
+github.com/oasdiff/yaml v0.1.0 h1:0bqZjfKc/8S9urj4JuwepX41WX9EoA6ifhU3SV06cXg=
+github.com/oasdiff/yaml v0.1.0/go.mod h1:kOlRmMdL2X3vucLCEQO5u61SU22RysnfXvcttrZA1O0=
+github.com/oasdiff/yaml3 v0.0.13 h1:06svmvOHOVBqF81+sY2EUScvUI/iS/vl2VIeUUxZQwg=
+github.com/oasdiff/yaml3 v0.0.13/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
+github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
+github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
+github.com/pelletier/go-toml/v2 v2.3.0 h1:k59bC/lIZREW0/iVaQR8nDHxVq8OVlIzYCOJf421CaM=
+github.com/pelletier/go-toml/v2 v2.3.0/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
-github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
-github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
-github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
+github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
+github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
+github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
+github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
+github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
-github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
-github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/segmentio/asm v1.2.1 h1:DTNbBqs57ioxAD4PrArqftgypG4/qNpXoJx8TVXxPR0=
+github.com/segmentio/asm v1.2.1/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
+github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
+github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
+github.com/speakeasy-api/jsonpath v0.6.3 h1:c+QPwzAOdrWvzycuc9HFsIZcxKIaWcNpC+xhOW9rJxU=
+github.com/speakeasy-api/jsonpath v0.6.3/go.mod h1:2cXloNuQ+RSXi5HTRaeBh7JEmjRXTiaKpFTdZiL7URI=
+github.com/speakeasy-api/openapi v1.23.0 h1:BlnHqUR/8uIs4tp3d2B4QDN03gw1/QY2R2MHg6fLhRU=
+github.com/speakeasy-api/openapi v1.23.0/go.mod h1:Ih+ZzaTCCPyB2ykiDXaxhqk6jsY84ke3n5p6fobMDXk=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/tdewolff/minify/v2 v2.12.9 h1:dvn5MtmuQ/DFMwqf5j8QhEVpPX6fi3WGImhv8RUB4zA=
-github.com/tdewolff/minify/v2 v2.12.9/go.mod h1:qOqdlDfL+7v0/fyymB+OP497nIxJYSvX4MQWA8OoiXU=
-github.com/tdewolff/parse/v2 v2.6.8 h1:mhNZXYCx//xG7Yq2e/kVLNZw4YfYmeHbhx+Zc0OvFMA=
-github.com/tdewolff/parse/v2 v2.6.8/go.mod h1:XHDhaU6IBgsryfdnpzUXBlT6leW/l25yrFBTEb4eIyM=
-github.com/tdewolff/test v1.0.9 h1:SswqJCmeN4B+9gEAi/5uqT0qpi1y2/2O47V/1hhGZT0=
-github.com/tdewolff/test v1.0.9/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/tdewolff/minify/v2 v2.24.13 h1:xrcF7gKDnUszseEY9WX9mUlZII2v2Go/QAcAwRASw58=
+github.com/tdewolff/minify/v2 v2.24.13/go.mod h1:emvwoYeIl8bfAKqRU5ww95LX9Gpggpqv/naal9a8Yq0=
+github.com/tdewolff/parse/v2 v2.8.12 h1:5BBjfaCv482v3nltlS0u6wH1xJaxjR6ofDrWttNvROg=
+github.com/tdewolff/parse/v2 v2.8.12/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLBLd6dlIXYqo=
+github.com/tdewolff/test v1.0.11/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
+github.com/tdewolff/test v1.0.12 h1:7F21DqIajswxuche0geHdrUZRCWE4oko4b7bcmkkrxk=
+github.com/tdewolff/test v1.0.12/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
-github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
-github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
-github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
-github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
+github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.49.0 h1:9FdvCpmxB74LH4dPb7IJ1cOSsluR07XG3I1txXWwJpE=
-github.com/valyala/fasthttp v1.49.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
-github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
+github.com/valyala/fasthttp v1.70.0 h1:LAhMGcWk13QZWm85+eg8ZBNbrq5mnkWFGbHMUJHIdXA=
+github.com/valyala/fasthttp v1.70.0/go.mod h1:oDZEHHkJ/Buyklg6uURmYs19442zFSnCIfX3j1FY3pE=
+github.com/valyala/fastjson v1.6.10 h1:/yjJg8jaVQdYR3arGxPE2X5z89xrlhS0eGXdv+ADTh4=
+github.com/valyala/fastjson v1.6.10/go.mod h1:e6FubmQouUNP73jtMLmcbxS6ydWIpOfhz34TSfO3JaE=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
-github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
-github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
-github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
-github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
+github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
+github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
+github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk=
+github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
+github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
+github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
+github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
+github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
-golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc=
-golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+go.mongodb.org/mongo-driver/v2 v2.6.0 h1:b9sJOYrkmt4l8bY43ZenFBcPlhYIjaOfYHLtbB/5qi8=
+go.mongodb.org/mongo-driver/v2 v2.6.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
+go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
+go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
+go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
+go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
+golang.org/x/arch v0.26.0 h1:jZ6dpec5haP/fUv1kLCbuJy6dnRrfX6iVK08lZBFpk4=
+golang.org/x/arch v0.26.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
-golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
-golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
+golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
+golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
+golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
+golang.org/x/lint v0.0.0-20241112194109-818c5a804067 h1:adDmSQyFTCiv19j015EGKJBoaa7ElV0Q1Wovb/4G7NA=
+golang.org/x/lint v0.0.0-20241112194109-818c5a804067/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
-golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
-golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
-golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
+golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
-golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
-golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
-golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
+golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
-golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
+golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
-golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
-golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
-golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
-golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
-golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
-golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
+golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
+golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
+golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
-golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
-golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
-golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
+golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
+golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
-google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
+google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
-gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k=
+gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs=
-nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
-rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
+moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE=
diff --git a/examples/import-mapping/admin/api.yaml b/examples/import-mapping/admin/api.yaml
new file mode 100644
index 0000000000..aeec72f407
--- /dev/null
+++ b/examples/import-mapping/admin/api.yaml
@@ -0,0 +1,32 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Admin API
+ description: The admin-only portion of the API, which has its own separate OpenAPI spec
+tags:
+ - name: admin
+ description: Admin API endpoints
+ - name: user
+ description: API endpoint that pertains to user data
+paths:
+ /admin/user/{id}:
+ get:
+ tags:
+ - admin
+ - user
+ summary: Get a user's details
+ operationId: getUserById
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ format: uuid
+ responses:
+ 200:
+ description: Success
+ content:
+ application/json:
+ schema:
+ $ref: '../common/api.yaml#/components/schemas/User'
diff --git a/examples/import-mapping/common/api.yaml b/examples/import-mapping/common/api.yaml
new file mode 100644
index 0000000000..08af65a133
--- /dev/null
+++ b/examples/import-mapping/common/api.yaml
@@ -0,0 +1,10 @@
+components:
+ schemas:
+ User:
+ type: object
+ additionalProperties: false
+ properties:
+ name:
+ type: string
+ required:
+ - name
diff --git a/examples/import-mapping/multiplepackages/admin/cfg.yaml b/examples/import-mapping/multiplepackages/admin/cfg.yaml
new file mode 100644
index 0000000000..65ca92f1b7
--- /dev/null
+++ b/examples/import-mapping/multiplepackages/admin/cfg.yaml
@@ -0,0 +1,11 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: admin
+output: server.gen.go
+generate:
+ models: true
+ chi-server: true
+output-options:
+ # to make sure that all types are generated
+ skip-prune: true
+import-mapping:
+ ../common/api.yaml: github.com/oapi-codegen/oapi-codegen/v2/examples/import-mapping/multiplepackages/common
diff --git a/examples/import-mapping/multiplepackages/admin/generate.go b/examples/import-mapping/multiplepackages/admin/generate.go
new file mode 100644
index 0000000000..304d122d22
--- /dev/null
+++ b/examples/import-mapping/multiplepackages/admin/generate.go
@@ -0,0 +1,3 @@
+package admin
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../admin/api.yaml
diff --git a/examples/import-mapping/multiplepackages/admin/server.gen.go b/examples/import-mapping/multiplepackages/admin/server.gen.go
new file mode 100644
index 0000000000..3235142110
--- /dev/null
+++ b/examples/import-mapping/multiplepackages/admin/server.gen.go
@@ -0,0 +1,185 @@
+// Package admin provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package admin
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/go-chi/chi/v5"
+ "github.com/oapi-codegen/runtime"
+ openapi_types "github.com/oapi-codegen/runtime/types"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // Get a user's details
+ // (GET /admin/user/{id})
+ GetUserById(w http.ResponseWriter, r *http.Request, id openapi_types.UUID)
+}
+
+// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
+
+type Unimplemented struct{}
+
+// Get a user's details
+// (GET /admin/user/{id})
+func (_ Unimplemented) GetUserById(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetUserById operation middleware
+func (siw *ServerInterfaceWrapper) GetUserById(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id openapi_types.UUID
+
+ err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "uuid"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetUserById(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{})
+}
+
+type ChiServerOptions struct {
+ BaseURL string
+ BaseRouter chi.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = chi.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/admin/user/{id}", wrapper.GetUserById)
+ })
+
+ return r
+}
diff --git a/examples/import-mapping/multiplepackages/common/cfg.yaml b/examples/import-mapping/multiplepackages/common/cfg.yaml
new file mode 100644
index 0000000000..8c38a4454d
--- /dev/null
+++ b/examples/import-mapping/multiplepackages/common/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: common
+output: types.gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated
+ skip-prune: true
diff --git a/examples/import-mapping/multiplepackages/common/generate.go b/examples/import-mapping/multiplepackages/common/generate.go
new file mode 100644
index 0000000000..2e515e9342
--- /dev/null
+++ b/examples/import-mapping/multiplepackages/common/generate.go
@@ -0,0 +1,3 @@
+package common
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../common/api.yaml
diff --git a/examples/import-mapping/multiplepackages/common/types.gen.go b/examples/import-mapping/multiplepackages/common/types.gen.go
new file mode 100644
index 0000000000..178106064e
--- /dev/null
+++ b/examples/import-mapping/multiplepackages/common/types.gen.go
@@ -0,0 +1,9 @@
+// Package common provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package common
+
+// User defines model for User.
+type User struct {
+ Name string `json:"name"`
+}
diff --git a/examples/import-mapping/samepackage/cfg-api.yaml b/examples/import-mapping/samepackage/cfg-api.yaml
new file mode 100644
index 0000000000..76e2cb90a5
--- /dev/null
+++ b/examples/import-mapping/samepackage/cfg-api.yaml
@@ -0,0 +1,12 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: samepackage
+output: server.gen.go
+generate:
+ models: true
+ chi-server: true
+ strict-server: true
+output-options:
+ # to make sure that all types are generated
+ skip-prune: true
+import-mapping:
+ ../common/api.yaml: "-"
diff --git a/examples/import-mapping/samepackage/cfg-user.yaml b/examples/import-mapping/samepackage/cfg-user.yaml
new file mode 100644
index 0000000000..1e9d5bc39f
--- /dev/null
+++ b/examples/import-mapping/samepackage/cfg-user.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: samepackage
+output: user.gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated
+ skip-prune: true
diff --git a/examples/import-mapping/samepackage/generate.go b/examples/import-mapping/samepackage/generate.go
new file mode 100644
index 0000000000..cb4ceae468
--- /dev/null
+++ b/examples/import-mapping/samepackage/generate.go
@@ -0,0 +1,4 @@
+package samepackage
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg-api.yaml ../admin/api.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg-user.yaml ../common/api.yaml
diff --git a/examples/import-mapping/samepackage/server.gen.go b/examples/import-mapping/samepackage/server.gen.go
new file mode 100644
index 0000000000..22710b98d8
--- /dev/null
+++ b/examples/import-mapping/samepackage/server.gen.go
@@ -0,0 +1,272 @@
+// Package samepackage provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package samepackage
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ "github.com/go-chi/chi/v5"
+ "github.com/oapi-codegen/runtime"
+ openapi_types "github.com/oapi-codegen/runtime/types"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // Get a user's details
+ // (GET /admin/user/{id})
+ GetUserById(w http.ResponseWriter, r *http.Request, id openapi_types.UUID)
+}
+
+// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
+
+type Unimplemented struct{}
+
+// Get a user's details
+// (GET /admin/user/{id})
+func (_ Unimplemented) GetUserById(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetUserById operation middleware
+func (siw *ServerInterfaceWrapper) GetUserById(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id openapi_types.UUID
+
+ err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "uuid"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetUserById(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{})
+}
+
+type ChiServerOptions struct {
+ BaseURL string
+ BaseRouter chi.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = chi.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/admin/user/{id}", wrapper.GetUserById)
+ })
+
+ return r
+}
+
+type GetUserByIdRequestObject struct {
+ Id openapi_types.UUID `json:"id"`
+}
+
+type GetUserByIdResponseObject interface {
+ VisitGetUserByIdResponse(w http.ResponseWriter) error
+}
+
+type GetUserById200JSONResponse User
+
+func (response GetUserById200JSONResponse) VisitGetUserByIdResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+ // Get a user's details
+ // (GET /admin/user/{id})
+ GetUserById(ctx context.Context, request GetUserByIdRequestObject) (GetUserByIdResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// GetUserById operation middleware
+func (sh *strictHandler) GetUserById(w http.ResponseWriter, r *http.Request, id openapi_types.UUID) {
+ var request GetUserByIdRequestObject
+
+ request.Id = id
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetUserById(ctx, request.(GetUserByIdRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetUserById")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetUserByIdResponseObject); ok {
+ if err := validResponse.VisitGetUserByIdResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/examples/import-mapping/samepackage/user.gen.go b/examples/import-mapping/samepackage/user.gen.go
new file mode 100644
index 0000000000..46ab646a4f
--- /dev/null
+++ b/examples/import-mapping/samepackage/user.gen.go
@@ -0,0 +1,9 @@
+// Package samepackage provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package samepackage
+
+// User defines model for User.
+type User struct {
+ Name string `json:"name"`
+}
diff --git a/examples/minimal-server/api.yaml b/examples/minimal-server/api.yaml
new file mode 100644
index 0000000000..ccf4cd590e
--- /dev/null
+++ b/examples/minimal-server/api.yaml
@@ -0,0 +1,25 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Minimal ping API server
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
diff --git a/examples/minimal-server/chi/api/cfg.yaml b/examples/minimal-server/chi/api/cfg.yaml
new file mode 100644
index 0000000000..c5df9dd559
--- /dev/null
+++ b/examples/minimal-server/chi/api/cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: api
+output: ping.gen.go
+generate:
+ models: true
+ chi-server: true
diff --git a/examples/minimal-server/chi/api/generate.go b/examples/minimal-server/chi/api/generate.go
new file mode 100644
index 0000000000..386f093dc1
--- /dev/null
+++ b/examples/minimal-server/chi/api/generate.go
@@ -0,0 +1,3 @@
+package api
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../api.yaml
diff --git a/examples/minimal-server/chi/api/impl.go b/examples/minimal-server/chi/api/impl.go
new file mode 100644
index 0000000000..ddb3121e93
--- /dev/null
+++ b/examples/minimal-server/chi/api/impl.go
@@ -0,0 +1,25 @@
+package api
+
+import (
+ "encoding/json"
+ "net/http"
+)
+
+// ensure that we've conformed to the `ServerInterface` with a compile-time check
+var _ ServerInterface = (*Server)(nil)
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(resp)
+}
diff --git a/examples/minimal-server/chi/api/ping.gen.go b/examples/minimal-server/chi/api/ping.gen.go
new file mode 100644
index 0000000000..a2f368005a
--- /dev/null
+++ b/examples/minimal-server/chi/api/ping.gen.go
@@ -0,0 +1,175 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/go-chi/chi/v5"
+)
+
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(w http.ResponseWriter, r *http.Request)
+}
+
+// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
+
+type Unimplemented struct{}
+
+// (GET /ping)
+func (_ Unimplemented) GetPing(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetPing operation middleware
+func (siw *ServerInterfaceWrapper) GetPing(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetPing(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{})
+}
+
+type ChiServerOptions struct {
+ BaseURL string
+ BaseRouter chi.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = chi.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/ping", wrapper.GetPing)
+ })
+
+ return r
+}
diff --git a/examples/minimal-server/chi/main.go b/examples/minimal-server/chi/main.go
new file mode 100644
index 0000000000..56e0a0515e
--- /dev/null
+++ b/examples/minimal-server/chi/main.go
@@ -0,0 +1,27 @@
+package main
+
+import (
+ "log"
+ "net/http"
+
+ "github.com/go-chi/chi/v5"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/chi/api"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ r := chi.NewMux()
+
+ // get an `http.Handler` that we can use
+ h := api.HandlerFromMux(server, r)
+
+ s := &http.Server{
+ Handler: h,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
diff --git a/examples/minimal-server/echo/api/cfg.yaml b/examples/minimal-server/echo/api/cfg.yaml
new file mode 100644
index 0000000000..06bb9233e2
--- /dev/null
+++ b/examples/minimal-server/echo/api/cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: api
+output: ping.gen.go
+generate:
+ models: true
+ echo-server: true
diff --git a/examples/minimal-server/echo/api/generate.go b/examples/minimal-server/echo/api/generate.go
new file mode 100644
index 0000000000..386f093dc1
--- /dev/null
+++ b/examples/minimal-server/echo/api/generate.go
@@ -0,0 +1,3 @@
+package api
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../api.yaml
diff --git a/examples/minimal-server/echo/api/impl.go b/examples/minimal-server/echo/api/impl.go
new file mode 100644
index 0000000000..355c69bbae
--- /dev/null
+++ b/examples/minimal-server/echo/api/impl.go
@@ -0,0 +1,25 @@
+package api
+
+import (
+ "net/http"
+
+ "github.com/labstack/echo/v4"
+)
+
+// ensure that we've conformed to the `ServerInterface` with a compile-time check
+var _ ServerInterface = (*Server)(nil)
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(ctx echo.Context) error {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ return ctx.JSON(http.StatusOK, resp)
+}
diff --git a/examples/minimal-server/echo/api/ping.gen.go b/examples/minimal-server/echo/api/ping.gen.go
new file mode 100644
index 0000000000..e376e807d2
--- /dev/null
+++ b/examples/minimal-server/echo/api/ping.gen.go
@@ -0,0 +1,85 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "github.com/labstack/echo/v4"
+)
+
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(ctx echo.Context) error
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+// GetPing converts echo context to params.
+func (w *ServerInterfaceWrapper) GetPing(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetPing(ctx)
+ return err
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+}
+
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
+}
+
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.GET(options.BaseURL+"/ping", wrapper.GetPing, options.OperationMiddlewares["GetPing"]...)
+
+}
diff --git a/examples/minimal-server/echo/main.go b/examples/minimal-server/echo/main.go
new file mode 100644
index 0000000000..ae53667f3e
--- /dev/null
+++ b/examples/minimal-server/echo/main.go
@@ -0,0 +1,20 @@
+package main
+
+import (
+ "log"
+
+ "github.com/labstack/echo/v4"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/echo/api"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ e := echo.New()
+
+ api.RegisterHandlers(e, server)
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(e.Start("0.0.0.0:8080"))
+}
diff --git a/examples/minimal-server/fiber/api/cfg.yaml b/examples/minimal-server/fiber/api/cfg.yaml
new file mode 100644
index 0000000000..79b6e07ac1
--- /dev/null
+++ b/examples/minimal-server/fiber/api/cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: api
+output: ping.gen.go
+generate:
+ models: true
+ fiber-server: true
diff --git a/examples/minimal-server/fiber/api/generate.go b/examples/minimal-server/fiber/api/generate.go
new file mode 100644
index 0000000000..386f093dc1
--- /dev/null
+++ b/examples/minimal-server/fiber/api/generate.go
@@ -0,0 +1,3 @@
+package api
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../api.yaml
diff --git a/examples/minimal-server/fiber/api/impl.go b/examples/minimal-server/fiber/api/impl.go
new file mode 100644
index 0000000000..20bcf8478f
--- /dev/null
+++ b/examples/minimal-server/fiber/api/impl.go
@@ -0,0 +1,27 @@
+package api
+
+import (
+ "net/http"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+// ensure that we've conformed to the `ServerInterface` with a compile-time check
+var _ ServerInterface = (*Server)(nil)
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(ctx *fiber.Ctx) error {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ return ctx.
+ Status(http.StatusOK).
+ JSON(resp)
+}
diff --git a/examples/minimal-server/fiber/api/ping.gen.go b/examples/minimal-server/fiber/api/ping.gen.go
new file mode 100644
index 0000000000..b926f841bb
--- /dev/null
+++ b/examples/minimal-server/fiber/api/ping.gen.go
@@ -0,0 +1,74 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "github.com/gofiber/fiber/v2"
+)
+
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(c *fiber.Ctx) error
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []HandlerMiddlewareFunc
+}
+
+type MiddlewareFunc fiber.Handler
+type HandlerMiddlewareFunc func(c *fiber.Ctx, next fiber.Handler) error
+
+// GetPing operation middleware
+func (siw *ServerInterfaceWrapper) GetPing(c *fiber.Ctx) error {
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetPing(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// FiberServerOptions provides options for the Fiber server.
+type FiberServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ HandlerMiddlewares []HandlerMiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router fiber.Router, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, FiberServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.HandlerMiddlewares,
+ }
+
+ for _, m := range options.Middlewares {
+ router.Use(fiber.Handler(m))
+ }
+
+ router.Get(options.BaseURL+"/ping", wrapper.GetPing)
+
+}
diff --git a/examples/minimal-server/fiber/main.go b/examples/minimal-server/fiber/main.go
new file mode 100644
index 0000000000..88504af7be
--- /dev/null
+++ b/examples/minimal-server/fiber/main.go
@@ -0,0 +1,20 @@
+package main
+
+import (
+ "log"
+
+ "github.com/gofiber/fiber/v2"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/fiber/api"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ app := fiber.New()
+
+ api.RegisterHandlers(app, server)
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(app.Listen("0.0.0.0:8080"))
+}
diff --git a/examples/minimal-server/gin/api/cfg.yaml b/examples/minimal-server/gin/api/cfg.yaml
new file mode 100644
index 0000000000..951cb3f6bc
--- /dev/null
+++ b/examples/minimal-server/gin/api/cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: api
+output: ping.gen.go
+generate:
+ models: true
+ gin-server: true
diff --git a/examples/minimal-server/gin/api/generate.go b/examples/minimal-server/gin/api/generate.go
new file mode 100644
index 0000000000..386f093dc1
--- /dev/null
+++ b/examples/minimal-server/gin/api/generate.go
@@ -0,0 +1,3 @@
+package api
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../api.yaml
diff --git a/examples/minimal-server/gin/api/impl.go b/examples/minimal-server/gin/api/impl.go
new file mode 100644
index 0000000000..663105193f
--- /dev/null
+++ b/examples/minimal-server/gin/api/impl.go
@@ -0,0 +1,25 @@
+package api
+
+import (
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+)
+
+// ensure that we've conformed to the `ServerInterface` with a compile-time check
+var _ ServerInterface = (*Server)(nil)
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(ctx *gin.Context) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ ctx.JSON(http.StatusOK, resp)
+}
diff --git a/examples/minimal-server/gin/api/ping.gen.go b/examples/minimal-server/gin/api/ping.gen.go
new file mode 100644
index 0000000000..8e018d4e89
--- /dev/null
+++ b/examples/minimal-server/gin/api/ping.gen.go
@@ -0,0 +1,72 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "github.com/gin-gonic/gin"
+)
+
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(c *gin.Context)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandler func(*gin.Context, error, int)
+}
+
+type MiddlewareFunc func(c *gin.Context)
+
+// GetPing operation middleware
+func (siw *ServerInterfaceWrapper) GetPing(c *gin.Context) {
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetPing(c)
+}
+
+// GinServerOptions provides options for the Gin server.
+type GinServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ ErrorHandler func(*gin.Context, error, int)
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router gin.IRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, GinServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) {
+ errorHandler := options.ErrorHandler
+ if errorHandler == nil {
+ errorHandler = func(c *gin.Context, err error, statusCode int) {
+ c.JSON(statusCode, gin.H{"msg": err.Error()})
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandler: errorHandler,
+ }
+
+ router.GET(options.BaseURL+"/ping", wrapper.GetPing)
+}
diff --git a/examples/minimal-server/gin/main.go b/examples/minimal-server/gin/main.go
new file mode 100644
index 0000000000..365932e313
--- /dev/null
+++ b/examples/minimal-server/gin/main.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+ "log"
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/gin/api"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ r := gin.Default()
+
+ api.RegisterHandlers(r, server)
+
+ // And we serve HTTP until the world ends.
+
+ s := &http.Server{
+ Handler: r,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
diff --git a/examples/minimal-server/gorillamux/api/cfg.yaml b/examples/minimal-server/gorillamux/api/cfg.yaml
new file mode 100644
index 0000000000..f68fe1c11d
--- /dev/null
+++ b/examples/minimal-server/gorillamux/api/cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: api
+output: ping.gen.go
+generate:
+ models: true
+ gorilla-server: true
diff --git a/examples/minimal-server/gorillamux/api/generate.go b/examples/minimal-server/gorillamux/api/generate.go
new file mode 100644
index 0000000000..386f093dc1
--- /dev/null
+++ b/examples/minimal-server/gorillamux/api/generate.go
@@ -0,0 +1,3 @@
+package api
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../api.yaml
diff --git a/examples/minimal-server/gorillamux/api/impl.go b/examples/minimal-server/gorillamux/api/impl.go
new file mode 100644
index 0000000000..ddb3121e93
--- /dev/null
+++ b/examples/minimal-server/gorillamux/api/impl.go
@@ -0,0 +1,25 @@
+package api
+
+import (
+ "encoding/json"
+ "net/http"
+)
+
+// ensure that we've conformed to the `ServerInterface` with a compile-time check
+var _ ServerInterface = (*Server)(nil)
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(resp)
+}
diff --git a/examples/minimal-server/gorillamux/api/ping.gen.go b/examples/minimal-server/gorillamux/api/ping.gen.go
new file mode 100644
index 0000000000..82ec6ebb5d
--- /dev/null
+++ b/examples/minimal-server/gorillamux/api/ping.gen.go
@@ -0,0 +1,164 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/gorilla/mux"
+)
+
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(w http.ResponseWriter, r *http.Request)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetPing operation middleware
+func (siw *ServerInterfaceWrapper) GetPing(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetPing(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+ BaseURL string
+ BaseRouter *mux.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = mux.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.HandleFunc(options.BaseURL+"/ping", wrapper.GetPing).Methods(http.MethodGet)
+
+ return r
+}
diff --git a/examples/minimal-server/gorillamux/main.go b/examples/minimal-server/gorillamux/main.go
new file mode 100644
index 0000000000..5d7dc87f7f
--- /dev/null
+++ b/examples/minimal-server/gorillamux/main.go
@@ -0,0 +1,27 @@
+package main
+
+import (
+ "log"
+ "net/http"
+
+ "github.com/gorilla/mux"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/gorillamux/api"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ r := mux.NewRouter()
+
+ // get an `http.Handler` that we can use
+ h := api.HandlerFromMux(server, r)
+
+ s := &http.Server{
+ Handler: h,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
diff --git a/examples/minimal-server/iris/api/cfg.yaml b/examples/minimal-server/iris/api/cfg.yaml
new file mode 100644
index 0000000000..1f83520f7e
--- /dev/null
+++ b/examples/minimal-server/iris/api/cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: api
+output: ping.gen.go
+generate:
+ models: true
+ iris-server: true
diff --git a/examples/minimal-server/iris/api/generate.go b/examples/minimal-server/iris/api/generate.go
new file mode 100644
index 0000000000..386f093dc1
--- /dev/null
+++ b/examples/minimal-server/iris/api/generate.go
@@ -0,0 +1,3 @@
+package api
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../api.yaml
diff --git a/examples/minimal-server/iris/api/impl.go b/examples/minimal-server/iris/api/impl.go
new file mode 100644
index 0000000000..4adbd04b3b
--- /dev/null
+++ b/examples/minimal-server/iris/api/impl.go
@@ -0,0 +1,26 @@
+package api
+
+import (
+ "net/http"
+
+ "github.com/kataras/iris/v12"
+)
+
+// ensure that we've conformed to the `ServerInterface` with a compile-time check
+var _ ServerInterface = (*Server)(nil)
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(ctx iris.Context) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ ctx.StatusCode(http.StatusOK)
+ _ = ctx.JSON(resp)
+}
diff --git a/examples/minimal-server/iris/api/ping.gen.go b/examples/minimal-server/iris/api/ping.gen.go
new file mode 100644
index 0000000000..144166eba2
--- /dev/null
+++ b/examples/minimal-server/iris/api/ping.gen.go
@@ -0,0 +1,57 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "github.com/kataras/iris/v12"
+)
+
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(ctx iris.Context)
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+type MiddlewareFunc iris.Handler
+
+// GetPing converts iris context to params.
+func (w *ServerInterfaceWrapper) GetPing(ctx iris.Context) {
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetPing(ctx)
+}
+
+// IrisServerOption is the option for iris server
+type IrisServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router *iris.Application, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, IrisServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router *iris.Application, si ServerInterface, options IrisServerOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.Get(options.BaseURL+"/ping", wrapper.GetPing)
+
+ router.Build()
+}
diff --git a/examples/minimal-server/iris/main.go b/examples/minimal-server/iris/main.go
new file mode 100644
index 0000000000..a163d6f598
--- /dev/null
+++ b/examples/minimal-server/iris/main.go
@@ -0,0 +1,20 @@
+package main
+
+import (
+ "log"
+
+ "github.com/kataras/iris/v12"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/iris/api"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ i := iris.Default()
+
+ api.RegisterHandlers(i, server)
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(i.Listen("0.0.0.0:8080"))
+}
diff --git a/examples/minimal-server/nethttp-compatible/main.go b/examples/minimal-server/nethttp-compatible/main.go
new file mode 100644
index 0000000000..784b741cf0
--- /dev/null
+++ b/examples/minimal-server/nethttp-compatible/main.go
@@ -0,0 +1,24 @@
+package main
+
+import (
+ "log"
+ "net/http"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/gorillamux/api"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ // get an `http.Handler` that we can use, but notice that we don't need to specify the router (although under-the-hood it'll use the generated router)
+ h := api.Handler(server)
+
+ s := &http.Server{
+ Handler: h,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
diff --git a/examples/minimal-server/stdhttp-go-tool/api/cfg.yaml b/examples/minimal-server/stdhttp-go-tool/api/cfg.yaml
new file mode 100644
index 0000000000..4369e342f4
--- /dev/null
+++ b/examples/minimal-server/stdhttp-go-tool/api/cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: api
+output: ping.gen.go
+generate:
+ models: true
+ std-http-server: true
diff --git a/examples/minimal-server/stdhttp-go-tool/api/generate.go b/examples/minimal-server/stdhttp-go-tool/api/generate.go
new file mode 100644
index 0000000000..8b01fe5ccc
--- /dev/null
+++ b/examples/minimal-server/stdhttp-go-tool/api/generate.go
@@ -0,0 +1,3 @@
+package api
+
+//go:generate go tool oapi-codegen -config cfg.yaml ../../api.yaml
diff --git a/examples/minimal-server/stdhttp-go-tool/api/impl.go b/examples/minimal-server/stdhttp-go-tool/api/impl.go
new file mode 100644
index 0000000000..ddb3121e93
--- /dev/null
+++ b/examples/minimal-server/stdhttp-go-tool/api/impl.go
@@ -0,0 +1,25 @@
+package api
+
+import (
+ "encoding/json"
+ "net/http"
+)
+
+// ensure that we've conformed to the `ServerInterface` with a compile-time check
+var _ ServerInterface = (*Server)(nil)
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(resp)
+}
diff --git a/examples/minimal-server/stdhttp-go-tool/api/ping.gen.go b/examples/minimal-server/stdhttp-go-tool/api/ping.gen.go
new file mode 100644
index 0000000000..0d4ab7751a
--- /dev/null
+++ b/examples/minimal-server/stdhttp-go-tool/api/ping.gen.go
@@ -0,0 +1,171 @@
+//go:build go1.22
+
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "fmt"
+ "net/http"
+)
+
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(w http.ResponseWriter, r *http.Request)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetPing operation middleware
+func (siw *ServerInterfaceWrapper) GetPing(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetPing(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{})
+}
+
+// ServeMux is an abstraction of [http.ServeMux].
+type ServeMux interface {
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+ http.Handler
+}
+
+type StdHTTPServerOptions struct {
+ BaseURL string
+ BaseRouter ServeMux
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/ping", wrapper.GetPing)
+
+ return m
+}
diff --git a/examples/minimal-server/stdhttp-go-tool/main.go b/examples/minimal-server/stdhttp-go-tool/main.go
new file mode 100644
index 0000000000..2fa48f1bf3
--- /dev/null
+++ b/examples/minimal-server/stdhttp-go-tool/main.go
@@ -0,0 +1,26 @@
+package main
+
+import (
+ "log"
+ "net/http"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/stdhttp-go-tool/api"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ r := http.NewServeMux()
+
+ // get an `http.Handler` that we can use
+ h := api.HandlerFromMux(server, r)
+
+ s := &http.Server{
+ Handler: h,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
diff --git a/examples/minimal-server/stdhttp/api/cfg.yaml b/examples/minimal-server/stdhttp/api/cfg.yaml
new file mode 100644
index 0000000000..4369e342f4
--- /dev/null
+++ b/examples/minimal-server/stdhttp/api/cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: api
+output: ping.gen.go
+generate:
+ models: true
+ std-http-server: true
diff --git a/examples/minimal-server/stdhttp/api/generate.go b/examples/minimal-server/stdhttp/api/generate.go
new file mode 100644
index 0000000000..386f093dc1
--- /dev/null
+++ b/examples/minimal-server/stdhttp/api/generate.go
@@ -0,0 +1,3 @@
+package api
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../api.yaml
diff --git a/examples/minimal-server/stdhttp/api/impl.go b/examples/minimal-server/stdhttp/api/impl.go
new file mode 100644
index 0000000000..ddb3121e93
--- /dev/null
+++ b/examples/minimal-server/stdhttp/api/impl.go
@@ -0,0 +1,25 @@
+package api
+
+import (
+ "encoding/json"
+ "net/http"
+)
+
+// ensure that we've conformed to the `ServerInterface` with a compile-time check
+var _ ServerInterface = (*Server)(nil)
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
+ resp := Pong{
+ Ping: "pong",
+ }
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(resp)
+}
diff --git a/examples/minimal-server/stdhttp/api/ping.gen.go b/examples/minimal-server/stdhttp/api/ping.gen.go
new file mode 100644
index 0000000000..0d4ab7751a
--- /dev/null
+++ b/examples/minimal-server/stdhttp/api/ping.gen.go
@@ -0,0 +1,171 @@
+//go:build go1.22
+
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "fmt"
+ "net/http"
+)
+
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(w http.ResponseWriter, r *http.Request)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetPing operation middleware
+func (siw *ServerInterfaceWrapper) GetPing(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetPing(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{})
+}
+
+// ServeMux is an abstraction of [http.ServeMux].
+type ServeMux interface {
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+ http.Handler
+}
+
+type StdHTTPServerOptions struct {
+ BaseURL string
+ BaseRouter ServeMux
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/ping", wrapper.GetPing)
+
+ return m
+}
diff --git a/examples/minimal-server/stdhttp/main.go b/examples/minimal-server/stdhttp/main.go
new file mode 100644
index 0000000000..8ee94ec49f
--- /dev/null
+++ b/examples/minimal-server/stdhttp/main.go
@@ -0,0 +1,26 @@
+package main
+
+import (
+ "log"
+ "net/http"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/stdhttp/api"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ r := http.NewServeMux()
+
+ // get an `http.Handler` that we can use
+ h := api.HandlerFromMux(server, r)
+
+ s := &http.Server{
+ Handler: h,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
diff --git a/examples/minimal-server/stdhttp/tools/tools.go b/examples/minimal-server/stdhttp/tools/tools.go
new file mode 100644
index 0000000000..8615cb4c57
--- /dev/null
+++ b/examples/minimal-server/stdhttp/tools/tools.go
@@ -0,0 +1,8 @@
+//go:build tools
+// +build tools
+
+package tools
+
+import (
+ _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen"
+)
diff --git a/examples/no-vcs-version-override/echo/api/api.gen.go b/examples/no-vcs-version-override/echo/api/api.gen.go
index 421870cb2f..0d70421505 100644
--- a/examples/no-vcs-version-override/echo/api/api.gen.go
+++ b/examples/no-vcs-version-override/echo/api/api.gen.go
@@ -1,6 +1,6 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v123.456.789 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v123.456.789 DO NOT EDIT.
package api
import (
@@ -43,19 +43,38 @@ type EchoRouter interface {
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
}
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
- router.GET(baseURL+"/nothing", wrapper.GetNothing)
+ router.GET(options.BaseURL+"/nothing", wrapper.GetNothing, options.OperationMiddlewares["getNothing"]...)
}
diff --git a/examples/no-vcs-version-override/echo/api/config.yaml b/examples/no-vcs-version-override/echo/api/config.yaml
index 00bb9c1a2d..1f6140c6e4 100644
--- a/examples/no-vcs-version-override/echo/api/config.yaml
+++ b/examples/no-vcs-version-override/echo/api/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
echo-server: true
diff --git a/examples/no-vcs-version-override/echo/api/doc.go b/examples/no-vcs-version-override/echo/api/doc.go
index 991e3e6e9d..03f5a0318f 100644
--- a/examples/no-vcs-version-override/echo/api/doc.go
+++ b/examples/no-vcs-version-override/echo/api/doc.go
@@ -1,3 +1,3 @@
package api
-//go:generate go run -ldflags "-X main.noVCSVersionOverride=v123.456.789" github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml ../../api.yaml
+//go:generate go run -ldflags "-X main.noVCSVersionOverride=v123.456.789" github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../../api.yaml
diff --git a/examples/only-models/api.yaml b/examples/only-models/api.yaml
new file mode 100644
index 0000000000..33820e8f0b
--- /dev/null
+++ b/examples/only-models/api.yaml
@@ -0,0 +1,50 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Generate models
+paths:
+ /client:
+ get:
+ operationId: getClient
+ responses:
+ 200:
+ content:
+ application/json:
+ schema:
+ # NOTE that Client is generated here, because it's within #/components/schemas
+ $ref: "#/components/schemas/Client"
+ put:
+ operationId: updateClient
+ responses:
+ 400:
+ content:
+ application/json:
+ # NOTE that this anonymous object is /not/ generated because it's an anonymous, but would be generated if using `generate: client`
+ # See https://github.com/oapi-codegen/oapi-codegen/issues/1512
+ schema:
+ type: object
+ properties:
+ code:
+ type: string
+ required:
+ - code
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ # NOTE that this is not generated by default because it's not referenced. If you want it, you need to use the following YAML configuration:
+ #
+ # output-options:
+ # skip-prune: true
+ Unreferenced:
+ type: object
+ required:
+ - id
+ properties:
+ id:
+ type: integer
diff --git a/examples/only-models/cfg.yaml b/examples/only-models/cfg.yaml
new file mode 100644
index 0000000000..01f4745bb7
--- /dev/null
+++ b/examples/only-models/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../configuration-schema.json
+package: onlymodels
+output: only-models.gen.go
+generate:
+ models: true
+output-options:
+ # NOTE that this is only required for the `Unreferenced` type
+ skip-prune: true
diff --git a/examples/only-models/generate.go b/examples/only-models/generate.go
new file mode 100644
index 0000000000..91b4957257
--- /dev/null
+++ b/examples/only-models/generate.go
@@ -0,0 +1,3 @@
+package onlymodels
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/only-models/only-models.gen.go b/examples/only-models/only-models.gen.go
new file mode 100644
index 0000000000..c8f33c9c8f
--- /dev/null
+++ b/examples/only-models/only-models.gen.go
@@ -0,0 +1,14 @@
+// Package onlymodels provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package onlymodels
+
+// Client defines model for Client.
+type Client struct {
+ Name string `json:"name"`
+}
+
+// Unreferenced defines model for Unreferenced.
+type Unreferenced struct {
+ Id int `json:"id"`
+}
diff --git a/examples/output-options/additionalinitialisms/api.yaml b/examples/output-options/additionalinitialisms/api.yaml
new file mode 100644
index 0000000000..fbad3fc0c7
--- /dev/null
+++ b/examples/output-options/additionalinitialisms/api.yaml
@@ -0,0 +1,14 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: additional-initialisms
+components:
+ schemas:
+ Request:
+ type: object
+ required:
+ - csp_name
+ properties:
+ csp_name:
+ description: The Cloud Service Provider's name.
+ type: string
diff --git a/examples/output-options/additionalinitialisms/cfg.yaml b/examples/output-options/additionalinitialisms/cfg.yaml
new file mode 100644
index 0000000000..9893d89ca0
--- /dev/null
+++ b/examples/output-options/additionalinitialisms/cfg.yaml
@@ -0,0 +1,11 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: additionalinitialisms
+output: gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
+ name-normalizer: ToCamelCaseWithInitialisms
+ additional-initialisms:
+ - CSP
diff --git a/examples/output-options/additionalinitialisms/gen.go b/examples/output-options/additionalinitialisms/gen.go
new file mode 100644
index 0000000000..950535b77b
--- /dev/null
+++ b/examples/output-options/additionalinitialisms/gen.go
@@ -0,0 +1,10 @@
+// Package additionalinitialisms provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package additionalinitialisms
+
+// Request defines model for Request.
+type Request struct {
+ // CSPName The Cloud Service Provider's name.
+ CSPName string `json:"csp_name"`
+}
diff --git a/examples/output-options/additionalinitialisms/generate.go b/examples/output-options/additionalinitialisms/generate.go
new file mode 100644
index 0000000000..5b6ed9ea57
--- /dev/null
+++ b/examples/output-options/additionalinitialisms/generate.go
@@ -0,0 +1,3 @@
+package additionalinitialisms
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/output-options/preferskipoptionalpointer/api.yaml b/examples/output-options/preferskipoptionalpointer/api.yaml
new file mode 100644
index 0000000000..8903309983
--- /dev/null
+++ b/examples/output-options/preferskipoptionalpointer/api.yaml
@@ -0,0 +1,67 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: prefer-skip-optional-pointer
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ description: This field is required, so will never have an optional pointer.
+ type: string
+ id:
+ description: This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer.
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ description: This field is required, so will never have an optional pointer.
+ type: string
+ id:
+ description: This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer.
+ type: number
+ pointer_id:
+ type: number
+ description: This field should have an optional pointer, as the field-level definition of `x-go-type-skip-optional-pointer` overrides the `prefer-skip-optional-pointer` Output Option.
+ # NOTE that this overrides the global preference
+ x-go-type-skip-optional-pointer: false
+ NestedType:
+ type: object
+ properties:
+ client:
+ description: This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer.
+ $ref: '#/components/schemas/Client'
+ ReferencesATypeWithAnExtensionInsideAllOf:
+ type: object
+ description: This type has a field which references - via an `allOf` - a type which should have an optional pointer, as the field-level definition of `x-go-type-skip-optional-pointer` overrides the `prefer-skip-optional-pointer` Output Option, as well as a field without that property.
+ additionalProperties: false
+ required:
+ - description
+ properties:
+ noExtension:
+ # NOTE this will not generate pointer type as global preference `prefer-skip-optional-pointer: true`
+ allOf:
+ - $ref: '#/components/schemas/ReferencedWithoutExtension'
+ withExtensionPointer:
+ # NOTE this will generate pointer type (despite global preference `prefer-skip-optional-pointer: true`) as we have field-level `x-go-type-skip-optional-pointer: false`
+ allOf:
+ - $ref: '#/components/schemas/ReferencedWithExtension'
+ ReferencedWithoutExtension:
+ type: object
+ additionalProperties: false
+ properties:
+ foo:
+ type: string
+ ReferencedWithExtension:
+ type: object
+ additionalProperties: false
+ properties:
+ foo:
+ type: string
+ x-go-type-skip-optional-pointer: false
diff --git a/examples/output-options/preferskipoptionalpointer/cfg.yaml b/examples/output-options/preferskipoptionalpointer/cfg.yaml
new file mode 100644
index 0000000000..ae49d9a943
--- /dev/null
+++ b/examples/output-options/preferskipoptionalpointer/cfg.yaml
@@ -0,0 +1,9 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: preferskipoptionalpointer
+output: gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
+ prefer-skip-optional-pointer: true
diff --git a/examples/output-options/preferskipoptionalpointer/gen.go b/examples/output-options/preferskipoptionalpointer/gen.go
new file mode 100644
index 0000000000..623bf9455f
--- /dev/null
+++ b/examples/output-options/preferskipoptionalpointer/gen.go
@@ -0,0 +1,46 @@
+// Package preferskipoptionalpointer provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package preferskipoptionalpointer
+
+// Client defines model for Client.
+type Client struct {
+ // Id This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer.
+ Id float32 `json:"id,omitempty"`
+
+ // Name This field is required, so will never have an optional pointer.
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ // Id This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer.
+ Id float32 `json:"id,omitempty"`
+
+ // Name This field is required, so will never have an optional pointer.
+ Name string `json:"name"`
+
+ // PointerId This field should have an optional pointer, as the field-level definition of `x-go-type-skip-optional-pointer` overrides the `prefer-skip-optional-pointer` Output Option.
+ PointerId *float32 `json:"pointer_id,omitempty"`
+}
+
+// NestedType defines model for NestedType.
+type NestedType struct {
+ Client Client `json:"client,omitempty"`
+}
+
+// ReferencedWithExtension defines model for ReferencedWithExtension.
+type ReferencedWithExtension struct {
+ Foo string `json:"foo,omitempty"`
+}
+
+// ReferencedWithoutExtension defines model for ReferencedWithoutExtension.
+type ReferencedWithoutExtension struct {
+ Foo string `json:"foo,omitempty"`
+}
+
+// ReferencesATypeWithAnExtensionInsideAllOf This type has a field which references - via an `allOf` - a type which should have an optional pointer, as the field-level definition of `x-go-type-skip-optional-pointer` overrides the `prefer-skip-optional-pointer` Output Option, as well as a field without that property.
+type ReferencesATypeWithAnExtensionInsideAllOf struct {
+ NoExtension ReferencedWithoutExtension `json:"noExtension,omitempty"`
+ WithExtensionPointer *ReferencedWithExtension `json:"withExtensionPointer,omitempty"`
+}
diff --git a/examples/output-options/preferskipoptionalpointer/gen_test.go b/examples/output-options/preferskipoptionalpointer/gen_test.go
new file mode 100644
index 0000000000..3a5f5b4ed8
--- /dev/null
+++ b/examples/output-options/preferskipoptionalpointer/gen_test.go
@@ -0,0 +1,127 @@
+package preferskipoptionalpointer
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestClient(t *testing.T) {
+ t.Run("zero value (empty string) on Name is not omitted", func(t *testing.T) {
+ client := Client{
+ Name: "",
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "name"))
+ })
+
+ t.Run("value on Name is not omitted", func(t *testing.T) {
+ client := Client{
+ Name: "some value",
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "name"))
+ })
+
+ t.Run("zero value (0.0) on Id is omitted (as `omitempty` flags it as empty)", func(t *testing.T) {
+ client := Client{
+ Id: 0.0,
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.False(t, jsonContainsKey(b, "id"))
+ })
+
+ t.Run("value on Id is not omitted", func(t *testing.T) {
+ client := Client{
+ Id: 3.142,
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "id"))
+ })
+}
+
+func TestNestedType(t *testing.T) {
+ t.Run("zero value (empty struct) on Client is not omitted", func(t *testing.T) {
+ nestedType := NestedType{
+ Client: Client{},
+ }
+
+ b, err := json.Marshal(nestedType)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "client"))
+ })
+
+ t.Run("value on Client is not omitted", func(t *testing.T) {
+ nestedType := NestedType{
+ Client: Client{
+ Name: "foo",
+ },
+ }
+
+ b, err := json.Marshal(nestedType)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "client"))
+ })
+}
+
+func TestReferencesATypeWithAnExtension(t *testing.T) {
+ t.Run("zero value", func(t *testing.T) {
+ typeWithExt := ReferencesATypeWithAnExtensionInsideAllOf{}
+
+ assert.Zero(t, typeWithExt)
+ assert.Zero(t, typeWithExt.NoExtension)
+ assert.Nil(t, typeWithExt.WithExtensionPointer)
+ })
+
+ t.Run("value on noExtension", func(t *testing.T) {
+ typeWithExt := ReferencesATypeWithAnExtensionInsideAllOf{
+ NoExtension: ReferencedWithoutExtension{"value"},
+ WithExtensionPointer: nil,
+ }
+
+ b, err := json.Marshal(typeWithExt)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "noExtension"))
+ assert.False(t, jsonContainsKey(b, "withExtensionPointer"))
+ })
+
+ t.Run("value on noExtension and withExtensionPointer", func(t *testing.T) {
+ typeWithExt := ReferencesATypeWithAnExtensionInsideAllOf{
+ NoExtension: ReferencedWithoutExtension{"value"},
+ WithExtensionPointer: &ReferencedWithExtension{"ptrValue"},
+ }
+
+ b, err := json.Marshal(typeWithExt)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "noExtension"))
+ assert.True(t, jsonContainsKey(b, "withExtensionPointer"))
+ })
+}
+
+// jsonContainsKey checks if the given JSON object contains the specified key at the top level.
+func jsonContainsKey(b []byte, key string) bool {
+ var m map[string]any
+ if err := json.Unmarshal(b, &m); err != nil {
+ return false
+ }
+ _, ok := m[key]
+ return ok
+}
diff --git a/examples/output-options/preferskipoptionalpointer/generate.go b/examples/output-options/preferskipoptionalpointer/generate.go
new file mode 100644
index 0000000000..4733fe3fe2
--- /dev/null
+++ b/examples/output-options/preferskipoptionalpointer/generate.go
@@ -0,0 +1,3 @@
+package preferskipoptionalpointer
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/api.yaml b/examples/output-options/preferskipoptionalpointerwithomitzero/api.yaml
new file mode 100644
index 0000000000..d43ae9ff1f
--- /dev/null
+++ b/examples/output-options/preferskipoptionalpointerwithomitzero/api.yaml
@@ -0,0 +1,44 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: prefer-skip-optional-pointer-with-omitzero
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ description: This field is required, so will never have an optional pointer, nor `omitzero`.
+ type: string
+ id:
+ description: This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer. However, it will receive `omitzero`.
+ type: number
+ ClientWithExtension:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ description: This field is required, so will never have an optional pointer, nor `omitzero`.
+ type: string
+ id:
+ description: This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer. However, it will receive `omitzero`.
+ type: number
+ pointer_id:
+ type: number
+ description: This field should have an optional pointer, as the field-level definition of `x-go-type-skip-optional-pointer` overrides the `prefer-skip-optional-pointer` Output Option. This will also not receive an `omitzero`.
+ # NOTE that this overrides the global preference
+ x-go-type-skip-optional-pointer: false
+ no_omit:
+ type: number
+ description: This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer. This will not receive `omitzero`, as the field-level definition of `x-omitzero` overrides the `prefer-skip-optional-pointer-with-omitzero` Output Option.
+ # NOTE that this overrides the global preference
+ x-omitzero: false
+ NestedType:
+ type: object
+ properties:
+ client:
+ description: This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer.
+ $ref: '#/components/schemas/Client'
diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/cfg.yaml b/examples/output-options/preferskipoptionalpointerwithomitzero/cfg.yaml
new file mode 100644
index 0000000000..030c49c472
--- /dev/null
+++ b/examples/output-options/preferskipoptionalpointerwithomitzero/cfg.yaml
@@ -0,0 +1,10 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: preferskipoptionalpointerwithomitzero
+output: gen.go
+generate:
+ models: true
+output-options:
+ # to make sure that all types are generated, even if they're unreferenced
+ skip-prune: true
+ prefer-skip-optional-pointer: true
+ prefer-skip-optional-pointer-with-omitzero: true
diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/gen.go b/examples/output-options/preferskipoptionalpointerwithomitzero/gen.go
new file mode 100644
index 0000000000..6ea8dc2576
--- /dev/null
+++ b/examples/output-options/preferskipoptionalpointerwithomitzero/gen.go
@@ -0,0 +1,33 @@
+// Package preferskipoptionalpointerwithomitzero provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package preferskipoptionalpointerwithomitzero
+
+// Client defines model for Client.
+type Client struct {
+ // Id This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer. However, it will receive `omitzero`.
+ Id float32 `json:"id,omitempty,omitzero"`
+
+ // Name This field is required, so will never have an optional pointer, nor `omitzero`.
+ Name string `json:"name"`
+}
+
+// ClientWithExtension defines model for ClientWithExtension.
+type ClientWithExtension struct {
+ // Id This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer. However, it will receive `omitzero`.
+ Id float32 `json:"id,omitempty,omitzero"`
+
+ // Name This field is required, so will never have an optional pointer, nor `omitzero`.
+ Name string `json:"name"`
+
+ // NoOmit This field is optional, but the `prefer-skip-optional-pointer` Output Option ensures that this should not have an optional pointer. This will not receive `omitzero`, as the field-level definition of `x-omitzero` overrides the `prefer-skip-optional-pointer-with-omitzero` Output Option.
+ NoOmit float32 `json:"no_omit,omitempty"`
+
+ // PointerId This field should have an optional pointer, as the field-level definition of `x-go-type-skip-optional-pointer` overrides the `prefer-skip-optional-pointer` Output Option. This will also not receive an `omitzero`.
+ PointerId *float32 `json:"pointer_id,omitempty"`
+}
+
+// NestedType defines model for NestedType.
+type NestedType struct {
+ Client Client `json:"client,omitempty,omitzero"`
+}
diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/gen_test.go b/examples/output-options/preferskipoptionalpointerwithomitzero/gen_test.go
new file mode 100644
index 0000000000..d591e28616
--- /dev/null
+++ b/examples/output-options/preferskipoptionalpointerwithomitzero/gen_test.go
@@ -0,0 +1,91 @@
+package preferskipoptionalpointerwithomitzero
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestClient(t *testing.T) {
+ t.Run("zero value (empty string) on Name is not omitted", func(t *testing.T) {
+ client := Client{
+ Name: "",
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "name"))
+ })
+
+ t.Run("value on Name is not omitted", func(t *testing.T) {
+ client := Client{
+ Name: "some value",
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "name"))
+ })
+
+ t.Run("zero value (0.0) on Id is omitted (as `omitempty` and/or `omitzero` flags it as empty)", func(t *testing.T) {
+ client := Client{
+ Id: 0.0,
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.False(t, jsonContainsKey(b, "id"))
+ })
+
+ t.Run("value on Id is not omitted", func(t *testing.T) {
+ client := Client{
+ Id: 3.142,
+ }
+
+ b, err := json.Marshal(client)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "id"))
+ })
+}
+
+func TestNestedType(t *testing.T) {
+ t.Run("zero value (empty struct) on Client is omitted", func(t *testing.T) {
+ nestedType := NestedType{
+ Client: Client{},
+ }
+
+ b, err := json.Marshal(nestedType)
+ require.NoError(t, err)
+
+ assert.False(t, jsonContainsKey(b, "client"))
+ })
+
+ t.Run("value on Client is not omitted", func(t *testing.T) {
+ nestedType := NestedType{
+ Client: Client{
+ Name: "foo",
+ },
+ }
+
+ b, err := json.Marshal(nestedType)
+ require.NoError(t, err)
+
+ assert.True(t, jsonContainsKey(b, "client"))
+ })
+}
+
+// jsonContainsKey checks if the given JSON object contains the specified key at the top level.
+func jsonContainsKey(b []byte, key string) bool {
+ var m map[string]any
+ if err := json.Unmarshal(b, &m); err != nil {
+ return false
+ }
+ _, ok := m[key]
+ return ok
+}
diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/generate.go b/examples/output-options/preferskipoptionalpointerwithomitzero/generate.go
new file mode 100644
index 0000000000..08c93968c1
--- /dev/null
+++ b/examples/output-options/preferskipoptionalpointerwithomitzero/generate.go
@@ -0,0 +1,3 @@
+package preferskipoptionalpointerwithomitzero
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/output-options/preferskipoptionalpointerwithomitzero/tools/tools.go b/examples/output-options/preferskipoptionalpointerwithomitzero/tools/tools.go
new file mode 100644
index 0000000000..8615cb4c57
--- /dev/null
+++ b/examples/output-options/preferskipoptionalpointerwithomitzero/tools/tools.go
@@ -0,0 +1,8 @@
+//go:build tools
+// +build tools
+
+package tools
+
+import (
+ _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen"
+)
diff --git a/examples/output-options/type-mapping/config.yaml b/examples/output-options/type-mapping/config.yaml
new file mode 100644
index 0000000000..7a1af00d54
--- /dev/null
+++ b/examples/output-options/type-mapping/config.yaml
@@ -0,0 +1,14 @@
+# yaml-language-server: $schema=../../configuration-schema.json
+package: typemapping
+generate:
+ models: true
+output-options:
+ skip-prune: true
+ type-mapping:
+ number:
+ default:
+ type: int64
+ formats:
+ date:
+ type: CustomDateHandler
+output: typemapping.gen.go
diff --git a/examples/output-options/type-mapping/customdate.go b/examples/output-options/type-mapping/customdate.go
new file mode 100644
index 0000000000..fda97a2d3e
--- /dev/null
+++ b/examples/output-options/type-mapping/customdate.go
@@ -0,0 +1,3 @@
+package typemapping
+
+type CustomDateHandler struct{}
diff --git a/examples/output-options/type-mapping/generate.go b/examples/output-options/type-mapping/generate.go
new file mode 100644
index 0000000000..8344a10709
--- /dev/null
+++ b/examples/output-options/type-mapping/generate.go
@@ -0,0 +1,6 @@
+package typemapping
+
+// The configuration in this directory overrides the default handling of
+// "type: number" from producing an `int` to producing an `int64`, and we
+// override `type: string, format: date` to be a custom type in this package.
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/examples/output-options/type-mapping/spec.yaml b/examples/output-options/type-mapping/spec.yaml
new file mode 100644
index 0000000000..2c8f63487a
--- /dev/null
+++ b/examples/output-options/type-mapping/spec.yaml
@@ -0,0 +1,18 @@
+openapi: "3.0.1"
+info:
+ version: 1.0.0
+ title: Type mapping test
+paths: {}
+components:
+ schemas:
+ EmployeeDatabaseRecord:
+ type: object
+ required:
+ - ID
+ - DateHired
+ properties:
+ ID:
+ type: number
+ DateHired:
+ type: number
+ format: date
diff --git a/examples/output-options/type-mapping/typemapping.gen.go b/examples/output-options/type-mapping/typemapping.gen.go
new file mode 100644
index 0000000000..744cab7f9c
--- /dev/null
+++ b/examples/output-options/type-mapping/typemapping.gen.go
@@ -0,0 +1,10 @@
+// Package typemapping provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package typemapping
+
+// EmployeeDatabaseRecord defines model for EmployeeDatabaseRecord.
+type EmployeeDatabaseRecord struct {
+ DateHired CustomDateHandler `json:"DateHired"`
+ ID int64 `json:"ID"`
+}
diff --git a/examples/overlay/api/api.yaml b/examples/overlay/api/api.yaml
new file mode 100644
index 0000000000..367ffb19e8
--- /dev/null
+++ b/examples/overlay/api/api.yaml
@@ -0,0 +1,91 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: "Example to indicate how to use the OpenAPI Overlay specification (https://github.com/OAI/Overlay-Specification)"
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: pet response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pong'
+ delete:
+ x-internal: true
+ responses:
+ '202':
+ content: {}
+ /admin/autoscaling:
+ get:
+ # this is a method-level `tags`
+ tags:
+ - internal
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ instances:
+ type: number
+ required:
+ - instances
+ /healthz:
+ x-internal: true
+ get:
+ responses:
+ '200':
+ content: {}
+ /admin/users/reset-password:
+ x-internal: true
+ put:
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ username:
+ type: string
+ not_documented:
+ type: string
+ format: uuid
+ x-internal: true
+ required:
+ - username
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ password:
+ type: string
+ not_documented:
+ type: string
+ format: uuid
+ x-internal: true
+ required:
+ - password
+components:
+ schemas:
+ # base types
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
+ seed:
+ type: number
+ description: The seed for the internal randomness. SHOULD NOT be explained to users
+ # undocumented and not useful
+ verbose:
+ type: boolean
+ x-internal: true
diff --git a/examples/overlay/api/cfg.yaml b/examples/overlay/api/cfg.yaml
new file mode 100644
index 0000000000..b506fc5679
--- /dev/null
+++ b/examples/overlay/api/cfg.yaml
@@ -0,0 +1,10 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: api
+output: ping.gen.go
+generate:
+ models: true
+ gorilla-server: true
+ embedded-spec: true
+output-options:
+ overlay:
+ path: overlay.yaml
diff --git a/examples/overlay/api/generate.go b/examples/overlay/api/generate.go
new file mode 100644
index 0000000000..c025a4570d
--- /dev/null
+++ b/examples/overlay/api/generate.go
@@ -0,0 +1,3 @@
+package api
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/examples/overlay/api/impl.go b/examples/overlay/api/impl.go
new file mode 100644
index 0000000000..4224ef2fe7
--- /dev/null
+++ b/examples/overlay/api/impl.go
@@ -0,0 +1,25 @@
+package api
+
+import (
+ "encoding/json"
+ "net/http"
+)
+
+// ensure that we've conformed to the `ServerInterface` with a compile-time check
+var _ ServerInterface = (*Server)(nil)
+
+type Server struct{}
+
+func NewServer() Server {
+ return Server{}
+}
+
+// (GET /ping)
+func (Server) GetPing(w http.ResponseWriter, r *http.Request) {
+ resp := OverriddenPong{
+ Ping: "pong",
+ }
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(resp)
+}
diff --git a/examples/overlay/api/overlay.yaml b/examples/overlay/api/overlay.yaml
new file mode 100644
index 0000000000..8ee1d72fd5
--- /dev/null
+++ b/examples/overlay/api/overlay.yaml
@@ -0,0 +1,65 @@
+overlay: 1.0.0
+info:
+ title: "Example to indicate how to use the OpenAPI Overlay specification (https://github.com/OAI/Overlay-Specification)"
+ version: 1.0.0
+actions:
+####################################################################################################
+# Structured Overlays, via https://github.com/OAI/Overlay-Specification/blob/main/versions/1.0.0.md#examples
+- target: "$"
+ description: Perform a structural overlay, which can be more readable, as it's clear what the shape of the document is
+ update:
+ info:
+ x-overlay-applied: structured-overlay
+ paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ description: Perform a ping request
+
+####################################################################################################
+# Wildcard/Targeted overlays, via https://github.com/OAI/Overlay-Specification/blob/main/versions/1.0.0.md#examples
+#
+- target: $.paths.*.*[?(!@.servers)]
+ description: Override the servers
+ update:
+ servers:
+ - url: http://localhost:35123
+ description: The default server.
+- target: $.components.schemas.Pong
+ description: Override the Pong schema to utilise the `x-go-name` to override the generated Go type name
+ update:
+ x-go-name: OverriddenPong
+
+- target: $.paths['/ping'].get
+ description: Override the poorly documented internal description for the ping API
+ update:
+ description: Check that the API is running OK
+
+- target: $.components.schemas.Pong.properties.seed
+ description: Hide information about the Seed parameter
+ remove: true
+
+- target: $.components.schemas.*.*.*[?(@.x-internal)]
+ description: Remove any internal fields on Schemas (noted by x-internal)
+ remove: true
+
+- target: $.paths.*.*.requestBody.*.*.schema..[?(@.x-internal)]
+ description: Remove any internal fields on request bodies (noted by x-internal)
+ remove: true
+
+- target: $.paths.*.*.responses.*.*.*.schema..[?(@.x-internal)]
+ description: Remove any internal fields on responses (noted by x-internal)
+ remove: true
+
+- target: $.paths.*[?(@.x-internal)]
+ description: Remove internal endpoints (noted by x-internal)
+ remove: true
+
+- target: $.paths.*.*[?(@.x-internal)]
+ description: Remove internal endpoints (noted by x-internal)
+ remove: true
+
+- target: $.paths.*.*[?(@.tags[*] == 'internal')]
+ description: Remove internal endpoints (noted by internal tag)
+ remove: true
diff --git a/examples/overlay/api/ping.gen.go b/examples/overlay/api/ping.gen.go
new file mode 100644
index 0000000000..0d6794fc38
--- /dev/null
+++ b/examples/overlay/api/ping.gen.go
@@ -0,0 +1,276 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gorilla/mux"
+)
+
+// OverriddenPong defines model for Pong.
+type OverriddenPong struct {
+ Ping string `json:"ping"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(w http.ResponseWriter, r *http.Request)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetPing operation middleware
+func (siw *ServerInterfaceWrapper) GetPing(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetPing(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+ BaseURL string
+ BaseRouter *mux.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = mux.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.HandleFunc(options.BaseURL+"/ping", wrapper.GetPing).Methods(http.MethodGet)
+
+ return r
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "XFLBbtQwEP0Va+AAUna97YqLbxVCaMVhV4Jb1YPrTGKXxGPsSWlV+d/ROLsUepp48uz33sx7AUdzooiR",
+ "C5gXKM7jbNvnieIoNWVKmDlg66awdvHJzmlCMJAE1wE/JzkVzoKotYOMv5aQsQdzu167+4ui+wd0DB08",
+ "bUbaRDtL8/iIOYe+x9ioq7wR4kBCx4Eb2ZeVVjGpEPvgLKPy9FvOS0HFHtUxYbw5HZQ8N9lnVRK6MAg0",
+ "UFQfPHMqRusxsF/ut45mfbw56DN68/1f9Efo4BFzCRTBwNV2t901zXQG25SmIAbF9uJ4ydhffkLtgBJG",
+ "mwIY2J/vJsu+zVHbfg5R24WpODutU60d6MuAR2QpPRaXQ+JVwmeP7qdib7lZFZuhqLzEGOKojt+gceYm",
+ "/iC6viKfQttPxpIolnWL17udFEeRMTaeZmV1rR+KkF3CIF/vMw5g4J1+TYs+R0W/Lut/rSfMA+VZWSWW",
+ "lKQBC7dkFMwyVjC3bw3+8Kh6HOwysVpRW+hgyRMYkM0ZrSdydvJU2Ow/XV3vod7VWuufAAAA//8=",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/examples/overlay/main.go b/examples/overlay/main.go
new file mode 100644
index 0000000000..34cfb71efd
--- /dev/null
+++ b/examples/overlay/main.go
@@ -0,0 +1,27 @@
+package main
+
+import (
+ "log"
+ "net/http"
+
+ "github.com/gorilla/mux"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/overlay/api"
+)
+
+func main() {
+ // create a type that satisfies the `api.ServerInterface`, which contains an implementation of every operation from the generated code
+ server := api.NewServer()
+
+ r := mux.NewRouter()
+
+ // get an `http.Handler` that we can use
+ h := api.HandlerFromMux(server, r)
+
+ s := &http.Server{
+ Handler: h,
+ Addr: "0.0.0.0:8080",
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
diff --git a/examples/petstore-expanded/chi/api/cfg.yaml b/examples/petstore-expanded/chi/api/cfg.yaml
index d1a29f3374..4191a3047d 100644
--- a/examples/petstore-expanded/chi/api/cfg.yaml
+++ b/examples/petstore-expanded/chi/api/cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
chi-server: true
diff --git a/examples/petstore-expanded/chi/api/petstore.gen.go b/examples/petstore-expanded/chi/api/petstore.gen.go
index 73c755288b..338c39e73f 100644
--- a/examples/petstore-expanded/chi/api/petstore.gen.go
+++ b/examples/petstore-expanded/chi/api/petstore.gen.go
@@ -1,12 +1,13 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
+ "errors"
"fmt"
"net/http"
"net/url"
@@ -115,26 +116,36 @@ type MiddlewareFunc func(http.Handler) http.Handler
// FindPets operation middleware
func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// Parameter object where we will unmarshal all parameters from the context
var params FindPetsParams
// ------------- Optional query parameter "tags" -------------
- err = runtime.BindQueryParameter("form", true, false, "tags", r.URL.Query(), ¶ms.Tags)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "tags", r.URL.Query(), ¶ms.Tags, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
if err != nil {
- siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err})
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "tags"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err})
+ }
return
}
// ------------- Optional query parameter "limit" -------------
- err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), ¶ms.Limit)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
if err != nil {
- siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err})
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err})
+ }
return
}
@@ -146,12 +157,11 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque
handler = siw.HandlerMiddlewares[i](handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// AddPet operation middleware
func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.AddPet(w, r)
@@ -161,19 +171,19 @@ func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request
handler = siw.HandlerMiddlewares[i](handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// DeletePet operation middleware
func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// ------------- Path parameter "id" -------------
var id int64
- err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, chi.URLParam(r, "id"), &id)
+ err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
return
@@ -187,19 +197,19 @@ func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Requ
handler = siw.HandlerMiddlewares[i](handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// FindPetByID operation middleware
func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// ------------- Path parameter "id" -------------
var id int64
- err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, chi.URLParam(r, "id"), &id)
+ err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
return
@@ -213,7 +223,7 @@ func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Re
handler = siw.HandlerMiddlewares[i](handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
type UnescapedCookieParamError struct {
@@ -345,54 +355,55 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl
return r
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/+RXW48budH9KwV+32OnNbEXedBTvB4vICBrT+LdvKznoYZdkmrBSw9Z1FgY6L8HRbZu",
- "I3k2QYIgQV506WY1T51zqlj9bGz0YwwUJJv5s8l2TR7rzw8pxaQ/xhRHSsJUL9s4kH4PlG3iUTgGM2+L",
- "od7rzDImj2LmhoO8fWM6I9uR2l9aUTK7znjKGVfffND+9iE0S+KwMrtdZxI9Fk40mPkvZtpwv/x+15mP",
- "9HRHcok7oL+y3Uf0BHEJsiYYSS437Izg6jLup+34etwLoHV3hTdhQ+c+Lc38l2fz/4mWZm7+b3YUYjap",
- "MJty2XUvk+HhEtLPgR8LAQ/nuE7F+MN3V8R4gZQHc7+73+llDsvYJA+CtuImj+zM3ODIQuj/mJ9wtaLU",
- "czTdRLH53K7Bu7sF/EToTWdK0qC1yJjns9lJ0K57kcU7yOhHRzVa1ihQMmVAzSZLTASYAQPQ17ZMIgzk",
- "Y8iSUAiWhFISZeBQOfg0UtAnve1vII9keckW61adcWwpZDqaw7wb0a4J3vQ3F5ifnp56rLf7mFazKTbP",
- "/rR4/+Hj5w+/e9Pf9GvxrjqGks+flp8pbdjS1cRndc1M5WBxp6zdTXmazmwo5cbK7/ub/kYfHUcKOLKZ",
- "m7f1UmdGlHX1xEwZ0h+rZrFzXv9CUlLIgM5VKmGZoq8U5W0W8o1r/V8yJVgry9ZSziDxS/iIHjINYGMY",
- "2FOQ4oGy9PAjkqWAGYT8GBNkXLEIZ8g4MoUOAllI6xhsyZDJnyxgAfQkPbyjQBgABVYJNzwgYFkV6gAt",
- "MNriuIb28L4kfGApCeLAEVxM5DuIKWAioBUJkKMJXSDbgS0pl6wl4chKyT3cFs7gGaSkkXMHY3EbDph0",
- "L0pRk+5AOFgeShDYYOKS4deSJfawCLBGC2sFgTkTjA6FEAa2UrzSsWhFpbngwCNny2EFGESzOebueFUc",
- "HjIf15hIEu5J1PXgo6MsTMB+pDSwMvVX3qBvCaHjx4IeBkZlJmGGR81tQ44FQgwgMUlMSgkvKQyH3Xu4",
- "S0iZgihMCuyPAEoKCJvoiowosKFAARVwI1c/PJakz1iE45OXlCbWl2jZcT7bpO6gH91RXws5DuhIhR06",
- "5dFSQtHE9LuHzyWPFAZWlh2qeYboYurUgZmsqJtrltUqmnUHG1qzLQ5BW1saigfHD5RiDz/G9MBAhbOP",
- "w6kMersa26HlwNh/CV/CZxqqEiXDktR8Lj7EVAMoHh2TiqTie9Da8FgfOJHP2XVA5axamuTgivpQ3dnD",
- "3RozOdcKY6Q0hVeaq7wksMRi+aE0wnG/j647jd+Qm6TjDaWE3fnWWifAQ3coxMAP6x5+FhjJOQpCWU+O",
- "MeZCWkn7IupBqcB9FWjR7bncP2mfVmWyq0AOtgglWJDEWerBtGFB6uGHki0BSe0GQ+FDFWinyJYcJa5w",
- "mn/3AV7dUrCaxxafMYDHlaZMblKrhz+XFuqjU92aelSad45QukPzASxWi6StnOzZ0p7MMTWZQzWqWVRg",
- "4NAdoUyFGzjzHnBWDJalDKxQc0YosvfZJGTb6Yy0ul8Pd6fCVOYmjGMi4eJPOlczTelO/K2tt/+iZ5wO",
- "DfW8Wwxmbn7gMOj5Uo+NpARQynUKOT8sBFfa92HJTijBw9boMGDm5rFQ2h5Pel1numlorHOJkK9n0OUU",
- "1S5gSrjV/1m29djT8aQOOOcIPH5lr228+AdKOtEkysVJhZXqWfYNTI49yxmo3xxHd/c6AuVRW0tF/+bm",
- "Zj/3UGjz2ji6aXKY/ZoV4vO1tF8b5tok94KI3cUANJLAHkwbj5ZYnPxDeF6D0cb6KxuXQF9Hba3ag9ua",
- "zuTiPabtlQFCsY0xXxk13idCqTNboCddux/G6lyjZ3DDrkt0nnMuPtFwYdZ3g3rVtOmUsnwfh+2/jIX9",
- "ZH1Jwx2JegyHQb8OsM3plCyp0O6f9MxvWuW/xxoXgtf7dR6dPfOwaxZxJFdewNp1jc0cVq6+tcADapuN",
- "zTWLW8hFc7rikdsa3Wzyakdb3GoPGZu2E5apf+gAfWwfPFwo/a1ecv1t6rKXfHeZtQJpKIb/JCFvD2JU",
- "FbawuFV4r79QnCt20HFx+63j5/ttvff367Ukset/m1z/s2X8QtGmfl1CabOX6fyteP9S3p+82err6e5+",
- "97cAAAD//ykDnxlaEgAA",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "5Fdbjxu50f0rBX7fY6c1sRd50FO8Hi8gIGtP4t28rOehhl2SasFLD1nUWBjovwdFtm4jeTZBgiBBXnTp",
+ "ZjVPnXOqWP1sbPRjDBQkm/mzyXZNHuvPDynFpD/GFEdKwlQv2ziQfg+UbeJROAYzb4uh3uvMMiaPYuaG",
+ "g7x9Yzoj25HaX1pRMrvOeMoZV9980P72ITRL4rAyu11nEj0WTjSY+S9m2nC//H7XmY/0dEdyiTugv7Ld",
+ "R/QEcQmyJhhJLjfsjODqMu6n7fh63AugdXeFN2FD5z4tzfyXZ/P/iZZmbv5vdhRiNqkwm3LZdS+T4eES",
+ "0s+BHwsBD+e4TsX4w3dXxHiBlAdzv7vf6WUOy9gkD4K24iaP7Mzc4MhC6P+Yn3C1otRzNN1EsfncrsG7",
+ "uwX8ROhNZ0rSoLXImOez2UnQrnuRxTvI6EdHNVrWKFAyZUDNJktMBJgBA9DXtkwiDORjyJJQCJaEUhJl",
+ "4FA5+DRS0Ce97W8gj2R5yRbrVp1xbClkOprDvBvRrgne9DcXmJ+ennqst/uYVrMpNs/+tHj/4ePnD797",
+ "09/0a/GuOoaSz5+Wnylt2NLVxGd1zUzlYHGnrN1NeZrObCjlxsrv+5v+Rh8dRwo4spmbt/VSZ0aUdfXE",
+ "TBnSH6tmsXNe/0JSUsiAzlUqYZmirxTlbRbyjWv9XzIlWCvL1lLOIPFL+IgeMg1gYxjYU5DigbL08COS",
+ "pYAZhPwYE2RcsQhnyDgyhQ4CWUjrGGzJkMmfLGAB9CQ9vKNAGAAFVgk3PCBgWRXqAC0w2uK4hvbwviR8",
+ "YCkJ4sARXEzkO4gpYCKgFQmQowldINuBLSmXrCXhyErJPdwWzuAZpKSRcwdjcRsOmHQvSlGT7kA4WB5K",
+ "ENhg4pLh15Il9rAIsEYLawWBOROMDoUQBrZSvNKxaEWlueDAI2fLYQUYRLM55u54VRweMh/XmEgS7knU",
+ "9eCjoyxMwH6kNLAy9VfeoG8JoePHgh4GRmUmYYZHzW1DjgVCDCAxSUxKCS8pDIfde7hLSJmCKEwK7I8A",
+ "SgoIm+iKjCiwoUABFXAjVz88lqTPWITjk5eUJtaXaNlxPtuk7qAf3VFfCzkO6EiFHTrl0VJC0cT0u4fP",
+ "JY8UBlaWHap5huhi6tSBmayom2uW1SqadQcbWrMtDkFbWxqKB8cPlGIPP8b0wECFs4/DqQx6uxrboeXA",
+ "2H8JX8JnGqoSJcOS1HwuPsRUAygeHZOKpOJ70NrwWB84kc/ZdUDlrFqa5OCK+lDd2cPdGjM51wpjpDSF",
+ "V5qrvCSwxGL5oTTCcb+PrjuN35CbpOMNpYTd+dZaJ8BDdyjEwA/rHn4WGMk5CkJZT44x5kJaSfsi6kGp",
+ "wH0VaNHtudw/aZ9WZbKrQA62CCVYkMRZ6sG0YUHq4YeSLQFJ7QZD4UMVaKfIlhwlrnCaf/cBXt1SsJrH",
+ "Fp8xgMeVpkxuUquHP5cW6qNT3Zp6VJp3jlC6Q/MBLFaLpK2c7NnSnswxNZlDNapZVGDg0B2hTIUbOPMe",
+ "cFYMlqUMrFBzRiiy99kkZNvpjLS6Xw93p8JU5iaMYyLh4k86VzNN6U78ra23/6JnnA4N9bxbDGZufuAw",
+ "6PlSj42kBFDKdQo5PywEV9r3YclOKMHD1ugwYObmsVDaHk96XWe6aWisc4mQr2fQ5RTVLmBKuNX/Wbb1",
+ "2NPxpA445wg8fmWvbbz4B0o60STKxUmFlepZ9g1Mjj3LGajfHEd39zoC5VFbS0X/5uZmP/dQaPPaOLpp",
+ "cpj9mhXi87W0Xxvm2iT3gojdxQA0ksAeTBuPllic/EN4XoPRxvorG5dAX0dtrdqD25rO5OI9pu2VAUKx",
+ "jTFfGTXeJ0KpM1ugJ127H8bqXKNncMOuS3Secy4+0XBh1neDetW06ZSyfB+H7b+Mhf1kfUnDHYl6DIdB",
+ "vw6wzemULKnQ7p/0zG9a5b/HGheC1/t1Hp0987BrFnEkV17A2nWNzRxWrr61wANqm43NNYtbyEVzuuKR",
+ "2xrdbPJqR1vcag8Zm7YTlql/6AB9bB88XCj9rV5y/W3qspd8d5m1Amkohv8kIW8PYlQVtrC4VXivv1Cc",
+ "K3bQcXH7rePn+2299/frtSSx63+bXP+zZfxC0aZ+XUJps5fp/K14/1Len7zZ6uvp7n73twAAAP//",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -400,7 +411,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -418,12 +429,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -449,3 +460,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/examples/petstore-expanded/chi/api/petstore.go b/examples/petstore-expanded/chi/api/petstore.go
index cc5298cddc..6ede559ec5 100644
--- a/examples/petstore-expanded/chi/api/petstore.go
+++ b/examples/petstore-expanded/chi/api/petstore.go
@@ -1,4 +1,4 @@
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=cfg.yaml ../../petstore-expanded.yaml
package api
diff --git a/examples/petstore-expanded/chi/petstore.go b/examples/petstore-expanded/chi/petstore.go
index d714eea8ef..644b4920ea 100644
--- a/examples/petstore-expanded/chi/petstore.go
+++ b/examples/petstore-expanded/chi/petstore.go
@@ -12,16 +12,16 @@ import (
"net/http"
"os"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/chi/api"
- middleware "github.com/oapi-codegen/nethttp-middleware"
"github.com/go-chi/chi/v5"
+ middleware "github.com/oapi-codegen/nethttp-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/chi/api"
)
func main() {
port := flag.String("port", "8080", "Port for test HTTP server")
flag.Parse()
- swagger, err := api.GetSwagger()
+ swagger, err := api.GetSpec()
if err != nil {
fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
os.Exit(1)
diff --git a/examples/petstore-expanded/chi/petstore_test.go b/examples/petstore-expanded/chi/petstore_test.go
index 1a768fd78b..86a9e2cd34 100644
--- a/examples/petstore-expanded/chi/petstore_test.go
+++ b/examples/petstore-expanded/chi/petstore_test.go
@@ -7,10 +7,10 @@ import (
"net/http/httptest"
"testing"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/chi/api"
- middleware "github.com/oapi-codegen/nethttp-middleware"
- "github.com/deepmap/oapi-codegen/pkg/testutil"
"github.com/go-chi/chi/v5"
+ middleware "github.com/oapi-codegen/nethttp-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/chi/api"
+ "github.com/oapi-codegen/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -20,11 +20,32 @@ func doGet(t *testing.T, mux *chi.Mux, url string) *httptest.ResponseRecorder {
return response.Recorder
}
+// TestSpecAccess covers the public spec accessors emitted by inline.tmpl:
+// - GetSpec returns a parsed *openapi3.T
+// - GetSpecJSON returns the raw JSON bytes (decompressed but unparsed),
+// which must be valid JSON.
+//
+// GetSwagger is intentionally not exercised here: it's marked
+// `// Deprecated:` and the repo's lint rule rejects in-tree calls to
+// deprecated functions. Its body is `return GetSpec()`, so its behaviour
+// is covered transitively.
+func TestSpecAccess(t *testing.T) {
+ spec, err := api.GetSpec()
+ require.NoError(t, err)
+ require.NotNil(t, spec)
+ assert.NotEmpty(t, spec.OpenAPI, "OpenAPI version field must be populated")
+
+ raw, err := api.GetSpecJSON()
+ require.NoError(t, err)
+ require.NotEmpty(t, raw, "raw spec bytes must be non-empty")
+ assert.True(t, json.Valid(raw), "GetSpecJSON must return valid JSON")
+}
+
func TestPetStore(t *testing.T) {
var err error
// Get the swagger description of our API
- swagger, err := api.GetSwagger()
+ swagger, err := api.GetSpec()
require.NoError(t, err)
// Clear out the servers array in the swagger spec, that skips validating
diff --git a/examples/petstore-expanded/echo-v5/api/models.cfg.yaml b/examples/petstore-expanded/echo-v5/api/models.cfg.yaml
new file mode 100644
index 0000000000..46b5e629c3
--- /dev/null
+++ b/examples/petstore-expanded/echo-v5/api/models.cfg.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: models
+generate:
+ models: true
+output: models/models.gen.go
diff --git a/examples/petstore-expanded/echo-v5/api/models/models.gen.go b/examples/petstore-expanded/echo-v5/api/models/models.gen.go
new file mode 100644
index 0000000000..0945e02abb
--- /dev/null
+++ b/examples/petstore-expanded/echo-v5/api/models/models.gen.go
@@ -0,0 +1,46 @@
+// Package models provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package models
+
+// Error defines model for Error.
+type Error struct {
+ // Code Error code
+ Code int32 `json:"code"`
+
+ // Message Error message
+ Message string `json:"message"`
+}
+
+// NewPet defines model for NewPet.
+type NewPet struct {
+ // Name Name of the pet
+ Name string `json:"name"`
+
+ // Tag Type of the pet
+ Tag *string `json:"tag,omitempty"`
+}
+
+// Pet defines model for Pet.
+type Pet struct {
+ // Id Unique id of the pet
+ Id int64 `json:"id"`
+
+ // Name Name of the pet
+ Name string `json:"name"`
+
+ // Tag Type of the pet
+ Tag *string `json:"tag,omitempty"`
+}
+
+// FindPetsParams defines parameters for FindPets.
+type FindPetsParams struct {
+ // Tags tags to filter by
+ Tags *[]string `form:"tags,omitempty" json:"tags,omitempty"`
+
+ // Limit maximum number of results to return
+ Limit *int32 `form:"limit,omitempty" json:"limit,omitempty"`
+}
+
+// AddPetJSONRequestBody defines body for AddPet for application/json ContentType.
+type AddPetJSONRequestBody = NewPet
diff --git a/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go b/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go
new file mode 100644
index 0000000000..557c96abf5
--- /dev/null
+++ b/examples/petstore-expanded/echo-v5/api/petstore-server.gen.go
@@ -0,0 +1,286 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/labstack/echo/v5"
+ . "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo-v5/api/models"
+ "github.com/oapi-codegen/runtime"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // Returns all pets
+ // (GET /pets)
+ FindPets(ctx *echo.Context, params FindPetsParams) error
+ // Creates a new pet
+ // (POST /pets)
+ AddPet(ctx *echo.Context) error
+ // Deletes a pet by ID
+ // (DELETE /pets/{id})
+ DeletePet(ctx *echo.Context, id int64) error
+ // Returns a pet by ID
+ // (GET /pets/{id})
+ FindPetByID(ctx *echo.Context, id int64) error
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+// FindPets converts echo context to params.
+func (w *ServerInterfaceWrapper) FindPets(ctx *echo.Context) error {
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params FindPetsParams
+ // ------------- Optional query parameter "tags" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "tags", ctx.QueryParams(), ¶ms.Tags, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter tags: %s", err))
+ }
+
+ // ------------- Optional query parameter "limit" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", ctx.QueryParams(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.FindPets(ctx, params)
+ return err
+}
+
+// AddPet converts echo context to params.
+func (w *ServerInterfaceWrapper) AddPet(ctx *echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.AddPet(ctx)
+ return err
+}
+
+// DeletePet converts echo context to params.
+func (w *ServerInterfaceWrapper) DeletePet(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "id" -------------
+ var id int64
+
+ err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.DeletePet(ctx, id)
+ return err
+}
+
+// FindPetByID converts echo context to params.
+func (w *ServerInterfaceWrapper) FindPetByID(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "id" -------------
+ var id int64
+
+ err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.FindPetByID(ctx, id)
+ return err
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+}
+
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
+}
+
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.GET(options.BaseURL+"/pets", wrapper.FindPets, options.OperationMiddlewares["findPets"]...)
+ router.POST(options.BaseURL+"/pets", wrapper.AddPet, options.OperationMiddlewares["addPet"]...)
+ router.DELETE(options.BaseURL+"/pets/:id", wrapper.DeletePet, options.OperationMiddlewares["deletePet"]...)
+ router.GET(options.BaseURL+"/pets/:id", wrapper.FindPetByID, options.OperationMiddlewares["findPetByID"]...)
+
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "5Fdbjxu50f0rBX7fY6c1sRd50FO8Hi8gIGtP4t28rOehhl2SasFLD1nUWBjovwdFtm4jeTZBgiBBXnTp",
+ "ZjVPnXOqWP1sbPRjDBQkm/mzyXZNHuvPDynFpD/GFEdKwlQv2ziQfg+UbeJROAYzb4uh3uvMMiaPYuaG",
+ "g7x9Yzoj25HaX1pRMrvOeMoZV9980P72ITRL4rAyu11nEj0WTjSY+S9m2nC//H7XmY/0dEdyiTugv7Ld",
+ "R/QEcQmyJhhJLjfsjODqMu6n7fh63AugdXeFN2FD5z4tzfyXZ/P/iZZmbv5vdhRiNqkwm3LZdS+T4eES",
+ "0s+BHwsBD+e4TsX4w3dXxHiBlAdzv7vf6WUOy9gkD4K24iaP7Mzc4MhC6P+Yn3C1otRzNN1EsfncrsG7",
+ "uwX8ROhNZ0rSoLXImOez2UnQrnuRxTvI6EdHNVrWKFAyZUDNJktMBJgBA9DXtkwiDORjyJJQCJaEUhJl",
+ "4FA5+DRS0Ce97W8gj2R5yRbrVp1xbClkOprDvBvRrgne9DcXmJ+ennqst/uYVrMpNs/+tHj/4ePnD797",
+ "09/0a/GuOoaSz5+Wnylt2NLVxGd1zUzlYHGnrN1NeZrObCjlxsrv+5v+Rh8dRwo4spmbt/VSZ0aUdfXE",
+ "TBnSH6tmsXNe/0JSUsiAzlUqYZmirxTlbRbyjWv9XzIlWCvL1lLOIPFL+IgeMg1gYxjYU5DigbL08COS",
+ "pYAZhPwYE2RcsQhnyDgyhQ4CWUjrGGzJkMmfLGAB9CQ9vKNAGAAFVgk3PCBgWRXqAC0w2uK4hvbwviR8",
+ "YCkJ4sARXEzkO4gpYCKgFQmQowldINuBLSmXrCXhyErJPdwWzuAZpKSRcwdjcRsOmHQvSlGT7kA4WB5K",
+ "ENhg4pLh15Il9rAIsEYLawWBOROMDoUQBrZSvNKxaEWlueDAI2fLYQUYRLM55u54VRweMh/XmEgS7knU",
+ "9eCjoyxMwH6kNLAy9VfeoG8JoePHgh4GRmUmYYZHzW1DjgVCDCAxSUxKCS8pDIfde7hLSJmCKEwK7I8A",
+ "SgoIm+iKjCiwoUABFXAjVz88lqTPWITjk5eUJtaXaNlxPtuk7qAf3VFfCzkO6EiFHTrl0VJC0cT0u4fP",
+ "JY8UBlaWHap5huhi6tSBmayom2uW1SqadQcbWrMtDkFbWxqKB8cPlGIPP8b0wECFs4/DqQx6uxrboeXA",
+ "2H8JX8JnGqoSJcOS1HwuPsRUAygeHZOKpOJ70NrwWB84kc/ZdUDlrFqa5OCK+lDd2cPdGjM51wpjpDSF",
+ "V5qrvCSwxGL5oTTCcb+PrjuN35CbpOMNpYTd+dZaJ8BDdyjEwA/rHn4WGMk5CkJZT44x5kJaSfsi6kGp",
+ "wH0VaNHtudw/aZ9WZbKrQA62CCVYkMRZ6sG0YUHq4YeSLQFJ7QZD4UMVaKfIlhwlrnCaf/cBXt1SsJrH",
+ "Fp8xgMeVpkxuUquHP5cW6qNT3Zp6VJp3jlC6Q/MBLFaLpK2c7NnSnswxNZlDNapZVGDg0B2hTIUbOPMe",
+ "cFYMlqUMrFBzRiiy99kkZNvpjLS6Xw93p8JU5iaMYyLh4k86VzNN6U78ra23/6JnnA4N9bxbDGZufuAw",
+ "6PlSj42kBFDKdQo5PywEV9r3YclOKMHD1ugwYObmsVDaHk96XWe6aWisc4mQr2fQ5RTVLmBKuNX/Wbb1",
+ "2NPxpA445wg8fmWvbbz4B0o60STKxUmFlepZ9g1Mjj3LGajfHEd39zoC5VFbS0X/5uZmP/dQaPPaOLpp",
+ "cpj9mhXi87W0Xxvm2iT3gojdxQA0ksAeTBuPllic/EN4XoPRxvorG5dAX0dtrdqD25rO5OI9pu2VAUKx",
+ "jTFfGTXeJ0KpM1ugJ127H8bqXKNncMOuS3Secy4+0XBh1neDetW06ZSyfB+H7b+Mhf1kfUnDHYl6DIdB",
+ "vw6wzemULKnQ7p/0zG9a5b/HGheC1/t1Hp0987BrFnEkV17A2nWNzRxWrr61wANqm43NNYtbyEVzuuKR",
+ "2xrdbPJqR1vcag8Zm7YTlql/6AB9bB88XCj9rV5y/W3qspd8d5m1Amkohv8kIW8PYlQVtrC4VXivv1Cc",
+ "K3bQcXH7rePn+2299/frtSSx63+bXP+zZfxC0aZ+XUJps5fp/K14/1Len7zZ6uvp7n73twAAAP//",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/examples/petstore-expanded/echo-v5/api/petstore.go b/examples/petstore-expanded/echo-v5/api/petstore.go
new file mode 100644
index 0000000000..6313eec228
--- /dev/null
+++ b/examples/petstore-expanded/echo-v5/api/petstore.go
@@ -0,0 +1,146 @@
+// Copyright 2019 DeepMap, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=models.cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../../petstore-expanded.yaml
+
+package api
+
+import (
+ "fmt"
+ "net/http"
+ "sync"
+
+ "github.com/labstack/echo/v5"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo-v5/api/models"
+)
+
+type PetStore struct {
+ Pets map[int64]models.Pet
+ NextId int64
+ Lock sync.Mutex
+}
+
+func NewPetStore() *PetStore {
+ return &PetStore{
+ Pets: make(map[int64]models.Pet),
+ NextId: 1000,
+ }
+}
+
+// sendPetStoreError wraps sending of an error in the Error format, and
+// handling the failure to marshal that.
+func sendPetStoreError(ctx *echo.Context, code int, message string) error {
+ petErr := models.Error{
+ Code: int32(code),
+ Message: message,
+ }
+ err := ctx.JSON(code, petErr)
+ return err
+}
+
+// FindPets implements all the handlers in the ServerInterface
+func (p *PetStore) FindPets(ctx *echo.Context, params models.FindPetsParams) error {
+ p.Lock.Lock()
+ defer p.Lock.Unlock()
+
+ var result []models.Pet
+
+ for _, pet := range p.Pets {
+ if params.Tags != nil {
+ // If we have tags, filter pets by tag
+ for _, t := range *params.Tags {
+ if pet.Tag != nil && (*pet.Tag == t) {
+ result = append(result, pet)
+ }
+ }
+ } else {
+ // Add all pets if we're not filtering
+ result = append(result, pet)
+ }
+
+ if params.Limit != nil {
+ l := int(*params.Limit)
+ if len(result) >= l {
+ // We're at the limit
+ break
+ }
+ }
+ }
+ return ctx.JSON(http.StatusOK, result)
+}
+
+func (p *PetStore) AddPet(ctx *echo.Context) error {
+ // We expect a NewPet object in the request body.
+ var newPet models.NewPet
+ err := ctx.Bind(&newPet)
+ if err != nil {
+ return sendPetStoreError(ctx, http.StatusBadRequest, "Invalid format for NewPet")
+ }
+ // We now have a pet, let's add it to our "database".
+
+ // We're always asynchronous, so lock unsafe operations below
+ p.Lock.Lock()
+ defer p.Lock.Unlock()
+
+ // We handle pets, not NewPets, which have an additional ID field
+ var pet models.Pet
+ pet.Name = newPet.Name
+ pet.Tag = newPet.Tag
+ pet.Id = p.NextId
+ p.NextId++
+
+ // Insert into map
+ p.Pets[pet.Id] = pet
+
+ // Now, we have to return the NewPet
+ err = ctx.JSON(http.StatusCreated, pet)
+ if err != nil {
+ // Something really bad happened, tell Echo that our handler failed
+ return err
+ }
+
+ // Return no error. This refers to the handler. Even if we return an HTTP
+ // error, but everything else is working properly, tell Echo that we serviced
+ // the error. We should only return errors from Echo handlers if the actual
+ // servicing of the error on the infrastructure level failed. Returning an
+ // HTTP/400 or HTTP/500 from here means Echo/HTTP are still working, so
+ // return nil.
+ return nil
+}
+
+func (p *PetStore) FindPetByID(ctx *echo.Context, petId int64) error {
+ p.Lock.Lock()
+ defer p.Lock.Unlock()
+
+ pet, found := p.Pets[petId]
+ if !found {
+ return sendPetStoreError(ctx, http.StatusNotFound,
+ fmt.Sprintf("Could not find pet with ID %d", petId))
+ }
+ return ctx.JSON(http.StatusOK, pet)
+}
+
+func (p *PetStore) DeletePet(ctx *echo.Context, id int64) error {
+ p.Lock.Lock()
+ defer p.Lock.Unlock()
+
+ _, found := p.Pets[id]
+ if !found {
+ return sendPetStoreError(ctx, http.StatusNotFound,
+ fmt.Sprintf("Could not find pet with ID %d", id))
+ }
+ delete(p.Pets, id)
+ return ctx.NoContent(http.StatusNoContent)
+}
diff --git a/examples/petstore-expanded/echo-v5/api/server.cfg.yaml b/examples/petstore-expanded/echo-v5/api/server.cfg.yaml
new file mode 100644
index 0000000000..478dc9fc99
--- /dev/null
+++ b/examples/petstore-expanded/echo-v5/api/server.cfg.yaml
@@ -0,0 +1,9 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: api
+output: petstore-server.gen.go
+additional-imports:
+ - package: github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo-v5/api/models
+ alias: .
+generate:
+ echo5-server: true
+ embedded-spec: true
diff --git a/examples/petstore-expanded/echo-v5/middleware/middleware.go b/examples/petstore-expanded/echo-v5/middleware/middleware.go
new file mode 100644
index 0000000000..0a241fbcf6
--- /dev/null
+++ b/examples/petstore-expanded/echo-v5/middleware/middleware.go
@@ -0,0 +1,226 @@
+// Package middleware provides OpenAPI request validation middleware for Echo v5.
+//
+// Adapted from github.com/oapi-codegen/echo-middleware (Echo v4) for use
+// with github.com/labstack/echo/v5, which has breaking API changes
+// (pointer context, NewHTTPError signature, no HTTPError.Internal field).
+//
+// This is intentionally inlined in the example because there is no published
+// echo-v5 middleware package yet.
+// TODO: make an echo-v5 middleware repo
+package middleware
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "log"
+ "net/http"
+ "net/url"
+ "os"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/getkin/kin-openapi/openapi3filter"
+ "github.com/getkin/kin-openapi/routers"
+ "github.com/getkin/kin-openapi/routers/gorillamux"
+ "github.com/labstack/echo/v5"
+ echomiddleware "github.com/labstack/echo/v5/middleware"
+)
+
+const (
+ EchoContextKey = "oapi-codegen/echo-context"
+ UserDataKey = "oapi-codegen/user-data"
+)
+
+// OapiValidatorFromYamlFile creates validator middleware from a YAML file path.
+func OapiValidatorFromYamlFile(path string) (echo.MiddlewareFunc, error) {
+ data, err := os.ReadFile(path)
+ if err != nil {
+ return nil, fmt.Errorf("error reading %s: %w", path, err)
+ }
+
+ spec, err := openapi3.NewLoader().LoadFromData(data)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing %s as OpenAPI YAML: %w", path, err)
+ }
+ return OapiRequestValidator(spec), nil
+}
+
+// OapiRequestValidator creates middleware to validate incoming requests against
+// the given OpenAPI 3.x spec with default configuration.
+func OapiRequestValidator(spec *openapi3.T) echo.MiddlewareFunc {
+ return OapiRequestValidatorWithOptions(spec, nil)
+}
+
+// ErrorHandler is called when there is an error in validation.
+type ErrorHandler func(c *echo.Context, err *echo.HTTPError) error
+
+// MultiErrorHandler is called when the OpenAPI filter returns a MultiError.
+type MultiErrorHandler func(openapi3.MultiError) *echo.HTTPError
+
+// Options to customize request validation.
+type Options struct {
+ ErrorHandler ErrorHandler
+ Options openapi3filter.Options
+ ParamDecoder openapi3filter.ContentParameterDecoder
+ UserData any
+ Skipper echomiddleware.Skipper
+ MultiErrorHandler MultiErrorHandler
+ SilenceServersWarning bool
+ DoNotValidateServers bool
+ Prefix string
+}
+
+// OapiRequestValidatorWithOptions creates middleware with explicit configuration.
+func OapiRequestValidatorWithOptions(spec *openapi3.T, options *Options) echo.MiddlewareFunc {
+ if options != nil && options.DoNotValidateServers {
+ spec.Servers = nil
+ }
+
+ if spec.Servers != nil && (options == nil || !options.SilenceServersWarning) {
+ log.Println("WARN: OapiRequestValidatorWithOptions called with an OpenAPI spec that has `Servers` set. This may lead to an HTTP 400 with `no matching operation was found` when sending a valid request, as the validator performs `Host` header validation. If you're expecting `Host` header validation, you can silence this warning by setting `Options.SilenceServersWarning = true`. See https://github.com/oapi-codegen/oapi-codegen/issues/882 for more information.")
+ }
+
+ router, err := gorillamux.NewRouter(spec)
+ if err != nil {
+ panic(err)
+ }
+
+ skipper := getSkipperFromOptions(options)
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c *echo.Context) error {
+ if skipper(c) {
+ return next(c)
+ }
+
+ err := validateRequestFromContext(c, router, options)
+ if err != nil {
+ if options != nil && options.ErrorHandler != nil {
+ return options.ErrorHandler(c, err)
+ }
+ return err
+ }
+ return next(c)
+ }
+ }
+}
+
+// validateRequestFromContext does the work of validating a request.
+func validateRequestFromContext(ctx *echo.Context, router routers.Router, options *Options) *echo.HTTPError {
+ req := ctx.Request()
+
+ if options != nil && options.Prefix != "" {
+ clone := req.Clone(req.Context())
+ clone.URL.Path = strings.TrimPrefix(clone.URL.Path, options.Prefix)
+ req = clone
+ }
+
+ route, pathParams, err := router.FindRoute(req)
+ if err != nil {
+ if errors.Is(err, routers.ErrMethodNotAllowed) {
+ return echo.NewHTTPError(http.StatusMethodNotAllowed, http.StatusText(http.StatusMethodNotAllowed))
+ }
+
+ switch e := err.(type) {
+ case *routers.RouteError:
+ return echo.NewHTTPError(http.StatusNotFound, e.Reason)
+ default:
+ return echo.NewHTTPError(http.StatusInternalServerError,
+ fmt.Sprintf("error validating route: %s", err.Error()))
+ }
+ }
+
+ for k, v := range pathParams {
+ if unescaped, err := url.PathUnescape(v); err == nil {
+ pathParams[k] = unescaped
+ }
+ }
+
+ validationInput := &openapi3filter.RequestValidationInput{
+ Request: req,
+ PathParams: pathParams,
+ Route: route,
+ }
+
+ requestContext := context.WithValue(context.Background(), EchoContextKey, ctx) //nolint:staticcheck
+
+ if options != nil {
+ validationInput.Options = &options.Options
+ validationInput.ParamDecoder = options.ParamDecoder
+ requestContext = context.WithValue(requestContext, UserDataKey, options.UserData) //nolint:staticcheck
+ }
+
+ err = openapi3filter.ValidateRequest(requestContext, validationInput)
+ if err != nil {
+ me := openapi3.MultiError{}
+ if errors.As(err, &me) {
+ errFunc := getMultiErrorHandlerFromOptions(options)
+ return errFunc(me)
+ }
+
+ switch e := err.(type) {
+ case *openapi3filter.RequestError:
+ errorLines := strings.Split(e.Error(), "\n")
+ return echo.NewHTTPError(http.StatusBadRequest, errorLines[0])
+ case *openapi3filter.SecurityRequirementsError:
+ for _, err := range e.Errors {
+ httpErr, ok := err.(*echo.HTTPError)
+ if ok {
+ return httpErr
+ }
+ }
+ return echo.NewHTTPError(http.StatusForbidden, e.Error())
+ default:
+ return echo.NewHTTPError(http.StatusInternalServerError,
+ fmt.Sprintf("error validating request: %s", err))
+ }
+ }
+ return nil
+}
+
+// GetEchoContext gets the echo context from within requests. It returns
+// nil if not found or wrong type.
+func GetEchoContext(c context.Context) *echo.Context {
+ iface := c.Value(EchoContextKey)
+ if iface == nil {
+ return nil
+ }
+ eCtx, ok := iface.(*echo.Context)
+ if !ok {
+ return nil
+ }
+ return eCtx
+}
+
+// GetUserData gets the user data from the context.
+func GetUserData(c context.Context) any {
+ return c.Value(UserDataKey)
+}
+
+func getSkipperFromOptions(options *Options) echomiddleware.Skipper {
+ if options == nil {
+ return echomiddleware.DefaultSkipper
+ }
+
+ if options.Skipper == nil {
+ return echomiddleware.DefaultSkipper
+ }
+
+ return options.Skipper
+}
+
+func getMultiErrorHandlerFromOptions(options *Options) MultiErrorHandler {
+ if options == nil {
+ return defaultMultiErrorHandler
+ }
+
+ if options.MultiErrorHandler == nil {
+ return defaultMultiErrorHandler
+ }
+
+ return options.MultiErrorHandler
+}
+
+func defaultMultiErrorHandler(me openapi3.MultiError) *echo.HTTPError {
+ return echo.NewHTTPError(http.StatusBadRequest, me.Error())
+}
diff --git a/examples/petstore-expanded/echo-v5/petstore.go b/examples/petstore-expanded/echo-v5/petstore.go
new file mode 100644
index 0000000000..7b15a9fdd5
--- /dev/null
+++ b/examples/petstore-expanded/echo-v5/petstore.go
@@ -0,0 +1,48 @@
+// This is an example of implementing the Pet Store from the OpenAPI documentation
+// found at:
+// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml
+//
+// The code under api/petstore/ has been generated from that specification.
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "net"
+ "os"
+
+ "github.com/labstack/echo/v5"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo-v5/api"
+ mw "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo-v5/middleware"
+)
+
+func main() {
+ port := flag.String("port", "8080", "Port for test HTTP server")
+ flag.Parse()
+
+ swagger, err := api.GetSpec()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
+ os.Exit(1)
+ }
+
+ // Clear out the servers array in the swagger spec, that skips validating
+ // that server names match. We don't know how this thing will be run.
+ swagger.Servers = nil
+
+ // Create an instance of our handler which satisfies the generated interface
+ petStore := api.NewPetStore()
+
+ // This is how you set up a basic Echo router
+ e := echo.New()
+ // Use our validation middleware to check all requests against the
+ // OpenAPI schema.
+ e.Use(mw.OapiRequestValidator(swagger))
+
+ // We now register our petStore above as the handler for the interface
+ api.RegisterHandlers(e, petStore)
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(e.Start(net.JoinHostPort("0.0.0.0", *port)))
+}
diff --git a/examples/petstore-expanded/echo-v5/petstore_test.go b/examples/petstore-expanded/echo-v5/petstore_test.go
new file mode 100644
index 0000000000..3809bb5544
--- /dev/null
+++ b/examples/petstore-expanded/echo-v5/petstore_test.go
@@ -0,0 +1,152 @@
+// Copyright 2019 DeepMap, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+ "fmt"
+ "net/http"
+ "testing"
+
+ "github.com/labstack/echo/v5"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo-v5/api"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo-v5/api/models"
+ mw "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo-v5/middleware"
+ "github.com/oapi-codegen/testutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestPetStore(t *testing.T) {
+ var err error
+ // Here, we Initialize echo
+ e := echo.New()
+
+ // Now, we create our empty pet store
+ store := api.NewPetStore()
+
+ // Get the swagger description of our API
+ swagger, err := api.GetSpec()
+ require.NoError(t, err)
+
+ // This disables swagger server name validation. It seems to work poorly,
+ // and requires our test server to be in that list.
+ swagger.Servers = nil
+
+ // Validate requests against the OpenAPI spec
+ e.Use(mw.OapiRequestValidator(swagger))
+
+ // We register the autogenerated boilerplate and bind our PetStore to this
+ // echo router.
+ api.RegisterHandlers(e, store)
+
+ // At this point, we can start sending simulated Http requests, and record
+ // the HTTP responses to check for validity. This exercises every part of
+ // the stack except the well-tested HTTP system in Go, which there is no
+ // point for us to test.
+ tag := "TagOfSpot"
+ newPet := models.NewPet{
+ Name: "Spot",
+ Tag: &tag,
+ }
+ result := testutil.NewRequest().Post("/pets").WithJsonBody(newPet).GoWithHTTPHandler(t, e)
+ // We expect 201 code on successful pet insertion
+ assert.Equal(t, http.StatusCreated, result.Code())
+
+ // We should have gotten a response from the server with the new pet. Make
+ // sure that its fields match.
+ var resultPet models.Pet
+ err = result.UnmarshalBodyToObject(&resultPet)
+ assert.NoError(t, err, "error unmarshaling response")
+ assert.Equal(t, newPet.Name, resultPet.Name)
+ assert.Equal(t, *newPet.Tag, *resultPet.Tag)
+
+ // This is the Id of the pet we inserted.
+ petId := resultPet.Id
+
+ // Test the getter function.
+ result = testutil.NewRequest().Get(fmt.Sprintf("/pets/%d", petId)).WithAcceptJson().GoWithHTTPHandler(t, e)
+ var resultPet2 models.Pet
+ err = result.UnmarshalBodyToObject(&resultPet2)
+ assert.NoError(t, err, "error getting pet")
+ assert.Equal(t, resultPet, resultPet2)
+
+ // We should get a 404 on invalid ID
+ result = testutil.NewRequest().Get("/pets/27179095781").WithAcceptJson().GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusNotFound, result.Code())
+ var petError models.Error
+ err = result.UnmarshalBodyToObject(&petError)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, int32(http.StatusNotFound), petError.Code)
+
+ // Let's insert another pet for subsequent tests.
+ tag = "TagOfFido"
+ newPet = models.NewPet{
+ Name: "Fido",
+ Tag: &tag,
+ }
+ result = testutil.NewRequest().Post("/pets").WithJsonBody(newPet).GoWithHTTPHandler(t, e)
+ // We expect 201 code on successful pet insertion
+ assert.Equal(t, http.StatusCreated, result.Code())
+ // We should have gotten a response from the server with the new pet. Make
+ // sure that its fields match.
+ err = result.UnmarshalBodyToObject(&resultPet)
+ assert.NoError(t, err, "error unmarshaling response")
+ petId2 := resultPet.Id
+
+ // Now, list all pets, we should have two
+ result = testutil.NewRequest().Get("/pets").WithAcceptJson().GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusOK, result.Code())
+ var petList []models.Pet
+ err = result.UnmarshalBodyToObject(&petList)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, 2, len(petList))
+
+ // Filter pets by tag, we should have 1
+ petList = nil
+ result = testutil.NewRequest().Get("/pets?tags=TagOfFido").WithAcceptJson().GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusOK, result.Code())
+ err = result.UnmarshalBodyToObject(&petList)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, 1, len(petList))
+
+ // Filter pets by non existent tag, we should have 0
+ petList = nil
+ result = testutil.NewRequest().Get("/pets?tags=NotExists").WithAcceptJson().GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusOK, result.Code())
+ err = result.UnmarshalBodyToObject(&petList)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, 0, len(petList))
+
+ // Let's delete non-existent pet
+ result = testutil.NewRequest().Delete("/pets/7").GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusNotFound, result.Code())
+ err = result.UnmarshalBodyToObject(&petError)
+ assert.NoError(t, err, "error unmarshaling PetError")
+ assert.Equal(t, int32(http.StatusNotFound), petError.Code)
+
+ // Now, delete both real pets
+ result = testutil.NewRequest().Delete(fmt.Sprintf("/pets/%d", petId)).GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusNoContent, result.Code())
+ result = testutil.NewRequest().Delete(fmt.Sprintf("/pets/%d", petId2)).GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusNoContent, result.Code())
+
+ // Should have no pets left.
+ petList = nil
+ result = testutil.NewRequest().Get("/pets").WithAcceptJson().GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusOK, result.Code())
+ err = result.UnmarshalBodyToObject(&petList)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, 0, len(petList))
+}
diff --git a/examples/petstore-expanded/echo/api/models.cfg.yaml b/examples/petstore-expanded/echo/api/models.cfg.yaml
index c1b80a89d9..46b5e629c3 100644
--- a/examples/petstore-expanded/echo/api/models.cfg.yaml
+++ b/examples/petstore-expanded/echo/api/models.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: models
generate:
models: true
diff --git a/examples/petstore-expanded/echo/api/models/models.gen.go b/examples/petstore-expanded/echo/api/models/models.gen.go
index 4be509a7cb..0945e02abb 100644
--- a/examples/petstore-expanded/echo/api/models/models.gen.go
+++ b/examples/petstore-expanded/echo/api/models/models.gen.go
@@ -1,6 +1,6 @@
// Package models provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package models
// Error defines model for Error.
diff --git a/examples/petstore-expanded/echo/api/petstore-server.gen.go b/examples/petstore-expanded/echo/api/petstore-server.gen.go
index 8314a77fb6..8a65c64304 100644
--- a/examples/petstore-expanded/echo/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/echo/api/petstore-server.gen.go
@@ -1,11 +1,11 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/http"
@@ -13,9 +13,9 @@ import (
"path"
"strings"
- . "github.com/deepmap/oapi-codegen/examples/petstore-expanded/echo/api/models"
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
+ . "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo/api/models"
"github.com/oapi-codegen/runtime"
)
@@ -48,14 +48,14 @@ func (w *ServerInterfaceWrapper) FindPets(ctx echo.Context) error {
var params FindPetsParams
// ------------- Optional query parameter "tags" -------------
- err = runtime.BindQueryParameter("form", true, false, "tags", ctx.QueryParams(), ¶ms.Tags)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "tags", ctx.QueryParams(), ¶ms.Tags, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter tags: %s", err))
}
// ------------- Optional query parameter "limit" -------------
- err = runtime.BindQueryParameter("form", true, false, "limit", ctx.QueryParams(), ¶ms.Limit)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", ctx.QueryParams(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter limit: %s", err))
}
@@ -80,7 +80,7 @@ func (w *ServerInterfaceWrapper) DeletePet(ctx echo.Context) error {
// ------------- Path parameter "id" -------------
var id int64
- err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, ctx.Param("id"), &id)
+ err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
}
@@ -96,7 +96,7 @@ func (w *ServerInterfaceWrapper) FindPetByID(ctx echo.Context) error {
// ------------- Path parameter "id" -------------
var id int64
- err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, ctx.Param("id"), &id)
+ err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
}
@@ -121,74 +121,94 @@ type EchoRouter interface {
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
}
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
- router.GET(baseURL+"/pets", wrapper.FindPets)
- router.POST(baseURL+"/pets", wrapper.AddPet)
- router.DELETE(baseURL+"/pets/:id", wrapper.DeletePet)
- router.GET(baseURL+"/pets/:id", wrapper.FindPetByID)
+ router.GET(options.BaseURL+"/pets", wrapper.FindPets, options.OperationMiddlewares["findPets"]...)
+ router.POST(options.BaseURL+"/pets", wrapper.AddPet, options.OperationMiddlewares["addPet"]...)
+ router.DELETE(options.BaseURL+"/pets/:id", wrapper.DeletePet, options.OperationMiddlewares["deletePet"]...)
+ router.GET(options.BaseURL+"/pets/:id", wrapper.FindPetByID, options.OperationMiddlewares["findPetByID"]...)
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
+ "5Fdbjxu50f0rBX7fY6c1sRd50FO8Hi8gIGtP4t28rOehhl2SasFLD1nUWBjovwdFtm4jeTZBgiBBXnTp",
+ "ZjVPnXOqWP1sbPRjDBQkm/mzyXZNHuvPDynFpD/GFEdKwlQv2ziQfg+UbeJROAYzb4uh3uvMMiaPYuaG",
+ "g7x9Yzoj25HaX1pRMrvOeMoZV9980P72ITRL4rAyu11nEj0WTjSY+S9m2nC//H7XmY/0dEdyiTugv7Ld",
+ "R/QEcQmyJhhJLjfsjODqMu6n7fh63AugdXeFN2FD5z4tzfyXZ/P/iZZmbv5vdhRiNqkwm3LZdS+T4eES",
+ "0s+BHwsBD+e4TsX4w3dXxHiBlAdzv7vf6WUOy9gkD4K24iaP7Mzc4MhC6P+Yn3C1otRzNN1EsfncrsG7",
+ "uwX8ROhNZ0rSoLXImOez2UnQrnuRxTvI6EdHNVrWKFAyZUDNJktMBJgBA9DXtkwiDORjyJJQCJaEUhJl",
+ "4FA5+DRS0Ce97W8gj2R5yRbrVp1xbClkOprDvBvRrgne9DcXmJ+ennqst/uYVrMpNs/+tHj/4ePnD797",
+ "09/0a/GuOoaSz5+Wnylt2NLVxGd1zUzlYHGnrN1NeZrObCjlxsrv+5v+Rh8dRwo4spmbt/VSZ0aUdfXE",
+ "TBnSH6tmsXNe/0JSUsiAzlUqYZmirxTlbRbyjWv9XzIlWCvL1lLOIPFL+IgeMg1gYxjYU5DigbL08COS",
+ "pYAZhPwYE2RcsQhnyDgyhQ4CWUjrGGzJkMmfLGAB9CQ9vKNAGAAFVgk3PCBgWRXqAC0w2uK4hvbwviR8",
+ "YCkJ4sARXEzkO4gpYCKgFQmQowldINuBLSmXrCXhyErJPdwWzuAZpKSRcwdjcRsOmHQvSlGT7kA4WB5K",
+ "ENhg4pLh15Il9rAIsEYLawWBOROMDoUQBrZSvNKxaEWlueDAI2fLYQUYRLM55u54VRweMh/XmEgS7knU",
+ "9eCjoyxMwH6kNLAy9VfeoG8JoePHgh4GRmUmYYZHzW1DjgVCDCAxSUxKCS8pDIfde7hLSJmCKEwK7I8A",
+ "SgoIm+iKjCiwoUABFXAjVz88lqTPWITjk5eUJtaXaNlxPtuk7qAf3VFfCzkO6EiFHTrl0VJC0cT0u4fP",
+ "JY8UBlaWHap5huhi6tSBmayom2uW1SqadQcbWrMtDkFbWxqKB8cPlGIPP8b0wECFs4/DqQx6uxrboeXA",
+ "2H8JX8JnGqoSJcOS1HwuPsRUAygeHZOKpOJ70NrwWB84kc/ZdUDlrFqa5OCK+lDd2cPdGjM51wpjpDSF",
+ "V5qrvCSwxGL5oTTCcb+PrjuN35CbpOMNpYTd+dZaJ8BDdyjEwA/rHn4WGMk5CkJZT44x5kJaSfsi6kGp",
+ "wH0VaNHtudw/aZ9WZbKrQA62CCVYkMRZ6sG0YUHq4YeSLQFJ7QZD4UMVaKfIlhwlrnCaf/cBXt1SsJrH",
+ "Fp8xgMeVpkxuUquHP5cW6qNT3Zp6VJp3jlC6Q/MBLFaLpK2c7NnSnswxNZlDNapZVGDg0B2hTIUbOPMe",
+ "cFYMlqUMrFBzRiiy99kkZNvpjLS6Xw93p8JU5iaMYyLh4k86VzNN6U78ra23/6JnnA4N9bxbDGZufuAw",
+ "6PlSj42kBFDKdQo5PywEV9r3YclOKMHD1ugwYObmsVDaHk96XWe6aWisc4mQr2fQ5RTVLmBKuNX/Wbb1",
+ "2NPxpA445wg8fmWvbbz4B0o60STKxUmFlepZ9g1Mjj3LGajfHEd39zoC5VFbS0X/5uZmP/dQaPPaOLpp",
+ "cpj9mhXi87W0Xxvm2iT3gojdxQA0ksAeTBuPllic/EN4XoPRxvorG5dAX0dtrdqD25rO5OI9pu2VAUKx",
+ "jTFfGTXeJ0KpM1ugJ127H8bqXKNncMOuS3Secy4+0XBh1neDetW06ZSyfB+H7b+Mhf1kfUnDHYl6DIdB",
+ "vw6wzemULKnQ7p/0zG9a5b/HGheC1/t1Hp0987BrFnEkV17A2nWNzRxWrr61wANqm43NNYtbyEVzuuKR",
+ "2xrdbPJqR1vcag8Zm7YTlql/6AB9bB88XCj9rV5y/W3qspd8d5m1Amkohv8kIW8PYlQVtrC4VXivv1Cc",
+ "K3bQcXH7rePn+2299/frtSSx63+bXP+zZfxC0aZ+XUJps5fp/K14/1Len7zZ6uvp7n73twAAAP//",
+}
- "H4sIAAAAAAAC/+RXW48budH9KwV+32OnNbEXedBTvB4vICBrT+LdvKznoYZdkmrBSw9Z1FgY6L8HRbZu",
- "I3k2QYIgQV506WY1T51zqlj9bGz0YwwUJJv5s8l2TR7rzw8pxaQ/xhRHSsJUL9s4kH4PlG3iUTgGM2+L",
- "od7rzDImj2LmhoO8fWM6I9uR2l9aUTK7znjKGVfffND+9iE0S+KwMrtdZxI9Fk40mPkvZtpwv/x+15mP",
- "9HRHcok7oL+y3Uf0BHEJsiYYSS437Izg6jLup+34etwLoHV3hTdhQ+c+Lc38l2fz/4mWZm7+b3YUYjap",
- "MJty2XUvk+HhEtLPgR8LAQ/nuE7F+MN3V8R4gZQHc7+73+llDsvYJA+CtuImj+zM3ODIQuj/mJ9wtaLU",
- "czTdRLH53K7Bu7sF/EToTWdK0qC1yJjns9lJ0K57kcU7yOhHRzVa1ihQMmVAzSZLTASYAQPQ17ZMIgzk",
- "Y8iSUAiWhFISZeBQOfg0UtAnve1vII9keckW61adcWwpZDqaw7wb0a4J3vQ3F5ifnp56rLf7mFazKTbP",
- "/rR4/+Hj5w+/e9Pf9GvxrjqGks+flp8pbdjS1cRndc1M5WBxp6zdTXmazmwo5cbK7/ub/kYfHUcKOLKZ",
- "m7f1UmdGlHX1xEwZ0h+rZrFzXv9CUlLIgM5VKmGZoq8U5W0W8o1r/V8yJVgry9ZSziDxS/iIHjINYGMY",
- "2FOQ4oGy9PAjkqWAGYT8GBNkXLEIZ8g4MoUOAllI6xhsyZDJnyxgAfQkPbyjQBgABVYJNzwgYFkV6gAt",
- "MNriuIb28L4kfGApCeLAEVxM5DuIKWAioBUJkKMJXSDbgS0pl6wl4chKyT3cFs7gGaSkkXMHY3EbDph0",
- "L0pRk+5AOFgeShDYYOKS4deSJfawCLBGC2sFgTkTjA6FEAa2UrzSsWhFpbngwCNny2EFGESzOebueFUc",
- "HjIf15hIEu5J1PXgo6MsTMB+pDSwMvVX3qBvCaHjx4IeBkZlJmGGR81tQ44FQgwgMUlMSgkvKQyH3Xu4",
- "S0iZgihMCuyPAEoKCJvoiowosKFAARVwI1c/PJakz1iE45OXlCbWl2jZcT7bpO6gH91RXws5DuhIhR06",
- "5dFSQtHE9LuHzyWPFAZWlh2qeYboYurUgZmsqJtrltUqmnUHG1qzLQ5BW1saigfHD5RiDz/G9MBAhbOP",
- "w6kMersa26HlwNh/CV/CZxqqEiXDktR8Lj7EVAMoHh2TiqTie9Da8FgfOJHP2XVA5axamuTgivpQ3dnD",
- "3RozOdcKY6Q0hVeaq7wksMRi+aE0wnG/j647jd+Qm6TjDaWE3fnWWifAQ3coxMAP6x5+FhjJOQpCWU+O",
- "MeZCWkn7IupBqcB9FWjR7bncP2mfVmWyq0AOtgglWJDEWerBtGFB6uGHki0BSe0GQ+FDFWinyJYcJa5w",
- "mn/3AV7dUrCaxxafMYDHlaZMblKrhz+XFuqjU92aelSad45QukPzASxWi6StnOzZ0p7MMTWZQzWqWVRg",
- "4NAdoUyFGzjzHnBWDJalDKxQc0YosvfZJGTb6Yy0ul8Pd6fCVOYmjGMi4eJPOlczTelO/K2tt/+iZ5wO",
- "DfW8Wwxmbn7gMOj5Uo+NpARQynUKOT8sBFfa92HJTijBw9boMGDm5rFQ2h5Pel1numlorHOJkK9n0OUU",
- "1S5gSrjV/1m29djT8aQOOOcIPH5lr228+AdKOtEkysVJhZXqWfYNTI49yxmo3xxHd/c6AuVRW0tF/+bm",
- "Zj/3UGjz2ji6aXKY/ZoV4vO1tF8b5tok94KI3cUANJLAHkwbj5ZYnPxDeF6D0cb6KxuXQF9Hba3ag9ua",
- "zuTiPabtlQFCsY0xXxk13idCqTNboCddux/G6lyjZ3DDrkt0nnMuPtFwYdZ3g3rVtOmUsnwfh+2/jIX9",
- "ZH1Jwx2JegyHQb8OsM3plCyp0O6f9MxvWuW/xxoXgtf7dR6dPfOwaxZxJFdewNp1jc0cVq6+tcADapuN",
- "zTWLW8hFc7rikdsa3Wzyakdb3GoPGZu2E5apf+gAfWwfPFwo/a1ecv1t6rKXfHeZtQJpKIb/JCFvD2JU",
- "FbawuFV4r79QnCt20HFx+63j5/ttvff367Ukset/m1z/s2X8QtGmfl1CabOX6fyteP9S3p+82err6e5+",
- "97cAAAD//ykDnxlaEgAA",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -196,7 +216,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -214,12 +234,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -245,3 +265,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/examples/petstore-expanded/echo/api/petstore.go b/examples/petstore-expanded/echo/api/petstore.go
index a95997cb2e..9934fa9921 100644
--- a/examples/petstore-expanded/echo/api/petstore.go
+++ b/examples/petstore-expanded/echo/api/petstore.go
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=models.cfg.yaml ../../petstore-expanded.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=models.cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../../petstore-expanded.yaml
package api
@@ -22,8 +22,8 @@ import (
"net/http"
"sync"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/echo/api/models"
"github.com/labstack/echo/v4"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo/api/models"
)
type PetStore struct {
diff --git a/examples/petstore-expanded/echo/api/server.cfg.yaml b/examples/petstore-expanded/echo/api/server.cfg.yaml
index 3c93576d54..534f4d8f59 100644
--- a/examples/petstore-expanded/echo/api/server.cfg.yaml
+++ b/examples/petstore-expanded/echo/api/server.cfg.yaml
@@ -1,7 +1,8 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
output: petstore-server.gen.go
additional-imports:
- - package: github.com/deepmap/oapi-codegen/examples/petstore-expanded/echo/api/models
+ - package: github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo/api/models
alias: .
generate:
echo-server: true
diff --git a/examples/petstore-expanded/echo/petstore.go b/examples/petstore-expanded/echo/petstore.go
index bbba8e5f6c..a764f00b04 100644
--- a/examples/petstore-expanded/echo/petstore.go
+++ b/examples/petstore-expanded/echo/petstore.go
@@ -11,17 +11,16 @@ import (
"net"
"os"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/echo/api"
"github.com/labstack/echo/v4"
- echomiddleware "github.com/labstack/echo/v4/middleware"
middleware "github.com/oapi-codegen/echo-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo/api"
)
func main() {
port := flag.String("port", "8080", "Port for test HTTP server")
flag.Parse()
- swagger, err := api.GetSwagger()
+ swagger, err := api.GetSpec()
if err != nil {
fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
os.Exit(1)
@@ -36,8 +35,6 @@ func main() {
// This is how you set up a basic Echo router
e := echo.New()
- // Log all requests
- e.Use(echomiddleware.Logger())
// Use our validation middleware to check all requests against the
// OpenAPI schema.
e.Use(middleware.OapiRequestValidator(swagger))
diff --git a/examples/petstore-expanded/echo/petstore_test.go b/examples/petstore-expanded/echo/petstore_test.go
index 20fd59d06d..eb3b8c1652 100644
--- a/examples/petstore-expanded/echo/petstore_test.go
+++ b/examples/petstore-expanded/echo/petstore_test.go
@@ -19,12 +19,11 @@ import (
"net/http"
"testing"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/echo/api"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/echo/api/models"
- "github.com/deepmap/oapi-codegen/pkg/testutil"
"github.com/labstack/echo/v4"
- echoMiddleware "github.com/labstack/echo/v4/middleware"
middleware "github.com/oapi-codegen/echo-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo/api"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo/api/models"
+ "github.com/oapi-codegen/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -38,7 +37,7 @@ func TestPetStore(t *testing.T) {
store := api.NewPetStore()
// Get the swagger description of our API
- swagger, err := api.GetSwagger()
+ swagger, err := api.GetSpec()
require.NoError(t, err)
// This disables swagger server name validation. It seems to work poorly,
@@ -48,9 +47,6 @@ func TestPetStore(t *testing.T) {
// Validate requests against the OpenAPI spec
e.Use(middleware.OapiRequestValidator(swagger))
- // Log requests
- e.Use(echoMiddleware.Logger())
-
// We register the autogenerated boilerplate and bind our PetStore to this
// echo router.
api.RegisterHandlers(e, store)
@@ -64,7 +60,7 @@ func TestPetStore(t *testing.T) {
Name: "Spot",
Tag: &tag,
}
- result := testutil.NewRequest().Post("/pets").WithJsonBody(newPet).Go(t, e)
+ result := testutil.NewRequest().Post("/pets").WithJsonBody(newPet).GoWithHTTPHandler(t, e)
// We expect 201 code on successful pet insertion
assert.Equal(t, http.StatusCreated, result.Code())
@@ -80,14 +76,14 @@ func TestPetStore(t *testing.T) {
petId := resultPet.Id
// Test the getter function.
- result = testutil.NewRequest().Get(fmt.Sprintf("/pets/%d", petId)).WithAcceptJson().Go(t, e)
+ result = testutil.NewRequest().Get(fmt.Sprintf("/pets/%d", petId)).WithAcceptJson().GoWithHTTPHandler(t, e)
var resultPet2 models.Pet
err = result.UnmarshalBodyToObject(&resultPet2)
assert.NoError(t, err, "error getting pet")
assert.Equal(t, resultPet, resultPet2)
// We should get a 404 on invalid ID
- result = testutil.NewRequest().Get("/pets/27179095781").WithAcceptJson().Go(t, e)
+ result = testutil.NewRequest().Get("/pets/27179095781").WithAcceptJson().GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusNotFound, result.Code())
var petError models.Error
err = result.UnmarshalBodyToObject(&petError)
@@ -100,7 +96,7 @@ func TestPetStore(t *testing.T) {
Name: "Fido",
Tag: &tag,
}
- result = testutil.NewRequest().Post("/pets").WithJsonBody(newPet).Go(t, e)
+ result = testutil.NewRequest().Post("/pets").WithJsonBody(newPet).GoWithHTTPHandler(t, e)
// We expect 201 code on successful pet insertion
assert.Equal(t, http.StatusCreated, result.Code())
// We should have gotten a response from the server with the new pet. Make
@@ -110,7 +106,7 @@ func TestPetStore(t *testing.T) {
petId2 := resultPet.Id
// Now, list all pets, we should have two
- result = testutil.NewRequest().Get("/pets").WithAcceptJson().Go(t, e)
+ result = testutil.NewRequest().Get("/pets").WithAcceptJson().GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
var petList []models.Pet
err = result.UnmarshalBodyToObject(&petList)
@@ -119,7 +115,7 @@ func TestPetStore(t *testing.T) {
// Filter pets by tag, we should have 1
petList = nil
- result = testutil.NewRequest().Get("/pets?tags=TagOfFido").WithAcceptJson().Go(t, e)
+ result = testutil.NewRequest().Get("/pets?tags=TagOfFido").WithAcceptJson().GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
err = result.UnmarshalBodyToObject(&petList)
assert.NoError(t, err, "error getting response", err)
@@ -127,28 +123,28 @@ func TestPetStore(t *testing.T) {
// Filter pets by non existent tag, we should have 0
petList = nil
- result = testutil.NewRequest().Get("/pets?tags=NotExists").WithAcceptJson().Go(t, e)
+ result = testutil.NewRequest().Get("/pets?tags=NotExists").WithAcceptJson().GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
err = result.UnmarshalBodyToObject(&petList)
assert.NoError(t, err, "error getting response", err)
assert.Equal(t, 0, len(petList))
// Let's delete non-existent pet
- result = testutil.NewRequest().Delete("/pets/7").Go(t, e)
+ result = testutil.NewRequest().Delete("/pets/7").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusNotFound, result.Code())
err = result.UnmarshalBodyToObject(&petError)
assert.NoError(t, err, "error unmarshaling PetError")
assert.Equal(t, int32(http.StatusNotFound), petError.Code)
// Now, delete both real pets
- result = testutil.NewRequest().Delete(fmt.Sprintf("/pets/%d", petId)).Go(t, e)
+ result = testutil.NewRequest().Delete(fmt.Sprintf("/pets/%d", petId)).GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusNoContent, result.Code())
- result = testutil.NewRequest().Delete(fmt.Sprintf("/pets/%d", petId2)).Go(t, e)
+ result = testutil.NewRequest().Delete(fmt.Sprintf("/pets/%d", petId2)).GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusNoContent, result.Code())
// Should have no pets left.
petList = nil
- result = testutil.NewRequest().Get("/pets").WithAcceptJson().Go(t, e)
+ result = testutil.NewRequest().Get("/pets").WithAcceptJson().GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
err = result.UnmarshalBodyToObject(&petList)
assert.NoError(t, err, "error getting response", err)
diff --git a/examples/petstore-expanded/echo/pkg_codegen_petstore_test.go b/examples/petstore-expanded/echo/pkg_codegen_petstore_test.go
index 4ced8b42cc..1f13ce4784 100644
--- a/examples/petstore-expanded/echo/pkg_codegen_petstore_test.go
+++ b/examples/petstore-expanded/echo/pkg_codegen_petstore_test.go
@@ -9,9 +9,9 @@ import (
"net/http/httptest"
"testing"
- examplePetstoreClient "github.com/deepmap/oapi-codegen/examples/petstore-expanded"
- examplePetstore "github.com/deepmap/oapi-codegen/examples/petstore-expanded/echo/api"
- "github.com/deepmap/oapi-codegen/pkg/codegen"
+ examplePetstoreClient "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded"
+ examplePetstore "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/echo/api"
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/codegen"
"github.com/stretchr/testify/assert"
"golang.org/x/lint"
)
@@ -38,7 +38,7 @@ func TestExamplePetStoreCodeGeneration(t *testing.T) {
}
// Get a spec from the example PetStore definition:
- swagger, err := examplePetstore.GetSwagger()
+ swagger, err := examplePetstore.GetSpec()
assert.NoError(t, err)
// Run our code generation:
@@ -85,7 +85,7 @@ func TestExamplePetStoreCodeGenerationWithUserTemplates(t *testing.T) {
}
// Get a spec from the example PetStore definition:
- swagger, err := examplePetstore.GetSwagger()
+ swagger, err := examplePetstore.GetSpec()
assert.NoError(t, err)
// Run our code generation:
@@ -121,7 +121,7 @@ func TestExamplePetStoreCodeGenerationWithFileUserTemplates(t *testing.T) {
}
// Get a spec from the example PetStore definition:
- swagger, err := examplePetstore.GetSwagger()
+ swagger, err := examplePetstore.GetSpec()
assert.NoError(t, err)
// Run our code generation:
@@ -162,7 +162,7 @@ func TestExamplePetStoreCodeGenerationWithHTTPUserTemplates(t *testing.T) {
}
// Get a spec from the example PetStore definition:
- swagger, err := examplePetstore.GetSwagger()
+ swagger, err := examplePetstore.GetSpec()
assert.NoError(t, err)
// Run our code generation:
diff --git a/examples/petstore-expanded/fiber/api/petstore-server.gen.go b/examples/petstore-expanded/fiber/api/petstore-server.gen.go
index d8872321c6..fe76a2fba4 100644
--- a/examples/petstore-expanded/fiber/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/fiber/api/petstore-server.gen.go
@@ -1,11 +1,11 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/url"
@@ -35,15 +35,18 @@ type ServerInterface interface {
// ServerInterfaceWrapper converts contexts to parameters.
type ServerInterfaceWrapper struct {
- Handler ServerInterface
+ Handler ServerInterface
+ HandlerMiddlewares []HandlerMiddlewareFunc
}
type MiddlewareFunc fiber.Handler
+type HandlerMiddlewareFunc func(c *fiber.Ctx, next fiber.Handler) error
// FindPets operation middleware
func (siw *ServerInterfaceWrapper) FindPets(c *fiber.Ctx) error {
var err error
+ _ = err
// Parameter object where we will unmarshal all parameters from the context
var params FindPetsParams
@@ -56,63 +59,114 @@ func (siw *ServerInterfaceWrapper) FindPets(c *fiber.Ctx) error {
// ------------- Optional query parameter "tags" -------------
- err = runtime.BindQueryParameter("form", true, false, "tags", query, ¶ms.Tags)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "tags", query, ¶ms.Tags, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter tags: %w", err).Error())
}
// ------------- Optional query parameter "limit" -------------
- err = runtime.BindQueryParameter("form", true, false, "limit", query, ¶ms.Limit)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", query, ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter limit: %w", err).Error())
}
- return siw.Handler.FindPets(c, params)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.FindPets(c, params)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// AddPet operation middleware
func (siw *ServerInterfaceWrapper) AddPet(c *fiber.Ctx) error {
- return siw.Handler.AddPet(c)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.AddPet(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// DeletePet operation middleware
func (siw *ServerInterfaceWrapper) DeletePet(c *fiber.Ctx) error {
var err error
+ _ = err
// ------------- Path parameter "id" -------------
var id int64
- err = runtime.BindStyledParameter("simple", false, "id", c.Params("id"), &id)
+ err = runtime.BindStyledParameterWithOptions("simple", "id", c.Params("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error())
}
- return siw.Handler.DeletePet(c, id)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.DeletePet(c, id)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// FindPetByID operation middleware
func (siw *ServerInterfaceWrapper) FindPetByID(c *fiber.Ctx) error {
var err error
+ _ = err
// ------------- Path parameter "id" -------------
var id int64
- err = runtime.BindStyledParameter("simple", false, "id", c.Params("id"), &id)
+ err = runtime.BindStyledParameterWithOptions("simple", "id", c.Params("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error())
}
- return siw.Handler.FindPetByID(c, id)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.FindPetByID(c, id)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// FiberServerOptions provides options for the Fiber server.
type FiberServerOptions struct {
- BaseURL string
- Middlewares []MiddlewareFunc
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ HandlerMiddlewares []HandlerMiddlewareFunc
}
// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
@@ -123,11 +177,12 @@ func RegisterHandlers(router fiber.Router, si ServerInterface) {
// RegisterHandlersWithOptions creates http.Handler with additional options
func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
wrapper := ServerInterfaceWrapper{
- Handler: si,
+ Handler: si,
+ HandlerMiddlewares: options.HandlerMiddlewares,
}
for _, m := range options.Middlewares {
- router.Use(m)
+ router.Use(fiber.Handler(m))
}
router.Get(options.BaseURL+"/pets", wrapper.FindPets)
@@ -140,54 +195,55 @@ func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, option
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
+ "5Fdbjxu50f0rBX7fY6c1sRd50FO8Hi8gIGtP4t28rOehhl2SasFLD1nUWBjovwdFtm4jeTZBgiBBXnTp",
+ "ZjVPnXOqWP1sbPRjDBQkm/mzyXZNHuvPDynFpD/GFEdKwlQv2ziQfg+UbeJROAYzb4uh3uvMMiaPYuaG",
+ "g7x9Yzoj25HaX1pRMrvOeMoZV9980P72ITRL4rAyu11nEj0WTjSY+S9m2nC//H7XmY/0dEdyiTugv7Ld",
+ "R/QEcQmyJhhJLjfsjODqMu6n7fh63AugdXeFN2FD5z4tzfyXZ/P/iZZmbv5vdhRiNqkwm3LZdS+T4eES",
+ "0s+BHwsBD+e4TsX4w3dXxHiBlAdzv7vf6WUOy9gkD4K24iaP7Mzc4MhC6P+Yn3C1otRzNN1EsfncrsG7",
+ "uwX8ROhNZ0rSoLXImOez2UnQrnuRxTvI6EdHNVrWKFAyZUDNJktMBJgBA9DXtkwiDORjyJJQCJaEUhJl",
+ "4FA5+DRS0Ce97W8gj2R5yRbrVp1xbClkOprDvBvRrgne9DcXmJ+ennqst/uYVrMpNs/+tHj/4ePnD797",
+ "09/0a/GuOoaSz5+Wnylt2NLVxGd1zUzlYHGnrN1NeZrObCjlxsrv+5v+Rh8dRwo4spmbt/VSZ0aUdfXE",
+ "TBnSH6tmsXNe/0JSUsiAzlUqYZmirxTlbRbyjWv9XzIlWCvL1lLOIPFL+IgeMg1gYxjYU5DigbL08COS",
+ "pYAZhPwYE2RcsQhnyDgyhQ4CWUjrGGzJkMmfLGAB9CQ9vKNAGAAFVgk3PCBgWRXqAC0w2uK4hvbwviR8",
+ "YCkJ4sARXEzkO4gpYCKgFQmQowldINuBLSmXrCXhyErJPdwWzuAZpKSRcwdjcRsOmHQvSlGT7kA4WB5K",
+ "ENhg4pLh15Il9rAIsEYLawWBOROMDoUQBrZSvNKxaEWlueDAI2fLYQUYRLM55u54VRweMh/XmEgS7knU",
+ "9eCjoyxMwH6kNLAy9VfeoG8JoePHgh4GRmUmYYZHzW1DjgVCDCAxSUxKCS8pDIfde7hLSJmCKEwK7I8A",
+ "SgoIm+iKjCiwoUABFXAjVz88lqTPWITjk5eUJtaXaNlxPtuk7qAf3VFfCzkO6EiFHTrl0VJC0cT0u4fP",
+ "JY8UBlaWHap5huhi6tSBmayom2uW1SqadQcbWrMtDkFbWxqKB8cPlGIPP8b0wECFs4/DqQx6uxrboeXA",
+ "2H8JX8JnGqoSJcOS1HwuPsRUAygeHZOKpOJ70NrwWB84kc/ZdUDlrFqa5OCK+lDd2cPdGjM51wpjpDSF",
+ "V5qrvCSwxGL5oTTCcb+PrjuN35CbpOMNpYTd+dZaJ8BDdyjEwA/rHn4WGMk5CkJZT44x5kJaSfsi6kGp",
+ "wH0VaNHtudw/aZ9WZbKrQA62CCVYkMRZ6sG0YUHq4YeSLQFJ7QZD4UMVaKfIlhwlrnCaf/cBXt1SsJrH",
+ "Fp8xgMeVpkxuUquHP5cW6qNT3Zp6VJp3jlC6Q/MBLFaLpK2c7NnSnswxNZlDNapZVGDg0B2hTIUbOPMe",
+ "cFYMlqUMrFBzRiiy99kkZNvpjLS6Xw93p8JU5iaMYyLh4k86VzNN6U78ra23/6JnnA4N9bxbDGZufuAw",
+ "6PlSj42kBFDKdQo5PywEV9r3YclOKMHD1ugwYObmsVDaHk96XWe6aWisc4mQr2fQ5RTVLmBKuNX/Wbb1",
+ "2NPxpA445wg8fmWvbbz4B0o60STKxUmFlepZ9g1Mjj3LGajfHEd39zoC5VFbS0X/5uZmP/dQaPPaOLpp",
+ "cpj9mhXi87W0Xxvm2iT3gojdxQA0ksAeTBuPllic/EN4XoPRxvorG5dAX0dtrdqD25rO5OI9pu2VAUKx",
+ "jTFfGTXeJ0KpM1ugJ127H8bqXKNncMOuS3Secy4+0XBh1neDetW06ZSyfB+H7b+Mhf1kfUnDHYl6DIdB",
+ "vw6wzemULKnQ7p/0zG9a5b/HGheC1/t1Hp0987BrFnEkV17A2nWNzRxWrr61wANqm43NNYtbyEVzuuKR",
+ "2xrdbPJqR1vcag8Zm7YTlql/6AB9bB88XCj9rV5y/W3qspd8d5m1Amkohv8kIW8PYlQVtrC4VXivv1Cc",
+ "K3bQcXH7rePn+2299/frtSSx63+bXP+zZfxC0aZ+XUJps5fp/K14/1Len7zZ6uvp7n73twAAAP//",
+}
- "H4sIAAAAAAAC/+RXW48budH9KwV+32OnNbEXedBTvB4vICBrT+LdvKznoYZdkmrBSw9Z1FgY6L8HRbZu",
- "I3k2QYIgQV506WY1T51zqlj9bGz0YwwUJJv5s8l2TR7rzw8pxaQ/xhRHSsJUL9s4kH4PlG3iUTgGM2+L",
- "od7rzDImj2LmhoO8fWM6I9uR2l9aUTK7znjKGVfffND+9iE0S+KwMrtdZxI9Fk40mPkvZtpwv/x+15mP",
- "9HRHcok7oL+y3Uf0BHEJsiYYSS437Izg6jLup+34etwLoHV3hTdhQ+c+Lc38l2fz/4mWZm7+b3YUYjap",
- "MJty2XUvk+HhEtLPgR8LAQ/nuE7F+MN3V8R4gZQHc7+73+llDsvYJA+CtuImj+zM3ODIQuj/mJ9wtaLU",
- "czTdRLH53K7Bu7sF/EToTWdK0qC1yJjns9lJ0K57kcU7yOhHRzVa1ihQMmVAzSZLTASYAQPQ17ZMIgzk",
- "Y8iSUAiWhFISZeBQOfg0UtAnve1vII9keckW61adcWwpZDqaw7wb0a4J3vQ3F5ifnp56rLf7mFazKTbP",
- "/rR4/+Hj5w+/e9Pf9GvxrjqGks+flp8pbdjS1cRndc1M5WBxp6zdTXmazmwo5cbK7/ub/kYfHUcKOLKZ",
- "m7f1UmdGlHX1xEwZ0h+rZrFzXv9CUlLIgM5VKmGZoq8U5W0W8o1r/V8yJVgry9ZSziDxS/iIHjINYGMY",
- "2FOQ4oGy9PAjkqWAGYT8GBNkXLEIZ8g4MoUOAllI6xhsyZDJnyxgAfQkPbyjQBgABVYJNzwgYFkV6gAt",
- "MNriuIb28L4kfGApCeLAEVxM5DuIKWAioBUJkKMJXSDbgS0pl6wl4chKyT3cFs7gGaSkkXMHY3EbDph0",
- "L0pRk+5AOFgeShDYYOKS4deSJfawCLBGC2sFgTkTjA6FEAa2UrzSsWhFpbngwCNny2EFGESzOebueFUc",
- "HjIf15hIEu5J1PXgo6MsTMB+pDSwMvVX3qBvCaHjx4IeBkZlJmGGR81tQ44FQgwgMUlMSgkvKQyH3Xu4",
- "S0iZgihMCuyPAEoKCJvoiowosKFAARVwI1c/PJakz1iE45OXlCbWl2jZcT7bpO6gH91RXws5DuhIhR06",
- "5dFSQtHE9LuHzyWPFAZWlh2qeYboYurUgZmsqJtrltUqmnUHG1qzLQ5BW1saigfHD5RiDz/G9MBAhbOP",
- "w6kMersa26HlwNh/CV/CZxqqEiXDktR8Lj7EVAMoHh2TiqTie9Da8FgfOJHP2XVA5axamuTgivpQ3dnD",
- "3RozOdcKY6Q0hVeaq7wksMRi+aE0wnG/j647jd+Qm6TjDaWE3fnWWifAQ3coxMAP6x5+FhjJOQpCWU+O",
- "MeZCWkn7IupBqcB9FWjR7bncP2mfVmWyq0AOtgglWJDEWerBtGFB6uGHki0BSe0GQ+FDFWinyJYcJa5w",
- "mn/3AV7dUrCaxxafMYDHlaZMblKrhz+XFuqjU92aelSad45QukPzASxWi6StnOzZ0p7MMTWZQzWqWVRg",
- "4NAdoUyFGzjzHnBWDJalDKxQc0YosvfZJGTb6Yy0ul8Pd6fCVOYmjGMi4eJPOlczTelO/K2tt/+iZ5wO",
- "DfW8Wwxmbn7gMOj5Uo+NpARQynUKOT8sBFfa92HJTijBw9boMGDm5rFQ2h5Pel1numlorHOJkK9n0OUU",
- "1S5gSrjV/1m29djT8aQOOOcIPH5lr228+AdKOtEkysVJhZXqWfYNTI49yxmo3xxHd/c6AuVRW0tF/+bm",
- "Zj/3UGjz2ji6aXKY/ZoV4vO1tF8b5tok94KI3cUANJLAHkwbj5ZYnPxDeF6D0cb6KxuXQF9Hba3ag9ua",
- "zuTiPabtlQFCsY0xXxk13idCqTNboCddux/G6lyjZ3DDrkt0nnMuPtFwYdZ3g3rVtOmUsnwfh+2/jIX9",
- "ZH1Jwx2JegyHQb8OsM3plCyp0O6f9MxvWuW/xxoXgtf7dR6dPfOwaxZxJFdewNp1jc0cVq6+tcADapuN",
- "zTWLW8hFc7rikdsa3Wzyakdb3GoPGZu2E5apf+gAfWwfPFwo/a1ecv1t6rKXfHeZtQJpKIb/JCFvD2JU",
- "FbawuFV4r79QnCt20HFx+63j5/ttvff367Ukset/m1z/s2X8QtGmfl1CabOX6fyteP9S3p+82err6e5+",
- "97cAAAD//ykDnxlaEgAA",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -195,7 +251,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -213,12 +269,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -244,3 +300,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/examples/petstore-expanded/fiber/api/petstore-types.gen.go b/examples/petstore-expanded/fiber/api/petstore-types.gen.go
index 551af8d9d0..0e4954f349 100644
--- a/examples/petstore-expanded/fiber/api/petstore-types.gen.go
+++ b/examples/petstore-expanded/fiber/api/petstore-types.gen.go
@@ -1,6 +1,6 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
// Error defines model for Error.
diff --git a/examples/petstore-expanded/fiber/api/petstore.go b/examples/petstore-expanded/fiber/api/petstore.go
index f69566b812..38eec12d65 100644
--- a/examples/petstore-expanded/fiber/api/petstore.go
+++ b/examples/petstore-expanded/fiber/api/petstore.go
@@ -1,5 +1,5 @@
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../../petstore-expanded.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../../petstore-expanded.yaml
package api
diff --git a/examples/petstore-expanded/fiber/api/server.cfg.yaml b/examples/petstore-expanded/fiber/api/server.cfg.yaml
index 91ef1331d2..6384086293 100644
--- a/examples/petstore-expanded/fiber/api/server.cfg.yaml
+++ b/examples/petstore-expanded/fiber/api/server.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
fiber-server: true
diff --git a/examples/petstore-expanded/fiber/api/types.cfg.yaml b/examples/petstore-expanded/fiber/api/types.cfg.yaml
index 9ac30e11e9..cf5128b726 100644
--- a/examples/petstore-expanded/fiber/api/types.cfg.yaml
+++ b/examples/petstore-expanded/fiber/api/types.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
models: true
diff --git a/examples/petstore-expanded/fiber/petstore.go b/examples/petstore-expanded/fiber/petstore.go
index 7374cbe1cb..eb6ddac31c 100644
--- a/examples/petstore-expanded/fiber/petstore.go
+++ b/examples/petstore-expanded/fiber/petstore.go
@@ -13,8 +13,8 @@ import (
"github.com/gofiber/fiber/v2"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/fiber/api"
middleware "github.com/oapi-codegen/fiber-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/fiber/api"
)
func main() {
@@ -32,7 +32,7 @@ func main() {
func NewFiberPetServer(petStore *api.PetStore) *fiber.App {
- swagger, err := api.GetSwagger()
+ swagger, err := api.GetSpec()
if err != nil {
fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
os.Exit(1)
diff --git a/examples/petstore-expanded/fiber/petstore_test.go b/examples/petstore-expanded/fiber/petstore_test.go
index e6a103ace9..7ddc14e426 100644
--- a/examples/petstore-expanded/fiber/petstore_test.go
+++ b/examples/petstore-expanded/fiber/petstore_test.go
@@ -12,7 +12,7 @@ import (
"github.com/gofiber/fiber/v2"
"github.com/stretchr/testify/assert"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/fiber/api"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/fiber/api"
)
func doGet(t *testing.T, app *fiber.App, rawURL string) (*http.Response, error) {
@@ -24,7 +24,7 @@ func doGet(t *testing.T, app *fiber.App, rawURL string) (*http.Response, error)
req := httptest.NewRequest("GET", u.RequestURI(), nil)
req.Header.Add("Accept", "application/json")
- req.Host = u.Host
+ req.Host = "example.com"
return app.Test(req)
}
@@ -42,7 +42,7 @@ func doPost(t *testing.T, app *fiber.App, rawURL string, jsonBody interface{}) (
req := httptest.NewRequest("POST", u.RequestURI(), bytes.NewReader(buf))
req.Header.Add("Accept", "application/json")
req.Header.Add("Content-Type", "application/json")
- req.Host = u.Host
+ req.Host = "example.com"
return app.Test(req)
}
@@ -54,7 +54,7 @@ func doDelete(t *testing.T, app *fiber.App, rawURL string) (*http.Response, erro
req := httptest.NewRequest("DELETE", u.RequestURI(), nil)
req.Header.Add("Accept", "application/json")
- req.Host = u.Host
+ req.Host = "example.com"
return app.Test(req)
}
diff --git a/examples/petstore-expanded/gin/api/petstore-server.gen.go b/examples/petstore-expanded/gin/api/petstore-server.gen.go
index b96d513dba..4a2d6f9e5c 100644
--- a/examples/petstore-expanded/gin/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/gin/api/petstore-server.gen.go
@@ -1,11 +1,11 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/http"
@@ -47,13 +47,14 @@ type MiddlewareFunc func(c *gin.Context)
func (siw *ServerInterfaceWrapper) FindPets(c *gin.Context) {
var err error
+ _ = err
// Parameter object where we will unmarshal all parameters from the context
var params FindPetsParams
// ------------- Optional query parameter "tags" -------------
- err = runtime.BindQueryParameter("form", true, false, "tags", c.Request.URL.Query(), ¶ms.Tags)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "tags", c.Request.URL.Query(), ¶ms.Tags, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter tags: %w", err), http.StatusBadRequest)
return
@@ -61,7 +62,7 @@ func (siw *ServerInterfaceWrapper) FindPets(c *gin.Context) {
// ------------- Optional query parameter "limit" -------------
- err = runtime.BindQueryParameter("form", true, false, "limit", c.Request.URL.Query(), ¶ms.Limit)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", c.Request.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter limit: %w", err), http.StatusBadRequest)
return
@@ -94,11 +95,12 @@ func (siw *ServerInterfaceWrapper) AddPet(c *gin.Context) {
func (siw *ServerInterfaceWrapper) DeletePet(c *gin.Context) {
var err error
+ _ = err
// ------------- Path parameter "id" -------------
var id int64
- err = runtime.BindStyledParameter("simple", false, "id", c.Param("id"), &id)
+ err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest)
return
@@ -118,11 +120,12 @@ func (siw *ServerInterfaceWrapper) DeletePet(c *gin.Context) {
func (siw *ServerInterfaceWrapper) FindPetByID(c *gin.Context) {
var err error
+ _ = err
// ------------- Path parameter "id" -------------
var id int64
- err = runtime.BindStyledParameter("simple", false, "id", c.Param("id"), &id)
+ err = runtime.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest)
return
@@ -171,54 +174,55 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options
router.GET(options.BaseURL+"/pets/:id", wrapper.FindPetByID)
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/+RXW48budH9KwV+32OnNbEXedBTvB4vICBrT+LdvKznoYZdkmrBSw9Z1FgY6L8HRbZu",
- "I3k2QYIgQV506WY1T51zqlj9bGz0YwwUJJv5s8l2TR7rzw8pxaQ/xhRHSsJUL9s4kH4PlG3iUTgGM2+L",
- "od7rzDImj2LmhoO8fWM6I9uR2l9aUTK7znjKGVfffND+9iE0S+KwMrtdZxI9Fk40mPkvZtpwv/x+15mP",
- "9HRHcok7oL+y3Uf0BHEJsiYYSS437Izg6jLup+34etwLoHV3hTdhQ+c+Lc38l2fz/4mWZm7+b3YUYjap",
- "MJty2XUvk+HhEtLPgR8LAQ/nuE7F+MN3V8R4gZQHc7+73+llDsvYJA+CtuImj+zM3ODIQuj/mJ9wtaLU",
- "czTdRLH53K7Bu7sF/EToTWdK0qC1yJjns9lJ0K57kcU7yOhHRzVa1ihQMmVAzSZLTASYAQPQ17ZMIgzk",
- "Y8iSUAiWhFISZeBQOfg0UtAnve1vII9keckW61adcWwpZDqaw7wb0a4J3vQ3F5ifnp56rLf7mFazKTbP",
- "/rR4/+Hj5w+/e9Pf9GvxrjqGks+flp8pbdjS1cRndc1M5WBxp6zdTXmazmwo5cbK7/ub/kYfHUcKOLKZ",
- "m7f1UmdGlHX1xEwZ0h+rZrFzXv9CUlLIgM5VKmGZoq8U5W0W8o1r/V8yJVgry9ZSziDxS/iIHjINYGMY",
- "2FOQ4oGy9PAjkqWAGYT8GBNkXLEIZ8g4MoUOAllI6xhsyZDJnyxgAfQkPbyjQBgABVYJNzwgYFkV6gAt",
- "MNriuIb28L4kfGApCeLAEVxM5DuIKWAioBUJkKMJXSDbgS0pl6wl4chKyT3cFs7gGaSkkXMHY3EbDph0",
- "L0pRk+5AOFgeShDYYOKS4deSJfawCLBGC2sFgTkTjA6FEAa2UrzSsWhFpbngwCNny2EFGESzOebueFUc",
- "HjIf15hIEu5J1PXgo6MsTMB+pDSwMvVX3qBvCaHjx4IeBkZlJmGGR81tQ44FQgwgMUlMSgkvKQyH3Xu4",
- "S0iZgihMCuyPAEoKCJvoiowosKFAARVwI1c/PJakz1iE45OXlCbWl2jZcT7bpO6gH91RXws5DuhIhR06",
- "5dFSQtHE9LuHzyWPFAZWlh2qeYboYurUgZmsqJtrltUqmnUHG1qzLQ5BW1saigfHD5RiDz/G9MBAhbOP",
- "w6kMersa26HlwNh/CV/CZxqqEiXDktR8Lj7EVAMoHh2TiqTie9Da8FgfOJHP2XVA5axamuTgivpQ3dnD",
- "3RozOdcKY6Q0hVeaq7wksMRi+aE0wnG/j647jd+Qm6TjDaWE3fnWWifAQ3coxMAP6x5+FhjJOQpCWU+O",
- "MeZCWkn7IupBqcB9FWjR7bncP2mfVmWyq0AOtgglWJDEWerBtGFB6uGHki0BSe0GQ+FDFWinyJYcJa5w",
- "mn/3AV7dUrCaxxafMYDHlaZMblKrhz+XFuqjU92aelSad45QukPzASxWi6StnOzZ0p7MMTWZQzWqWVRg",
- "4NAdoUyFGzjzHnBWDJalDKxQc0YosvfZJGTb6Yy0ul8Pd6fCVOYmjGMi4eJPOlczTelO/K2tt/+iZ5wO",
- "DfW8Wwxmbn7gMOj5Uo+NpARQynUKOT8sBFfa92HJTijBw9boMGDm5rFQ2h5Pel1numlorHOJkK9n0OUU",
- "1S5gSrjV/1m29djT8aQOOOcIPH5lr228+AdKOtEkysVJhZXqWfYNTI49yxmo3xxHd/c6AuVRW0tF/+bm",
- "Zj/3UGjz2ji6aXKY/ZoV4vO1tF8b5tok94KI3cUANJLAHkwbj5ZYnPxDeF6D0cb6KxuXQF9Hba3ag9ua",
- "zuTiPabtlQFCsY0xXxk13idCqTNboCddux/G6lyjZ3DDrkt0nnMuPtFwYdZ3g3rVtOmUsnwfh+2/jIX9",
- "ZH1Jwx2JegyHQb8OsM3plCyp0O6f9MxvWuW/xxoXgtf7dR6dPfOwaxZxJFdewNp1jc0cVq6+tcADapuN",
- "zTWLW8hFc7rikdsa3Wzyakdb3GoPGZu2E5apf+gAfWwfPFwo/a1ecv1t6rKXfHeZtQJpKIb/JCFvD2JU",
- "FbawuFV4r79QnCt20HFx+63j5/ttvff367Ukset/m1z/s2X8QtGmfl1CabOX6fyteP9S3p+82err6e5+",
- "97cAAAD//ykDnxlaEgAA",
+ "5Fdbjxu50f0rBX7fY6c1sRd50FO8Hi8gIGtP4t28rOehhl2SasFLD1nUWBjovwdFtm4jeTZBgiBBXnTp",
+ "ZjVPnXOqWP1sbPRjDBQkm/mzyXZNHuvPDynFpD/GFEdKwlQv2ziQfg+UbeJROAYzb4uh3uvMMiaPYuaG",
+ "g7x9Yzoj25HaX1pRMrvOeMoZV9980P72ITRL4rAyu11nEj0WTjSY+S9m2nC//H7XmY/0dEdyiTugv7Ld",
+ "R/QEcQmyJhhJLjfsjODqMu6n7fh63AugdXeFN2FD5z4tzfyXZ/P/iZZmbv5vdhRiNqkwm3LZdS+T4eES",
+ "0s+BHwsBD+e4TsX4w3dXxHiBlAdzv7vf6WUOy9gkD4K24iaP7Mzc4MhC6P+Yn3C1otRzNN1EsfncrsG7",
+ "uwX8ROhNZ0rSoLXImOez2UnQrnuRxTvI6EdHNVrWKFAyZUDNJktMBJgBA9DXtkwiDORjyJJQCJaEUhJl",
+ "4FA5+DRS0Ce97W8gj2R5yRbrVp1xbClkOprDvBvRrgne9DcXmJ+ennqst/uYVrMpNs/+tHj/4ePnD797",
+ "09/0a/GuOoaSz5+Wnylt2NLVxGd1zUzlYHGnrN1NeZrObCjlxsrv+5v+Rh8dRwo4spmbt/VSZ0aUdfXE",
+ "TBnSH6tmsXNe/0JSUsiAzlUqYZmirxTlbRbyjWv9XzIlWCvL1lLOIPFL+IgeMg1gYxjYU5DigbL08COS",
+ "pYAZhPwYE2RcsQhnyDgyhQ4CWUjrGGzJkMmfLGAB9CQ9vKNAGAAFVgk3PCBgWRXqAC0w2uK4hvbwviR8",
+ "YCkJ4sARXEzkO4gpYCKgFQmQowldINuBLSmXrCXhyErJPdwWzuAZpKSRcwdjcRsOmHQvSlGT7kA4WB5K",
+ "ENhg4pLh15Il9rAIsEYLawWBOROMDoUQBrZSvNKxaEWlueDAI2fLYQUYRLM55u54VRweMh/XmEgS7knU",
+ "9eCjoyxMwH6kNLAy9VfeoG8JoePHgh4GRmUmYYZHzW1DjgVCDCAxSUxKCS8pDIfde7hLSJmCKEwK7I8A",
+ "SgoIm+iKjCiwoUABFXAjVz88lqTPWITjk5eUJtaXaNlxPtuk7qAf3VFfCzkO6EiFHTrl0VJC0cT0u4fP",
+ "JY8UBlaWHap5huhi6tSBmayom2uW1SqadQcbWrMtDkFbWxqKB8cPlGIPP8b0wECFs4/DqQx6uxrboeXA",
+ "2H8JX8JnGqoSJcOS1HwuPsRUAygeHZOKpOJ70NrwWB84kc/ZdUDlrFqa5OCK+lDd2cPdGjM51wpjpDSF",
+ "V5qrvCSwxGL5oTTCcb+PrjuN35CbpOMNpYTd+dZaJ8BDdyjEwA/rHn4WGMk5CkJZT44x5kJaSfsi6kGp",
+ "wH0VaNHtudw/aZ9WZbKrQA62CCVYkMRZ6sG0YUHq4YeSLQFJ7QZD4UMVaKfIlhwlrnCaf/cBXt1SsJrH",
+ "Fp8xgMeVpkxuUquHP5cW6qNT3Zp6VJp3jlC6Q/MBLFaLpK2c7NnSnswxNZlDNapZVGDg0B2hTIUbOPMe",
+ "cFYMlqUMrFBzRiiy99kkZNvpjLS6Xw93p8JU5iaMYyLh4k86VzNN6U78ra23/6JnnA4N9bxbDGZufuAw",
+ "6PlSj42kBFDKdQo5PywEV9r3YclOKMHD1ugwYObmsVDaHk96XWe6aWisc4mQr2fQ5RTVLmBKuNX/Wbb1",
+ "2NPxpA445wg8fmWvbbz4B0o60STKxUmFlepZ9g1Mjj3LGajfHEd39zoC5VFbS0X/5uZmP/dQaPPaOLpp",
+ "cpj9mhXi87W0Xxvm2iT3gojdxQA0ksAeTBuPllic/EN4XoPRxvorG5dAX0dtrdqD25rO5OI9pu2VAUKx",
+ "jTFfGTXeJ0KpM1ugJ127H8bqXKNncMOuS3Secy4+0XBh1neDetW06ZSyfB+H7b+Mhf1kfUnDHYl6DIdB",
+ "vw6wzemULKnQ7p/0zG9a5b/HGheC1/t1Hp0987BrFnEkV17A2nWNzRxWrr61wANqm43NNYtbyEVzuuKR",
+ "2xrdbPJqR1vcag8Zm7YTlql/6AB9bB88XCj9rV5y/W3qspd8d5m1Amkohv8kIW8PYlQVtrC4VXivv1Cc",
+ "K3bQcXH7rePn+2299/frtSSx63+bXP+zZfxC0aZ+XUJps5fp/K14/1Len7zZ6uvp7n73twAAAP//",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -226,7 +230,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -244,12 +248,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -275,3 +279,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/examples/petstore-expanded/gin/api/petstore-types.gen.go b/examples/petstore-expanded/gin/api/petstore-types.gen.go
index 551af8d9d0..0e4954f349 100644
--- a/examples/petstore-expanded/gin/api/petstore-types.gen.go
+++ b/examples/petstore-expanded/gin/api/petstore-types.gen.go
@@ -1,6 +1,6 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
// Error defines model for Error.
diff --git a/examples/petstore-expanded/gin/api/petstore.go b/examples/petstore-expanded/gin/api/petstore.go
index c2c8ffa2a2..094b4ef9eb 100644
--- a/examples/petstore-expanded/gin/api/petstore.go
+++ b/examples/petstore-expanded/gin/api/petstore.go
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../../petstore-expanded.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../../petstore-expanded.yaml
package api
diff --git a/examples/petstore-expanded/gin/api/server.cfg.yaml b/examples/petstore-expanded/gin/api/server.cfg.yaml
index 61944bcef0..fe54882eb9 100644
--- a/examples/petstore-expanded/gin/api/server.cfg.yaml
+++ b/examples/petstore-expanded/gin/api/server.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
gin-server: true
diff --git a/examples/petstore-expanded/gin/api/types.cfg.yaml b/examples/petstore-expanded/gin/api/types.cfg.yaml
index 9ac30e11e9..cf5128b726 100644
--- a/examples/petstore-expanded/gin/api/types.cfg.yaml
+++ b/examples/petstore-expanded/gin/api/types.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
models: true
diff --git a/examples/petstore-expanded/gin/petstore.go b/examples/petstore-expanded/gin/petstore.go
index 70028ad5c4..0c0a7e1589 100644
--- a/examples/petstore-expanded/gin/petstore.go
+++ b/examples/petstore-expanded/gin/petstore.go
@@ -14,12 +14,12 @@ import (
"github.com/gin-gonic/gin"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/gin/api"
middleware "github.com/oapi-codegen/gin-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/gin/api"
)
func NewGinPetServer(petStore *api.PetStore, port string) *http.Server {
- swagger, err := api.GetSwagger()
+ swagger, err := api.GetSpec()
if err != nil {
fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
os.Exit(1)
diff --git a/examples/petstore-expanded/gin/petstore_test.go b/examples/petstore-expanded/gin/petstore_test.go
index d967486bb1..d7a557d1cb 100644
--- a/examples/petstore-expanded/gin/petstore_test.go
+++ b/examples/petstore-expanded/gin/petstore_test.go
@@ -7,8 +7,8 @@ import (
"net/http/httptest"
"testing"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/gin/api"
- "github.com/deepmap/oapi-codegen/pkg/testutil"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/gin/api"
+ "github.com/oapi-codegen/testutil"
"github.com/stretchr/testify/assert"
)
diff --git a/examples/petstore-expanded/gorilla/api/cfg.yaml b/examples/petstore-expanded/gorilla/api/cfg.yaml
index 8ead7a60de..0034869958 100644
--- a/examples/petstore-expanded/gorilla/api/cfg.yaml
+++ b/examples/petstore-expanded/gorilla/api/cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
gorilla-server: true
diff --git a/examples/petstore-expanded/gorilla/api/petstore.gen.go b/examples/petstore-expanded/gorilla/api/petstore.gen.go
index f5b07ba154..3ed8b4c27e 100644
--- a/examples/petstore-expanded/gorilla/api/petstore.gen.go
+++ b/examples/petstore-expanded/gorilla/api/petstore.gen.go
@@ -1,12 +1,13 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
+ "errors"
"fmt"
"net/http"
"net/url"
@@ -87,26 +88,36 @@ type MiddlewareFunc func(http.Handler) http.Handler
// FindPets operation middleware
func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// Parameter object where we will unmarshal all parameters from the context
var params FindPetsParams
// ------------- Optional query parameter "tags" -------------
- err = runtime.BindQueryParameter("form", true, false, "tags", r.URL.Query(), ¶ms.Tags)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "tags", r.URL.Query(), ¶ms.Tags, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
if err != nil {
- siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err})
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "tags"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err})
+ }
return
}
// ------------- Optional query parameter "limit" -------------
- err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), ¶ms.Limit)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
if err != nil {
- siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err})
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err})
+ }
return
}
@@ -118,12 +129,11 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque
handler = siw.HandlerMiddlewares[i](handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// AddPet operation middleware
func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.AddPet(w, r)
@@ -133,19 +143,19 @@ func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request
handler = siw.HandlerMiddlewares[i](handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// DeletePet operation middleware
func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// ------------- Path parameter "id" -------------
var id int64
- err = runtime.BindStyledParameter("simple", false, "id", mux.Vars(r)["id"], &id)
+ err = runtime.BindStyledParameterWithOptions("simple", "id", mux.Vars(r)["id"], &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
return
@@ -159,19 +169,19 @@ func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Requ
handler = siw.HandlerMiddlewares[i](handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// FindPetByID operation middleware
func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// ------------- Path parameter "id" -------------
var id int64
- err = runtime.BindStyledParameter("simple", false, "id", mux.Vars(r)["id"], &id)
+ err = runtime.BindStyledParameterWithOptions("simple", "id", mux.Vars(r)["id"], &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
return
@@ -185,7 +195,7 @@ func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Re
handler = siw.HandlerMiddlewares[i](handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
type UnescapedCookieParamError struct {
@@ -301,65 +311,66 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
- r.HandleFunc(options.BaseURL+"/pets", wrapper.FindPets).Methods("GET")
+ r.HandleFunc(options.BaseURL+"/pets", wrapper.FindPets).Methods(http.MethodGet)
- r.HandleFunc(options.BaseURL+"/pets", wrapper.AddPet).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/pets", wrapper.AddPet).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/pets/{id}", wrapper.DeletePet).Methods("DELETE")
+ r.HandleFunc(options.BaseURL+"/pets/{id}", wrapper.DeletePet).Methods(http.MethodDelete)
- r.HandleFunc(options.BaseURL+"/pets/{id}", wrapper.FindPetByID).Methods("GET")
+ r.HandleFunc(options.BaseURL+"/pets/{id}", wrapper.FindPetByID).Methods(http.MethodGet)
return r
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/+RXW48budH9KwV+32OnNbEXedBTvB4vICBrT+LdvKznoYZdkmrBSw9Z1FgY6L8HRbZu",
- "I3k2QYIgQV506WY1T51zqlj9bGz0YwwUJJv5s8l2TR7rzw8pxaQ/xhRHSsJUL9s4kH4PlG3iUTgGM2+L",
- "od7rzDImj2LmhoO8fWM6I9uR2l9aUTK7znjKGVfffND+9iE0S+KwMrtdZxI9Fk40mPkvZtpwv/x+15mP",
- "9HRHcok7oL+y3Uf0BHEJsiYYSS437Izg6jLup+34etwLoHV3hTdhQ+c+Lc38l2fz/4mWZm7+b3YUYjap",
- "MJty2XUvk+HhEtLPgR8LAQ/nuE7F+MN3V8R4gZQHc7+73+llDsvYJA+CtuImj+zM3ODIQuj/mJ9wtaLU",
- "czTdRLH53K7Bu7sF/EToTWdK0qC1yJjns9lJ0K57kcU7yOhHRzVa1ihQMmVAzSZLTASYAQPQ17ZMIgzk",
- "Y8iSUAiWhFISZeBQOfg0UtAnve1vII9keckW61adcWwpZDqaw7wb0a4J3vQ3F5ifnp56rLf7mFazKTbP",
- "/rR4/+Hj5w+/e9Pf9GvxrjqGks+flp8pbdjS1cRndc1M5WBxp6zdTXmazmwo5cbK7/ub/kYfHUcKOLKZ",
- "m7f1UmdGlHX1xEwZ0h+rZrFzXv9CUlLIgM5VKmGZoq8U5W0W8o1r/V8yJVgry9ZSziDxS/iIHjINYGMY",
- "2FOQ4oGy9PAjkqWAGYT8GBNkXLEIZ8g4MoUOAllI6xhsyZDJnyxgAfQkPbyjQBgABVYJNzwgYFkV6gAt",
- "MNriuIb28L4kfGApCeLAEVxM5DuIKWAioBUJkKMJXSDbgS0pl6wl4chKyT3cFs7gGaSkkXMHY3EbDph0",
- "L0pRk+5AOFgeShDYYOKS4deSJfawCLBGC2sFgTkTjA6FEAa2UrzSsWhFpbngwCNny2EFGESzOebueFUc",
- "HjIf15hIEu5J1PXgo6MsTMB+pDSwMvVX3qBvCaHjx4IeBkZlJmGGR81tQ44FQgwgMUlMSgkvKQyH3Xu4",
- "S0iZgihMCuyPAEoKCJvoiowosKFAARVwI1c/PJakz1iE45OXlCbWl2jZcT7bpO6gH91RXws5DuhIhR06",
- "5dFSQtHE9LuHzyWPFAZWlh2qeYboYurUgZmsqJtrltUqmnUHG1qzLQ5BW1saigfHD5RiDz/G9MBAhbOP",
- "w6kMersa26HlwNh/CV/CZxqqEiXDktR8Lj7EVAMoHh2TiqTie9Da8FgfOJHP2XVA5axamuTgivpQ3dnD",
- "3RozOdcKY6Q0hVeaq7wksMRi+aE0wnG/j647jd+Qm6TjDaWE3fnWWifAQ3coxMAP6x5+FhjJOQpCWU+O",
- "MeZCWkn7IupBqcB9FWjR7bncP2mfVmWyq0AOtgglWJDEWerBtGFB6uGHki0BSe0GQ+FDFWinyJYcJa5w",
- "mn/3AV7dUrCaxxafMYDHlaZMblKrhz+XFuqjU92aelSad45QukPzASxWi6StnOzZ0p7MMTWZQzWqWVRg",
- "4NAdoUyFGzjzHnBWDJalDKxQc0YosvfZJGTb6Yy0ul8Pd6fCVOYmjGMi4eJPOlczTelO/K2tt/+iZ5wO",
- "DfW8Wwxmbn7gMOj5Uo+NpARQynUKOT8sBFfa92HJTijBw9boMGDm5rFQ2h5Pel1numlorHOJkK9n0OUU",
- "1S5gSrjV/1m29djT8aQOOOcIPH5lr228+AdKOtEkysVJhZXqWfYNTI49yxmo3xxHd/c6AuVRW0tF/+bm",
- "Zj/3UGjz2ji6aXKY/ZoV4vO1tF8b5tok94KI3cUANJLAHkwbj5ZYnPxDeF6D0cb6KxuXQF9Hba3ag9ua",
- "zuTiPabtlQFCsY0xXxk13idCqTNboCddux/G6lyjZ3DDrkt0nnMuPtFwYdZ3g3rVtOmUsnwfh+2/jIX9",
- "ZH1Jwx2JegyHQb8OsM3plCyp0O6f9MxvWuW/xxoXgtf7dR6dPfOwaxZxJFdewNp1jc0cVq6+tcADapuN",
- "zTWLW8hFc7rikdsa3Wzyakdb3GoPGZu2E5apf+gAfWwfPFwo/a1ecv1t6rKXfHeZtQJpKIb/JCFvD2JU",
- "FbawuFV4r79QnCt20HFx+63j5/ttvff367Ukset/m1z/s2X8QtGmfl1CabOX6fyteP9S3p+82err6e5+",
- "97cAAAD//ykDnxlaEgAA",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "5Fdbjxu50f0rBX7fY6c1sRd50FO8Hi8gIGtP4t28rOehhl2SasFLD1nUWBjovwdFtm4jeTZBgiBBXnTp",
+ "ZjVPnXOqWP1sbPRjDBQkm/mzyXZNHuvPDynFpD/GFEdKwlQv2ziQfg+UbeJROAYzb4uh3uvMMiaPYuaG",
+ "g7x9Yzoj25HaX1pRMrvOeMoZV9980P72ITRL4rAyu11nEj0WTjSY+S9m2nC//H7XmY/0dEdyiTugv7Ld",
+ "R/QEcQmyJhhJLjfsjODqMu6n7fh63AugdXeFN2FD5z4tzfyXZ/P/iZZmbv5vdhRiNqkwm3LZdS+T4eES",
+ "0s+BHwsBD+e4TsX4w3dXxHiBlAdzv7vf6WUOy9gkD4K24iaP7Mzc4MhC6P+Yn3C1otRzNN1EsfncrsG7",
+ "uwX8ROhNZ0rSoLXImOez2UnQrnuRxTvI6EdHNVrWKFAyZUDNJktMBJgBA9DXtkwiDORjyJJQCJaEUhJl",
+ "4FA5+DRS0Ce97W8gj2R5yRbrVp1xbClkOprDvBvRrgne9DcXmJ+ennqst/uYVrMpNs/+tHj/4ePnD797",
+ "09/0a/GuOoaSz5+Wnylt2NLVxGd1zUzlYHGnrN1NeZrObCjlxsrv+5v+Rh8dRwo4spmbt/VSZ0aUdfXE",
+ "TBnSH6tmsXNe/0JSUsiAzlUqYZmirxTlbRbyjWv9XzIlWCvL1lLOIPFL+IgeMg1gYxjYU5DigbL08COS",
+ "pYAZhPwYE2RcsQhnyDgyhQ4CWUjrGGzJkMmfLGAB9CQ9vKNAGAAFVgk3PCBgWRXqAC0w2uK4hvbwviR8",
+ "YCkJ4sARXEzkO4gpYCKgFQmQowldINuBLSmXrCXhyErJPdwWzuAZpKSRcwdjcRsOmHQvSlGT7kA4WB5K",
+ "ENhg4pLh15Il9rAIsEYLawWBOROMDoUQBrZSvNKxaEWlueDAI2fLYQUYRLM55u54VRweMh/XmEgS7knU",
+ "9eCjoyxMwH6kNLAy9VfeoG8JoePHgh4GRmUmYYZHzW1DjgVCDCAxSUxKCS8pDIfde7hLSJmCKEwK7I8A",
+ "SgoIm+iKjCiwoUABFXAjVz88lqTPWITjk5eUJtaXaNlxPtuk7qAf3VFfCzkO6EiFHTrl0VJC0cT0u4fP",
+ "JY8UBlaWHap5huhi6tSBmayom2uW1SqadQcbWrMtDkFbWxqKB8cPlGIPP8b0wECFs4/DqQx6uxrboeXA",
+ "2H8JX8JnGqoSJcOS1HwuPsRUAygeHZOKpOJ70NrwWB84kc/ZdUDlrFqa5OCK+lDd2cPdGjM51wpjpDSF",
+ "V5qrvCSwxGL5oTTCcb+PrjuN35CbpOMNpYTd+dZaJ8BDdyjEwA/rHn4WGMk5CkJZT44x5kJaSfsi6kGp",
+ "wH0VaNHtudw/aZ9WZbKrQA62CCVYkMRZ6sG0YUHq4YeSLQFJ7QZD4UMVaKfIlhwlrnCaf/cBXt1SsJrH",
+ "Fp8xgMeVpkxuUquHP5cW6qNT3Zp6VJp3jlC6Q/MBLFaLpK2c7NnSnswxNZlDNapZVGDg0B2hTIUbOPMe",
+ "cFYMlqUMrFBzRiiy99kkZNvpjLS6Xw93p8JU5iaMYyLh4k86VzNN6U78ra23/6JnnA4N9bxbDGZufuAw",
+ "6PlSj42kBFDKdQo5PywEV9r3YclOKMHD1ugwYObmsVDaHk96XWe6aWisc4mQr2fQ5RTVLmBKuNX/Wbb1",
+ "2NPxpA445wg8fmWvbbz4B0o60STKxUmFlepZ9g1Mjj3LGajfHEd39zoC5VFbS0X/5uZmP/dQaPPaOLpp",
+ "cpj9mhXi87W0Xxvm2iT3gojdxQA0ksAeTBuPllic/EN4XoPRxvorG5dAX0dtrdqD25rO5OI9pu2VAUKx",
+ "jTFfGTXeJ0KpM1ugJ127H8bqXKNncMOuS3Secy4+0XBh1neDetW06ZSyfB+H7b+Mhf1kfUnDHYl6DIdB",
+ "vw6wzemULKnQ7p/0zG9a5b/HGheC1/t1Hp0987BrFnEkV17A2nWNzRxWrr61wANqm43NNYtbyEVzuuKR",
+ "2xrdbPJqR1vcag8Zm7YTlql/6AB9bB88XCj9rV5y/W3qspd8d5m1Amkohv8kIW8PYlQVtrC4VXivv1Cc",
+ "K3bQcXH7rePn+2299/frtSSx63+bXP+zZfxC0aZ+XUJps5fp/K14/1Len7zZ6uvp7n73twAAAP//",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -367,7 +378,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -385,12 +396,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -416,3 +427,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/examples/petstore-expanded/gorilla/api/petstore.go b/examples/petstore-expanded/gorilla/api/petstore.go
index cc5298cddc..6ede559ec5 100644
--- a/examples/petstore-expanded/gorilla/api/petstore.go
+++ b/examples/petstore-expanded/gorilla/api/petstore.go
@@ -1,4 +1,4 @@
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=cfg.yaml ../../petstore-expanded.yaml
package api
diff --git a/examples/petstore-expanded/gorilla/petstore.go b/examples/petstore-expanded/gorilla/petstore.go
index f413c85a0d..8a6eac558c 100644
--- a/examples/petstore-expanded/gorilla/petstore.go
+++ b/examples/petstore-expanded/gorilla/petstore.go
@@ -12,16 +12,16 @@ import (
"net/http"
"os"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/gorilla/api"
- middleware "github.com/oapi-codegen/nethttp-middleware"
"github.com/gorilla/mux"
+ middleware "github.com/oapi-codegen/nethttp-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/gorilla/api"
)
func main() {
port := flag.String("port", "8080", "Port for test HTTP server")
flag.Parse()
- swagger, err := api.GetSwagger()
+ swagger, err := api.GetSpec()
if err != nil {
fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
os.Exit(1)
diff --git a/examples/petstore-expanded/gorilla/petstore_test.go b/examples/petstore-expanded/gorilla/petstore_test.go
index d102c2691d..c3dc320f0b 100644
--- a/examples/petstore-expanded/gorilla/petstore_test.go
+++ b/examples/petstore-expanded/gorilla/petstore_test.go
@@ -7,10 +7,10 @@ import (
"net/http/httptest"
"testing"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/gorilla/api"
- middleware "github.com/oapi-codegen/nethttp-middleware"
- "github.com/deepmap/oapi-codegen/pkg/testutil"
"github.com/gorilla/mux"
+ middleware "github.com/oapi-codegen/nethttp-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/gorilla/api"
+ "github.com/oapi-codegen/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -24,7 +24,7 @@ func TestPetStore(t *testing.T) {
var err error
// Get the swagger description of our API
- swagger, err := api.GetSwagger()
+ swagger, err := api.GetSpec()
require.NoError(t, err)
// Clear out the servers array in the swagger spec, that skips validating
diff --git a/examples/petstore-expanded/internal/config.yaml b/examples/petstore-expanded/internal/config.yaml
index 0678280542..33b649fd81 100644
--- a/examples/petstore-expanded/internal/config.yaml
+++ b/examples/petstore-expanded/internal/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
package: petstore
generate:
client: true
diff --git a/examples/petstore-expanded/internal/doc.go b/examples/petstore-expanded/internal/doc.go
index b255193076..b04cac3f8d 100644
--- a/examples/petstore-expanded/internal/doc.go
+++ b/examples/petstore-expanded/internal/doc.go
@@ -17,4 +17,4 @@ package internal
// server. The file petstore.gen.go is automatically generated from the schema
// Run oapi-codegen to regenerate the petstore boilerplate
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml ../petstore-expanded.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../petstore-expanded.yaml
diff --git a/examples/petstore-expanded/iris/api/petstore-server.gen.go b/examples/petstore-expanded/iris/api/petstore-server.gen.go
index d9394a65f6..f5bcd2cb29 100644
--- a/examples/petstore-expanded/iris/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/iris/api/petstore-server.gen.go
@@ -1,11 +1,11 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/http"
@@ -45,12 +45,13 @@ type MiddlewareFunc iris.Handler
func (w *ServerInterfaceWrapper) FindPets(ctx iris.Context) {
var err error
+ _ = err
// Parameter object where we will unmarshal all parameters from the context
var params FindPetsParams
// ------------- Optional query parameter "tags" -------------
- err = runtime.BindQueryParameter("form", true, false, "tags", ctx.Request().URL.Query(), ¶ms.Tags)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "tags", ctx.Request().URL.Query(), ¶ms.Tags, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
if err != nil {
ctx.StatusCode(http.StatusBadRequest)
ctx.Writef("Invalid format for parameter tags: %s", err)
@@ -59,7 +60,7 @@ func (w *ServerInterfaceWrapper) FindPets(ctx iris.Context) {
// ------------- Optional query parameter "limit" -------------
- err = runtime.BindQueryParameter("form", true, false, "limit", ctx.Request().URL.Query(), ¶ms.Limit)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", ctx.Request().URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
if err != nil {
ctx.StatusCode(http.StatusBadRequest)
ctx.Writef("Invalid format for parameter limit: %s", err)
@@ -81,11 +82,12 @@ func (w *ServerInterfaceWrapper) AddPet(ctx iris.Context) {
func (w *ServerInterfaceWrapper) DeletePet(ctx iris.Context) {
var err error
+ _ = err
// ------------- Path parameter "id" -------------
var id int64
- err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, ctx.Params().Get("id"), &id)
+ err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Params().Get("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
ctx.StatusCode(http.StatusBadRequest)
ctx.Writef("Invalid format for parameter id: %s", err)
@@ -100,11 +102,12 @@ func (w *ServerInterfaceWrapper) DeletePet(ctx iris.Context) {
func (w *ServerInterfaceWrapper) FindPetByID(ctx iris.Context) {
var err error
+ _ = err
// ------------- Path parameter "id" -------------
var id int64
- err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, ctx.Params().Get("id"), &id)
+ err = runtime.BindStyledParameterWithOptions("simple", "id", ctx.Params().Get("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
ctx.StatusCode(http.StatusBadRequest)
ctx.Writef("Invalid format for parameter id: %s", err)
@@ -141,54 +144,55 @@ func RegisterHandlersWithOptions(router *iris.Application, si ServerInterface, o
router.Build()
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
+ "5Fdbjxu50f0rBX7fY6c1sRd50FO8Hi8gIGtP4t28rOehhl2SasFLD1nUWBjovwdFtm4jeTZBgiBBXnTp",
+ "ZjVPnXOqWP1sbPRjDBQkm/mzyXZNHuvPDynFpD/GFEdKwlQv2ziQfg+UbeJROAYzb4uh3uvMMiaPYuaG",
+ "g7x9Yzoj25HaX1pRMrvOeMoZV9980P72ITRL4rAyu11nEj0WTjSY+S9m2nC//H7XmY/0dEdyiTugv7Ld",
+ "R/QEcQmyJhhJLjfsjODqMu6n7fh63AugdXeFN2FD5z4tzfyXZ/P/iZZmbv5vdhRiNqkwm3LZdS+T4eES",
+ "0s+BHwsBD+e4TsX4w3dXxHiBlAdzv7vf6WUOy9gkD4K24iaP7Mzc4MhC6P+Yn3C1otRzNN1EsfncrsG7",
+ "uwX8ROhNZ0rSoLXImOez2UnQrnuRxTvI6EdHNVrWKFAyZUDNJktMBJgBA9DXtkwiDORjyJJQCJaEUhJl",
+ "4FA5+DRS0Ce97W8gj2R5yRbrVp1xbClkOprDvBvRrgne9DcXmJ+ennqst/uYVrMpNs/+tHj/4ePnD797",
+ "09/0a/GuOoaSz5+Wnylt2NLVxGd1zUzlYHGnrN1NeZrObCjlxsrv+5v+Rh8dRwo4spmbt/VSZ0aUdfXE",
+ "TBnSH6tmsXNe/0JSUsiAzlUqYZmirxTlbRbyjWv9XzIlWCvL1lLOIPFL+IgeMg1gYxjYU5DigbL08COS",
+ "pYAZhPwYE2RcsQhnyDgyhQ4CWUjrGGzJkMmfLGAB9CQ9vKNAGAAFVgk3PCBgWRXqAC0w2uK4hvbwviR8",
+ "YCkJ4sARXEzkO4gpYCKgFQmQowldINuBLSmXrCXhyErJPdwWzuAZpKSRcwdjcRsOmHQvSlGT7kA4WB5K",
+ "ENhg4pLh15Il9rAIsEYLawWBOROMDoUQBrZSvNKxaEWlueDAI2fLYQUYRLM55u54VRweMh/XmEgS7knU",
+ "9eCjoyxMwH6kNLAy9VfeoG8JoePHgh4GRmUmYYZHzW1DjgVCDCAxSUxKCS8pDIfde7hLSJmCKEwK7I8A",
+ "SgoIm+iKjCiwoUABFXAjVz88lqTPWITjk5eUJtaXaNlxPtuk7qAf3VFfCzkO6EiFHTrl0VJC0cT0u4fP",
+ "JY8UBlaWHap5huhi6tSBmayom2uW1SqadQcbWrMtDkFbWxqKB8cPlGIPP8b0wECFs4/DqQx6uxrboeXA",
+ "2H8JX8JnGqoSJcOS1HwuPsRUAygeHZOKpOJ70NrwWB84kc/ZdUDlrFqa5OCK+lDd2cPdGjM51wpjpDSF",
+ "V5qrvCSwxGL5oTTCcb+PrjuN35CbpOMNpYTd+dZaJ8BDdyjEwA/rHn4WGMk5CkJZT44x5kJaSfsi6kGp",
+ "wH0VaNHtudw/aZ9WZbKrQA62CCVYkMRZ6sG0YUHq4YeSLQFJ7QZD4UMVaKfIlhwlrnCaf/cBXt1SsJrH",
+ "Fp8xgMeVpkxuUquHP5cW6qNT3Zp6VJp3jlC6Q/MBLFaLpK2c7NnSnswxNZlDNapZVGDg0B2hTIUbOPMe",
+ "cFYMlqUMrFBzRiiy99kkZNvpjLS6Xw93p8JU5iaMYyLh4k86VzNN6U78ra23/6JnnA4N9bxbDGZufuAw",
+ "6PlSj42kBFDKdQo5PywEV9r3YclOKMHD1ugwYObmsVDaHk96XWe6aWisc4mQr2fQ5RTVLmBKuNX/Wbb1",
+ "2NPxpA445wg8fmWvbbz4B0o60STKxUmFlepZ9g1Mjj3LGajfHEd39zoC5VFbS0X/5uZmP/dQaPPaOLpp",
+ "cpj9mhXi87W0Xxvm2iT3gojdxQA0ksAeTBuPllic/EN4XoPRxvorG5dAX0dtrdqD25rO5OI9pu2VAUKx",
+ "jTFfGTXeJ0KpM1ugJ127H8bqXKNncMOuS3Secy4+0XBh1neDetW06ZSyfB+H7b+Mhf1kfUnDHYl6DIdB",
+ "vw6wzemULKnQ7p/0zG9a5b/HGheC1/t1Hp0987BrFnEkV17A2nWNzRxWrr61wANqm43NNYtbyEVzuuKR",
+ "2xrdbPJqR1vcag8Zm7YTlql/6AB9bB88XCj9rV5y/W3qspd8d5m1Amkohv8kIW8PYlQVtrC4VXivv1Cc",
+ "K3bQcXH7rePn+2299/frtSSx63+bXP+zZfxC0aZ+XUJps5fp/K14/1Len7zZ6uvp7n73twAAAP//",
+}
- "H4sIAAAAAAAC/+RXW48budH9KwV+32OnNbEXedBTvB4vICBrT+LdvKznoYZdkmrBSw9Z1FgY6L8HRbZu",
- "I3k2QYIgQV506WY1T51zqlj9bGz0YwwUJJv5s8l2TR7rzw8pxaQ/xhRHSsJUL9s4kH4PlG3iUTgGM2+L",
- "od7rzDImj2LmhoO8fWM6I9uR2l9aUTK7znjKGVfffND+9iE0S+KwMrtdZxI9Fk40mPkvZtpwv/x+15mP",
- "9HRHcok7oL+y3Uf0BHEJsiYYSS437Izg6jLup+34etwLoHV3hTdhQ+c+Lc38l2fz/4mWZm7+b3YUYjap",
- "MJty2XUvk+HhEtLPgR8LAQ/nuE7F+MN3V8R4gZQHc7+73+llDsvYJA+CtuImj+zM3ODIQuj/mJ9wtaLU",
- "czTdRLH53K7Bu7sF/EToTWdK0qC1yJjns9lJ0K57kcU7yOhHRzVa1ihQMmVAzSZLTASYAQPQ17ZMIgzk",
- "Y8iSUAiWhFISZeBQOfg0UtAnve1vII9keckW61adcWwpZDqaw7wb0a4J3vQ3F5ifnp56rLf7mFazKTbP",
- "/rR4/+Hj5w+/e9Pf9GvxrjqGks+flp8pbdjS1cRndc1M5WBxp6zdTXmazmwo5cbK7/ub/kYfHUcKOLKZ",
- "m7f1UmdGlHX1xEwZ0h+rZrFzXv9CUlLIgM5VKmGZoq8U5W0W8o1r/V8yJVgry9ZSziDxS/iIHjINYGMY",
- "2FOQ4oGy9PAjkqWAGYT8GBNkXLEIZ8g4MoUOAllI6xhsyZDJnyxgAfQkPbyjQBgABVYJNzwgYFkV6gAt",
- "MNriuIb28L4kfGApCeLAEVxM5DuIKWAioBUJkKMJXSDbgS0pl6wl4chKyT3cFs7gGaSkkXMHY3EbDph0",
- "L0pRk+5AOFgeShDYYOKS4deSJfawCLBGC2sFgTkTjA6FEAa2UrzSsWhFpbngwCNny2EFGESzOebueFUc",
- "HjIf15hIEu5J1PXgo6MsTMB+pDSwMvVX3qBvCaHjx4IeBkZlJmGGR81tQ44FQgwgMUlMSgkvKQyH3Xu4",
- "S0iZgihMCuyPAEoKCJvoiowosKFAARVwI1c/PJakz1iE45OXlCbWl2jZcT7bpO6gH91RXws5DuhIhR06",
- "5dFSQtHE9LuHzyWPFAZWlh2qeYboYurUgZmsqJtrltUqmnUHG1qzLQ5BW1saigfHD5RiDz/G9MBAhbOP",
- "w6kMersa26HlwNh/CV/CZxqqEiXDktR8Lj7EVAMoHh2TiqTie9Da8FgfOJHP2XVA5axamuTgivpQ3dnD",
- "3RozOdcKY6Q0hVeaq7wksMRi+aE0wnG/j647jd+Qm6TjDaWE3fnWWifAQ3coxMAP6x5+FhjJOQpCWU+O",
- "MeZCWkn7IupBqcB9FWjR7bncP2mfVmWyq0AOtgglWJDEWerBtGFB6uGHki0BSe0GQ+FDFWinyJYcJa5w",
- "mn/3AV7dUrCaxxafMYDHlaZMblKrhz+XFuqjU92aelSad45QukPzASxWi6StnOzZ0p7MMTWZQzWqWVRg",
- "4NAdoUyFGzjzHnBWDJalDKxQc0YosvfZJGTb6Yy0ul8Pd6fCVOYmjGMi4eJPOlczTelO/K2tt/+iZ5wO",
- "DfW8Wwxmbn7gMOj5Uo+NpARQynUKOT8sBFfa92HJTijBw9boMGDm5rFQ2h5Pel1numlorHOJkK9n0OUU",
- "1S5gSrjV/1m29djT8aQOOOcIPH5lr228+AdKOtEkysVJhZXqWfYNTI49yxmo3xxHd/c6AuVRW0tF/+bm",
- "Zj/3UGjz2ji6aXKY/ZoV4vO1tF8b5tok94KI3cUANJLAHkwbj5ZYnPxDeF6D0cb6KxuXQF9Hba3ag9ua",
- "zuTiPabtlQFCsY0xXxk13idCqTNboCddux/G6lyjZ3DDrkt0nnMuPtFwYdZ3g3rVtOmUsnwfh+2/jIX9",
- "ZH1Jwx2JegyHQb8OsM3plCyp0O6f9MxvWuW/xxoXgtf7dR6dPfOwaxZxJFdewNp1jc0cVq6+tcADapuN",
- "zTWLW8hFc7rikdsa3Wzyakdb3GoPGZu2E5apf+gAfWwfPFwo/a1ecv1t6rKXfHeZtQJpKIb/JCFvD2JU",
- "FbawuFV4r79QnCt20HFx+63j5/ttvff367Ukset/m1z/s2X8QtGmfl1CabOX6fyteP9S3p+82err6e5+",
- "97cAAAD//ykDnxlaEgAA",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -196,7 +200,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -214,12 +218,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -245,3 +249,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/examples/petstore-expanded/iris/api/petstore-types.gen.go b/examples/petstore-expanded/iris/api/petstore-types.gen.go
index 551af8d9d0..0e4954f349 100644
--- a/examples/petstore-expanded/iris/api/petstore-types.gen.go
+++ b/examples/petstore-expanded/iris/api/petstore-types.gen.go
@@ -1,6 +1,6 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
// Error defines model for Error.
diff --git a/examples/petstore-expanded/iris/api/petstore.go b/examples/petstore-expanded/iris/api/petstore.go
index 29d44ad60d..d1e8018012 100644
--- a/examples/petstore-expanded/iris/api/petstore.go
+++ b/examples/petstore-expanded/iris/api/petstore.go
@@ -12,8 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../../petstore-expanded.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../../petstore-expanded.yaml
package api
diff --git a/examples/petstore-expanded/iris/api/server.cfg.yaml b/examples/petstore-expanded/iris/api/server.cfg.yaml
index cb44eb33f8..f8bb40c5bd 100644
--- a/examples/petstore-expanded/iris/api/server.cfg.yaml
+++ b/examples/petstore-expanded/iris/api/server.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
iris-server: true
diff --git a/examples/petstore-expanded/iris/api/types.cfg.yaml b/examples/petstore-expanded/iris/api/types.cfg.yaml
index 9ac30e11e9..cf5128b726 100644
--- a/examples/petstore-expanded/iris/api/types.cfg.yaml
+++ b/examples/petstore-expanded/iris/api/types.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
models: true
diff --git a/examples/petstore-expanded/iris/petstore.go b/examples/petstore-expanded/iris/petstore.go
index 9d3829a6c5..b97b95c5c6 100644
--- a/examples/petstore-expanded/iris/petstore.go
+++ b/examples/petstore-expanded/iris/petstore.go
@@ -11,13 +11,13 @@ import (
"log"
"os"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/iris/api"
- middleware "github.com/oapi-codegen/iris-middleware"
"github.com/kataras/iris/v12"
+ middleware "github.com/oapi-codegen/iris-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/iris/api"
)
func NewIrisPetServer(petStore *api.PetStore, port int) *iris.Application {
- swagger, err := api.GetSwagger()
+ swagger, err := api.GetSpec()
if err != nil {
fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
os.Exit(1)
diff --git a/examples/petstore-expanded/iris/petstore_test.go b/examples/petstore-expanded/iris/petstore_test.go
index f59d2bcb6d..837a53369c 100644
--- a/examples/petstore-expanded/iris/petstore_test.go
+++ b/examples/petstore-expanded/iris/petstore_test.go
@@ -21,8 +21,8 @@ import (
"net/http/httptest"
"testing"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/iris/api"
- "github.com/deepmap/oapi-codegen/pkg/testutil"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/iris/api"
+ "github.com/oapi-codegen/testutil"
"github.com/stretchr/testify/assert"
)
diff --git a/examples/petstore-expanded/petstore-client.gen.go b/examples/petstore-expanded/petstore-client.gen.go
index 3a168372fe..0b77852791 100644
--- a/examples/petstore-expanded/petstore-client.gen.go
+++ b/examples/petstore-expanded/petstore-client.gen.go
@@ -1,6 +1,6 @@
// Package petstore provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package petstore
import (
@@ -226,19 +226,21 @@ func NewFindPetsRequest(server string, params *FindPetsParams) (*http.Request, e
}
if params != nil {
+ // queryValues collects non-styled parameters (passthrough, JSON)
+ // that are safe to round-trip through url.Values.Encode().
queryValues := queryURL.Query()
+ // rawQueryFragments collects pre-encoded query fragments from
+ // styled parameters, preserving literal commas as delimiters
+ // per the OpenAPI spec (e.g. "color=blue,black,brown").
+ var rawQueryFragments []string
if params.Tags != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "tags", runtime.ParamLocationQuery, *params.Tags); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "tags", *params.Tags, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "array", Format: ""}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
@@ -246,24 +248,23 @@ func NewFindPetsRequest(server string, params *FindPetsParams) (*http.Request, e
if params.Limit != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "limit", runtime.ParamLocationQuery, *params.Limit); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "limit", *params.Limit, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "integer", Format: "int32"}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
}
- queryURL.RawQuery = queryValues.Encode()
+ if encoded := queryValues.Encode(); encoded != "" {
+ rawQueryFragments = append(rawQueryFragments, encoded)
+ }
+ queryURL.RawQuery = strings.Join(rawQueryFragments, "&")
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -301,7 +302,7 @@ func NewAddPetRequestWithBody(server string, contentType string, body io.Reader)
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -317,7 +318,7 @@ func NewDeletePetRequest(server string, id int64) (*http.Request, error) {
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id)
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "id", id, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "integer", Format: "int64"})
if err != nil {
return nil, err
}
@@ -337,7 +338,7 @@ func NewDeletePetRequest(server string, id int64) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("DELETE", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodDelete, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -351,7 +352,7 @@ func NewFindPetByIDRequest(server string, id int64) (*http.Request, error) {
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("simple", false, "id", runtime.ParamLocationPath, id)
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "id", id, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "integer", Format: "int64"})
if err != nil {
return nil, err
}
@@ -371,7 +372,7 @@ func NewFindPetByIDRequest(server string, id int64) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -444,6 +445,21 @@ type FindPetsResponse struct {
JSONDefault *Error
}
+// GetJSON200 returns JSON200
+func (r FindPetsResponse) GetJSON200() *[]Pet {
+ return r.JSON200
+}
+
+// GetJSONDefault returns JSONDefault
+func (r FindPetsResponse) GetJSONDefault() *Error {
+ return r.JSONDefault
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r FindPetsResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r FindPetsResponse) Status() string {
if r.HTTPResponse != nil {
@@ -460,6 +476,14 @@ func (r FindPetsResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r FindPetsResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type AddPetResponse struct {
Body []byte
HTTPResponse *http.Response
@@ -467,6 +491,21 @@ type AddPetResponse struct {
JSONDefault *Error
}
+// GetJSON200 returns JSON200
+func (r AddPetResponse) GetJSON200() *Pet {
+ return r.JSON200
+}
+
+// GetJSONDefault returns JSONDefault
+func (r AddPetResponse) GetJSONDefault() *Error {
+ return r.JSONDefault
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r AddPetResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r AddPetResponse) Status() string {
if r.HTTPResponse != nil {
@@ -483,12 +522,30 @@ func (r AddPetResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r AddPetResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type DeletePetResponse struct {
Body []byte
HTTPResponse *http.Response
JSONDefault *Error
}
+// GetJSONDefault returns JSONDefault
+func (r DeletePetResponse) GetJSONDefault() *Error {
+ return r.JSONDefault
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r DeletePetResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r DeletePetResponse) Status() string {
if r.HTTPResponse != nil {
@@ -505,6 +562,14 @@ func (r DeletePetResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r DeletePetResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type FindPetByIDResponse struct {
Body []byte
HTTPResponse *http.Response
@@ -512,6 +577,21 @@ type FindPetByIDResponse struct {
JSONDefault *Error
}
+// GetJSON200 returns JSON200
+func (r FindPetByIDResponse) GetJSON200() *Pet {
+ return r.JSON200
+}
+
+// GetJSONDefault returns JSONDefault
+func (r FindPetByIDResponse) GetJSONDefault() *Error {
+ return r.JSONDefault
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r FindPetByIDResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r FindPetByIDResponse) Status() string {
if r.HTTPResponse != nil {
@@ -528,6 +608,14 @@ func (r FindPetByIDResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r FindPetByIDResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// FindPetsWithResponse request returning *FindPetsResponse
func (c *ClientWithResponses) FindPetsWithResponse(ctx context.Context, params *FindPetsParams, reqEditors ...RequestEditorFn) (*FindPetsResponse, error) {
rsp, err := c.FindPets(ctx, params, reqEditors...)
diff --git a/examples/petstore-expanded/stdhttp/api/cfg.yaml b/examples/petstore-expanded/stdhttp/api/cfg.yaml
new file mode 100644
index 0000000000..12339c51fa
--- /dev/null
+++ b/examples/petstore-expanded/stdhttp/api/cfg.yaml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: api
+generate:
+ std-http-server: true
+ embedded-spec: true
+ models: true
+output: petstore.gen.go
diff --git a/examples/petstore-expanded/stdhttp/api/petstore.gen.go b/examples/petstore-expanded/stdhttp/api/petstore.gen.go
new file mode 100644
index 0000000000..9ae158e3fd
--- /dev/null
+++ b/examples/petstore-expanded/stdhttp/api/petstore.gen.go
@@ -0,0 +1,453 @@
+//go:build go1.22
+
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/oapi-codegen/runtime"
+)
+
+// Error defines model for Error.
+type Error struct {
+ // Code Error code
+ Code int32 `json:"code"`
+
+ // Message Error message
+ Message string `json:"message"`
+}
+
+// NewPet defines model for NewPet.
+type NewPet struct {
+ // Name Name of the pet
+ Name string `json:"name"`
+
+ // Tag Type of the pet
+ Tag *string `json:"tag,omitempty"`
+}
+
+// Pet defines model for Pet.
+type Pet struct {
+ // Id Unique id of the pet
+ Id int64 `json:"id"`
+
+ // Name Name of the pet
+ Name string `json:"name"`
+
+ // Tag Type of the pet
+ Tag *string `json:"tag,omitempty"`
+}
+
+// FindPetsParams defines parameters for FindPets.
+type FindPetsParams struct {
+ // Tags tags to filter by
+ Tags *[]string `form:"tags,omitempty" json:"tags,omitempty"`
+
+ // Limit maximum number of results to return
+ Limit *int32 `form:"limit,omitempty" json:"limit,omitempty"`
+}
+
+// AddPetJSONRequestBody defines body for AddPet for application/json ContentType.
+type AddPetJSONRequestBody = NewPet
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // Returns all pets
+ // (GET /pets)
+ FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams)
+ // Creates a new pet
+ // (POST /pets)
+ AddPet(w http.ResponseWriter, r *http.Request)
+ // Deletes a pet by ID
+ // (DELETE /pets/{id})
+ DeletePet(w http.ResponseWriter, r *http.Request, id int64)
+ // Returns a pet by ID
+ // (GET /pets/{id})
+ FindPetByID(w http.ResponseWriter, r *http.Request, id int64)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// FindPets operation middleware
+func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params FindPetsParams
+
+ // ------------- Optional query parameter "tags" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "tags", r.URL.Query(), ¶ms.Tags, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "tags"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "limit" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err})
+ }
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.FindPets(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// AddPet operation middleware
+func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.AddPet(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// DeletePet operation middleware
+func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id int64
+
+ err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.DeletePet(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// FindPetByID operation middleware
+func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id int64
+
+ err = runtime.BindStyledParameterWithOptions("simple", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.FindPetByID(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{})
+}
+
+// ServeMux is an abstraction of [http.ServeMux].
+type ServeMux interface {
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+ http.Handler
+}
+
+type StdHTTPServerOptions struct {
+ BaseURL string
+ BaseRouter ServeMux
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/pets", wrapper.FindPets)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/pets", wrapper.AddPet)
+ m.HandleFunc(http.MethodDelete+" "+options.BaseURL+"/pets/{id}", wrapper.DeletePet)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/pets/{id}", wrapper.FindPetByID)
+
+ return m
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "5Fdbjxu50f0rBX7fY6c1sRd50FO8Hi8gIGtP4t28rOehhl2SasFLD1nUWBjovwdFtm4jeTZBgiBBXnTp",
+ "ZjVPnXOqWP1sbPRjDBQkm/mzyXZNHuvPDynFpD/GFEdKwlQv2ziQfg+UbeJROAYzb4uh3uvMMiaPYuaG",
+ "g7x9Yzoj25HaX1pRMrvOeMoZV9980P72ITRL4rAyu11nEj0WTjSY+S9m2nC//H7XmY/0dEdyiTugv7Ld",
+ "R/QEcQmyJhhJLjfsjODqMu6n7fh63AugdXeFN2FD5z4tzfyXZ/P/iZZmbv5vdhRiNqkwm3LZdS+T4eES",
+ "0s+BHwsBD+e4TsX4w3dXxHiBlAdzv7vf6WUOy9gkD4K24iaP7Mzc4MhC6P+Yn3C1otRzNN1EsfncrsG7",
+ "uwX8ROhNZ0rSoLXImOez2UnQrnuRxTvI6EdHNVrWKFAyZUDNJktMBJgBA9DXtkwiDORjyJJQCJaEUhJl",
+ "4FA5+DRS0Ce97W8gj2R5yRbrVp1xbClkOprDvBvRrgne9DcXmJ+ennqst/uYVrMpNs/+tHj/4ePnD797",
+ "09/0a/GuOoaSz5+Wnylt2NLVxGd1zUzlYHGnrN1NeZrObCjlxsrv+5v+Rh8dRwo4spmbt/VSZ0aUdfXE",
+ "TBnSH6tmsXNe/0JSUsiAzlUqYZmirxTlbRbyjWv9XzIlWCvL1lLOIPFL+IgeMg1gYxjYU5DigbL08COS",
+ "pYAZhPwYE2RcsQhnyDgyhQ4CWUjrGGzJkMmfLGAB9CQ9vKNAGAAFVgk3PCBgWRXqAC0w2uK4hvbwviR8",
+ "YCkJ4sARXEzkO4gpYCKgFQmQowldINuBLSmXrCXhyErJPdwWzuAZpKSRcwdjcRsOmHQvSlGT7kA4WB5K",
+ "ENhg4pLh15Il9rAIsEYLawWBOROMDoUQBrZSvNKxaEWlueDAI2fLYQUYRLM55u54VRweMh/XmEgS7knU",
+ "9eCjoyxMwH6kNLAy9VfeoG8JoePHgh4GRmUmYYZHzW1DjgVCDCAxSUxKCS8pDIfde7hLSJmCKEwK7I8A",
+ "SgoIm+iKjCiwoUABFXAjVz88lqTPWITjk5eUJtaXaNlxPtuk7qAf3VFfCzkO6EiFHTrl0VJC0cT0u4fP",
+ "JY8UBlaWHap5huhi6tSBmayom2uW1SqadQcbWrMtDkFbWxqKB8cPlGIPP8b0wECFs4/DqQx6uxrboeXA",
+ "2H8JX8JnGqoSJcOS1HwuPsRUAygeHZOKpOJ70NrwWB84kc/ZdUDlrFqa5OCK+lDd2cPdGjM51wpjpDSF",
+ "V5qrvCSwxGL5oTTCcb+PrjuN35CbpOMNpYTd+dZaJ8BDdyjEwA/rHn4WGMk5CkJZT44x5kJaSfsi6kGp",
+ "wH0VaNHtudw/aZ9WZbKrQA62CCVYkMRZ6sG0YUHq4YeSLQFJ7QZD4UMVaKfIlhwlrnCaf/cBXt1SsJrH",
+ "Fp8xgMeVpkxuUquHP5cW6qNT3Zp6VJp3jlC6Q/MBLFaLpK2c7NnSnswxNZlDNapZVGDg0B2hTIUbOPMe",
+ "cFYMlqUMrFBzRiiy99kkZNvpjLS6Xw93p8JU5iaMYyLh4k86VzNN6U78ra23/6JnnA4N9bxbDGZufuAw",
+ "6PlSj42kBFDKdQo5PywEV9r3YclOKMHD1ugwYObmsVDaHk96XWe6aWisc4mQr2fQ5RTVLmBKuNX/Wbb1",
+ "2NPxpA445wg8fmWvbbz4B0o60STKxUmFlepZ9g1Mjj3LGajfHEd39zoC5VFbS0X/5uZmP/dQaPPaOLpp",
+ "cpj9mhXi87W0Xxvm2iT3gojdxQA0ksAeTBuPllic/EN4XoPRxvorG5dAX0dtrdqD25rO5OI9pu2VAUKx",
+ "jTFfGTXeJ0KpM1ugJ127H8bqXKNncMOuS3Secy4+0XBh1neDetW06ZSyfB+H7b+Mhf1kfUnDHYl6DIdB",
+ "vw6wzemULKnQ7p/0zG9a5b/HGheC1/t1Hp0987BrFnEkV17A2nWNzRxWrr61wANqm43NNYtbyEVzuuKR",
+ "2xrdbPJqR1vcag8Zm7YTlql/6AB9bB88XCj9rV5y/W3qspd8d5m1Amkohv8kIW8PYlQVtrC4VXivv1Cc",
+ "K3bQcXH7rePn+2299/frtSSx63+bXP+zZfxC0aZ+XUJps5fp/K14/1Len7zZ6uvp7n73twAAAP//",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/examples/petstore-expanded/stdhttp/api/petstore.go b/examples/petstore-expanded/stdhttp/api/petstore.go
new file mode 100644
index 0000000000..5b9d8606f1
--- /dev/null
+++ b/examples/petstore-expanded/stdhttp/api/petstore.go
@@ -0,0 +1,130 @@
+//go:build go1.22
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=cfg.yaml ../../petstore-expanded.yaml
+
+package api
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "sync"
+)
+
+type PetStore struct {
+ Pets map[int64]Pet
+ NextId int64
+ Lock sync.Mutex
+}
+
+// Make sure we conform to ServerInterface
+
+var _ ServerInterface = (*PetStore)(nil)
+
+func NewPetStore() *PetStore {
+ return &PetStore{
+ Pets: make(map[int64]Pet),
+ NextId: 1000,
+ }
+}
+
+// sendPetStoreError wraps sending of an error in the Error format, and
+// handling the failure to marshal that.
+func sendPetStoreError(w http.ResponseWriter, code int, message string) {
+ petErr := Error{
+ Code: int32(code),
+ Message: message,
+ }
+ w.WriteHeader(code)
+ _ = json.NewEncoder(w).Encode(petErr)
+}
+
+// FindPets implements all the handlers in the ServerInterface
+func (p *PetStore) FindPets(w http.ResponseWriter, r *http.Request, params FindPetsParams) {
+ p.Lock.Lock()
+ defer p.Lock.Unlock()
+
+ var result []Pet
+
+ for _, pet := range p.Pets {
+ if params.Tags != nil {
+ // If we have tags, filter pets by tag
+ for _, t := range *params.Tags {
+ if pet.Tag != nil && (*pet.Tag == t) {
+ result = append(result, pet)
+ }
+ }
+ } else {
+ // Add all pets if we're not filtering
+ result = append(result, pet)
+ }
+
+ if params.Limit != nil {
+ l := int(*params.Limit)
+ if len(result) >= l {
+ // We're at the limit
+ break
+ }
+ }
+ }
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(result)
+}
+
+func (p *PetStore) AddPet(w http.ResponseWriter, r *http.Request) {
+ // We expect a NewPet object in the request body.
+ var newPet NewPet
+ if err := json.NewDecoder(r.Body).Decode(&newPet); err != nil {
+ sendPetStoreError(w, http.StatusBadRequest, "Invalid format for NewPet")
+ return
+ }
+
+ // We now have a pet, let's add it to our "database".
+
+ // We're always asynchronous, so lock unsafe operations below
+ p.Lock.Lock()
+ defer p.Lock.Unlock()
+
+ // We handle pets, not NewPets, which have an additional ID field
+ var pet Pet
+ pet.Name = newPet.Name
+ pet.Tag = newPet.Tag
+ pet.Id = p.NextId
+ p.NextId++
+
+ // Insert into map
+ p.Pets[pet.Id] = pet
+
+ // Now, we have to return the NewPet
+ w.WriteHeader(http.StatusCreated)
+ _ = json.NewEncoder(w).Encode(pet)
+}
+
+func (p *PetStore) FindPetByID(w http.ResponseWriter, r *http.Request, id int64) {
+ p.Lock.Lock()
+ defer p.Lock.Unlock()
+
+ pet, found := p.Pets[id]
+ if !found {
+ sendPetStoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id))
+ return
+ }
+
+ w.WriteHeader(http.StatusOK)
+ _ = json.NewEncoder(w).Encode(pet)
+}
+
+func (p *PetStore) DeletePet(w http.ResponseWriter, r *http.Request, id int64) {
+ p.Lock.Lock()
+ defer p.Lock.Unlock()
+
+ _, found := p.Pets[id]
+ if !found {
+ sendPetStoreError(w, http.StatusNotFound, fmt.Sprintf("Could not find pet with ID %d", id))
+ return
+ }
+ delete(p.Pets, id)
+
+ w.WriteHeader(http.StatusNoContent)
+}
diff --git a/examples/petstore-expanded/stdhttp/petstore.go b/examples/petstore-expanded/stdhttp/petstore.go
new file mode 100644
index 0000000000..043e60b841
--- /dev/null
+++ b/examples/petstore-expanded/stdhttp/petstore.go
@@ -0,0 +1,54 @@
+//go:build go1.22
+
+// This is an example of implementing the Pet Store from the OpenAPI documentation
+// found at:
+// https://github.com/OAI/OpenAPI-Specification/blob/master/examples/v3.0/petstore.yaml
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "net"
+ "net/http"
+ "os"
+
+ middleware "github.com/oapi-codegen/nethttp-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/stdhttp/api"
+)
+
+func main() {
+ port := flag.String("port", "8080", "Port for test HTTP server")
+ flag.Parse()
+
+ swagger, err := api.GetSpec()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
+ os.Exit(1)
+ }
+
+ // Clear out the servers array in the swagger spec, that skips validating
+ // that server names match. We don't know how this thing will be run.
+ swagger.Servers = nil
+
+ // Create an instance of our handler which satisfies the generated interface
+ petStore := api.NewPetStore()
+
+ r := http.NewServeMux()
+
+ // We now register our petStore above as the handler for the interface
+ api.HandlerFromMux(petStore, r)
+
+ // Use our validation middleware to check all requests against the
+ // OpenAPI schema.
+ h := middleware.OapiRequestValidator(swagger)(r)
+
+ s := &http.Server{
+ Handler: h,
+ Addr: net.JoinHostPort("0.0.0.0", *port),
+ }
+
+ // And we serve HTTP until the world ends.
+ log.Fatal(s.ListenAndServe())
+}
diff --git a/examples/petstore-expanded/stdhttp/petstore_test.go b/examples/petstore-expanded/stdhttp/petstore_test.go
new file mode 100644
index 0000000000..ce6322c946
--- /dev/null
+++ b/examples/petstore-expanded/stdhttp/petstore_test.go
@@ -0,0 +1,173 @@
+//go:build go1.22
+
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ middleware "github.com/oapi-codegen/nethttp-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/stdhttp/api"
+ "github.com/oapi-codegen/testutil"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func doGet(t *testing.T, mux *http.ServeMux, url string) *httptest.ResponseRecorder {
+ response := testutil.NewRequest().Get(url).WithAcceptJson().GoWithHTTPHandler(t, mux)
+ return response.Recorder
+}
+
+func TestPetStore(t *testing.T) {
+ var err error
+
+ // Get the swagger description of our API
+ swagger, err := api.GetSpec()
+ require.NoError(t, err)
+
+ // Clear out the servers array in the swagger spec, that skips validating
+ // that server names match. We don't know how this thing will be run.
+ swagger.Servers = nil
+
+ // Create a new ServeMux for testing.
+ m := http.NewServeMux()
+
+ // Use our validation middleware to check all requests against the
+ // OpenAPI schema.
+ opts := api.StdHTTPServerOptions{
+ BaseRouter: m,
+ Middlewares: []api.MiddlewareFunc{
+ middleware.OapiRequestValidator(swagger),
+ },
+ }
+
+ store := api.NewPetStore()
+ api.HandlerWithOptions(store, opts)
+
+ t.Run("Add pet", func(t *testing.T) {
+ tag := "TagOfSpot"
+ newPet := api.NewPet{
+ Name: "Spot",
+ Tag: &tag,
+ }
+
+ rr := testutil.NewRequest().Post("/pets").WithJsonBody(newPet).GoWithHTTPHandler(t, m).Recorder
+ assert.Equal(t, http.StatusCreated, rr.Code)
+
+ var resultPet api.Pet
+ err = json.NewDecoder(rr.Body).Decode(&resultPet)
+ assert.NoError(t, err, "error unmarshaling response")
+ assert.Equal(t, newPet.Name, resultPet.Name)
+ assert.Equal(t, *newPet.Tag, *resultPet.Tag)
+ })
+
+ t.Run("Find pet by ID", func(t *testing.T) {
+ pet := api.Pet{
+ Id: 100,
+ }
+
+ store.Pets[pet.Id] = pet
+ rr := doGet(t, m, fmt.Sprintf("/pets/%d", pet.Id))
+
+ var resultPet api.Pet
+ err = json.NewDecoder(rr.Body).Decode(&resultPet)
+ assert.NoError(t, err, "error getting pet")
+ assert.Equal(t, pet, resultPet)
+ })
+
+ t.Run("Pet not found", func(t *testing.T) {
+ rr := doGet(t, m, "/pets/27179095781")
+ assert.Equal(t, http.StatusNotFound, rr.Code)
+
+ var petError api.Error
+ err = json.NewDecoder(rr.Body).Decode(&petError)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, int32(http.StatusNotFound), petError.Code)
+ })
+
+ t.Run("List all pets", func(t *testing.T) {
+ store.Pets = map[int64]api.Pet{
+ 1: {},
+ 2: {},
+ }
+
+ // Now, list all pets, we should have two
+ rr := doGet(t, m, "/pets")
+ assert.Equal(t, http.StatusOK, rr.Code)
+
+ var petList []api.Pet
+ err = json.NewDecoder(rr.Body).Decode(&petList)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, 2, len(petList))
+ })
+
+ t.Run("Filter pets by tag", func(t *testing.T) {
+ tag := "TagOfFido"
+
+ store.Pets = map[int64]api.Pet{
+ 1: {
+ Tag: &tag,
+ },
+ 2: {},
+ }
+
+ // Filter pets by tag, we should have 1
+ rr := doGet(t, m, "/pets?tags=TagOfFido")
+ assert.Equal(t, http.StatusOK, rr.Code)
+
+ var petList []api.Pet
+ err = json.NewDecoder(rr.Body).Decode(&petList)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, 1, len(petList))
+ })
+
+ t.Run("Filter pets by tag", func(t *testing.T) {
+ store.Pets = map[int64]api.Pet{
+ 1: {},
+ 2: {},
+ }
+
+ // Filter pets by non-existent tag, we should have 0
+ rr := doGet(t, m, "/pets?tags=NotExists")
+ assert.Equal(t, http.StatusOK, rr.Code)
+
+ var petList []api.Pet
+ err = json.NewDecoder(rr.Body).Decode(&petList)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, 0, len(petList))
+ })
+
+ t.Run("Delete pets", func(t *testing.T) {
+ store.Pets = map[int64]api.Pet{
+ 1: {},
+ 2: {},
+ }
+
+ // Let's delete non-existent pet
+ rr := testutil.NewRequest().Delete("/pets/7").GoWithHTTPHandler(t, m).Recorder
+ assert.Equal(t, http.StatusNotFound, rr.Code)
+
+ var petError api.Error
+ err = json.NewDecoder(rr.Body).Decode(&petError)
+ assert.NoError(t, err, "error unmarshaling PetError")
+ assert.Equal(t, int32(http.StatusNotFound), petError.Code)
+
+ // Now, delete both real pets
+ rr = testutil.NewRequest().Delete("/pets/1").GoWithHTTPHandler(t, m).Recorder
+ assert.Equal(t, http.StatusNoContent, rr.Code)
+
+ rr = testutil.NewRequest().Delete("/pets/2").GoWithHTTPHandler(t, m).Recorder
+ assert.Equal(t, http.StatusNoContent, rr.Code)
+
+ // Should have no pets left.
+ var petList []api.Pet
+ rr = doGet(t, m, "/pets")
+ assert.Equal(t, http.StatusOK, rr.Code)
+ err = json.NewDecoder(rr.Body).Decode(&petList)
+ assert.NoError(t, err, "error getting response", err)
+ assert.Equal(t, 0, len(petList))
+ })
+}
diff --git a/examples/petstore-expanded/strict/api/petstore-server.gen.go b/examples/petstore-expanded/strict/api/petstore-server.gen.go
index 86bb165de0..e35edad725 100644
--- a/examples/petstore-expanded/strict/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/strict/api/petstore-server.gen.go
@@ -1,14 +1,15 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
+ "errors"
"fmt"
"net/http"
"net/url"
@@ -18,7 +19,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/go-chi/chi/v5"
"github.com/oapi-codegen/runtime"
- strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"
)
// ServerInterface represents all server handlers.
@@ -76,26 +76,36 @@ type MiddlewareFunc func(http.Handler) http.Handler
// FindPets operation middleware
func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// Parameter object where we will unmarshal all parameters from the context
var params FindPetsParams
// ------------- Optional query parameter "tags" -------------
- err = runtime.BindQueryParameter("form", true, false, "tags", r.URL.Query(), ¶ms.Tags)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "tags", r.URL.Query(), ¶ms.Tags, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
if err != nil {
- siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err})
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "tags"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "tags", Err: err})
+ }
return
}
// ------------- Optional query parameter "limit" -------------
- err = runtime.BindQueryParameter("form", true, false, "limit", r.URL.Query(), ¶ms.Limit)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
if err != nil {
- siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err})
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err})
+ }
return
}
@@ -107,12 +117,11 @@ func (siw *ServerInterfaceWrapper) FindPets(w http.ResponseWriter, r *http.Reque
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// AddPet operation middleware
func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.AddPet(w, r)
@@ -122,19 +131,19 @@ func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// DeletePet operation middleware
func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// ------------- Path parameter "id" -------------
var id int64
- err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, chi.URLParam(r, "id"), &id)
+ err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
return
@@ -148,19 +157,19 @@ func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Requ
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// FindPetByID operation middleware
func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// ------------- Path parameter "id" -------------
var id int64
- err = runtime.BindStyledParameterWithLocation("simple", false, "id", runtime.ParamLocationPath, chi.URLParam(r, "id"), &id)
+ err = runtime.BindStyledParameterWithOptions("simple", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
return
@@ -174,7 +183,7 @@ func (siw *ServerInterfaceWrapper) FindPetByID(w http.ResponseWriter, r *http.Re
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
type UnescapedCookieParamError struct {
@@ -317,10 +326,15 @@ type FindPetsResponseObject interface {
type FindPets200JSONResponse []Pet
func (response FindPets200JSONResponse) VisitFindPetsResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type FindPetsdefaultJSONResponse struct {
@@ -329,10 +343,15 @@ type FindPetsdefaultJSONResponse struct {
}
func (response FindPetsdefaultJSONResponse) VisitFindPetsResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(response.StatusCode)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type AddPetRequestObject struct {
@@ -346,10 +365,15 @@ type AddPetResponseObject interface {
type AddPet200JSONResponse Pet
func (response AddPet200JSONResponse) VisitAddPetResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type AddPetdefaultJSONResponse struct {
@@ -358,10 +382,15 @@ type AddPetdefaultJSONResponse struct {
}
func (response AddPetdefaultJSONResponse) VisitAddPetResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(response.StatusCode)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type DeletePetRequestObject struct {
@@ -386,10 +415,15 @@ type DeletePetdefaultJSONResponse struct {
}
func (response DeletePetdefaultJSONResponse) VisitDeletePetResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(response.StatusCode)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type FindPetByIDRequestObject struct {
@@ -403,10 +437,15 @@ type FindPetByIDResponseObject interface {
type FindPetByID200JSONResponse Pet
func (response FindPetByID200JSONResponse) VisitFindPetByIDResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type FindPetByIDdefaultJSONResponse struct {
@@ -415,10 +454,15 @@ type FindPetByIDdefaultJSONResponse struct {
}
func (response FindPetByIDdefaultJSONResponse) VisitFindPetByIDResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(response.StatusCode)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
// StrictServerInterface represents all server handlers.
@@ -437,8 +481,8 @@ type StrictServerInterface interface {
FindPetByID(ctx context.Context, request FindPetByIDRequestObject) (FindPetByIDResponseObject, error)
}
-type StrictHandlerFunc = strictnethttp.StrictHttpHandlerFunc
-type StrictMiddlewareFunc = strictnethttp.StrictHttpMiddlewareFunc
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
type StrictHTTPServerOptions struct {
RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
@@ -575,54 +619,55 @@ func (sh *strictHandler) FindPetByID(w http.ResponseWriter, r *http.Request, id
}
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/+RXW48budH9KwV+32OnNbEXedBTvB4vICBrT+LdvKznoYZdkmrBSw9Z1FgY6L8HRbZu",
- "I3k2QYIgQV506WY1T51zqlj9bGz0YwwUJJv5s8l2TR7rzw8pxaQ/xhRHSsJUL9s4kH4PlG3iUTgGM2+L",
- "od7rzDImj2LmhoO8fWM6I9uR2l9aUTK7znjKGVfffND+9iE0S+KwMrtdZxI9Fk40mPkvZtpwv/x+15mP",
- "9HRHcok7oL+y3Uf0BHEJsiYYSS437Izg6jLup+34etwLoHV3hTdhQ+c+Lc38l2fz/4mWZm7+b3YUYjap",
- "MJty2XUvk+HhEtLPgR8LAQ/nuE7F+MN3V8R4gZQHc7+73+llDsvYJA+CtuImj+zM3ODIQuj/mJ9wtaLU",
- "czTdRLH53K7Bu7sF/EToTWdK0qC1yJjns9lJ0K57kcU7yOhHRzVa1ihQMmVAzSZLTASYAQPQ17ZMIgzk",
- "Y8iSUAiWhFISZeBQOfg0UtAnve1vII9keckW61adcWwpZDqaw7wb0a4J3vQ3F5ifnp56rLf7mFazKTbP",
- "/rR4/+Hj5w+/e9Pf9GvxrjqGks+flp8pbdjS1cRndc1M5WBxp6zdTXmazmwo5cbK7/ub/kYfHUcKOLKZ",
- "m7f1UmdGlHX1xEwZ0h+rZrFzXv9CUlLIgM5VKmGZoq8U5W0W8o1r/V8yJVgry9ZSziDxS/iIHjINYGMY",
- "2FOQ4oGy9PAjkqWAGYT8GBNkXLEIZ8g4MoUOAllI6xhsyZDJnyxgAfQkPbyjQBgABVYJNzwgYFkV6gAt",
- "MNriuIb28L4kfGApCeLAEVxM5DuIKWAioBUJkKMJXSDbgS0pl6wl4chKyT3cFs7gGaSkkXMHY3EbDph0",
- "L0pRk+5AOFgeShDYYOKS4deSJfawCLBGC2sFgTkTjA6FEAa2UrzSsWhFpbngwCNny2EFGESzOebueFUc",
- "HjIf15hIEu5J1PXgo6MsTMB+pDSwMvVX3qBvCaHjx4IeBkZlJmGGR81tQ44FQgwgMUlMSgkvKQyH3Xu4",
- "S0iZgihMCuyPAEoKCJvoiowosKFAARVwI1c/PJakz1iE45OXlCbWl2jZcT7bpO6gH91RXws5DuhIhR06",
- "5dFSQtHE9LuHzyWPFAZWlh2qeYboYurUgZmsqJtrltUqmnUHG1qzLQ5BW1saigfHD5RiDz/G9MBAhbOP",
- "w6kMersa26HlwNh/CV/CZxqqEiXDktR8Lj7EVAMoHh2TiqTie9Da8FgfOJHP2XVA5axamuTgivpQ3dnD",
- "3RozOdcKY6Q0hVeaq7wksMRi+aE0wnG/j647jd+Qm6TjDaWE3fnWWifAQ3coxMAP6x5+FhjJOQpCWU+O",
- "MeZCWkn7IupBqcB9FWjR7bncP2mfVmWyq0AOtgglWJDEWerBtGFB6uGHki0BSe0GQ+FDFWinyJYcJa5w",
- "mn/3AV7dUrCaxxafMYDHlaZMblKrhz+XFuqjU92aelSad45QukPzASxWi6StnOzZ0p7MMTWZQzWqWVRg",
- "4NAdoUyFGzjzHnBWDJalDKxQc0YosvfZJGTb6Yy0ul8Pd6fCVOYmjGMi4eJPOlczTelO/K2tt/+iZ5wO",
- "DfW8Wwxmbn7gMOj5Uo+NpARQynUKOT8sBFfa92HJTijBw9boMGDm5rFQ2h5Pel1numlorHOJkK9n0OUU",
- "1S5gSrjV/1m29djT8aQOOOcIPH5lr228+AdKOtEkysVJhZXqWfYNTI49yxmo3xxHd/c6AuVRW0tF/+bm",
- "Zj/3UGjz2ji6aXKY/ZoV4vO1tF8b5tok94KI3cUANJLAHkwbj5ZYnPxDeF6D0cb6KxuXQF9Hba3ag9ua",
- "zuTiPabtlQFCsY0xXxk13idCqTNboCddux/G6lyjZ3DDrkt0nnMuPtFwYdZ3g3rVtOmUsnwfh+2/jIX9",
- "ZH1Jwx2JegyHQb8OsM3plCyp0O6f9MxvWuW/xxoXgtf7dR6dPfOwaxZxJFdewNp1jc0cVq6+tcADapuN",
- "zTWLW8hFc7rikdsa3Wzyakdb3GoPGZu2E5apf+gAfWwfPFwo/a1ecv1t6rKXfHeZtQJpKIb/JCFvD2JU",
- "FbawuFV4r79QnCt20HFx+63j5/ttvff367Ukset/m1z/s2X8QtGmfl1CabOX6fyteP9S3p+82err6e5+",
- "97cAAAD//ykDnxlaEgAA",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "5Fdbjxu50f0rBX7fY6c1sRd50FO8Hi8gIGtP4t28rOehhl2SasFLD1nUWBjovwdFtm4jeTZBgiBBXnTp",
+ "ZjVPnXOqWP1sbPRjDBQkm/mzyXZNHuvPDynFpD/GFEdKwlQv2ziQfg+UbeJROAYzb4uh3uvMMiaPYuaG",
+ "g7x9Yzoj25HaX1pRMrvOeMoZV9980P72ITRL4rAyu11nEj0WTjSY+S9m2nC//H7XmY/0dEdyiTugv7Ld",
+ "R/QEcQmyJhhJLjfsjODqMu6n7fh63AugdXeFN2FD5z4tzfyXZ/P/iZZmbv5vdhRiNqkwm3LZdS+T4eES",
+ "0s+BHwsBD+e4TsX4w3dXxHiBlAdzv7vf6WUOy9gkD4K24iaP7Mzc4MhC6P+Yn3C1otRzNN1EsfncrsG7",
+ "uwX8ROhNZ0rSoLXImOez2UnQrnuRxTvI6EdHNVrWKFAyZUDNJktMBJgBA9DXtkwiDORjyJJQCJaEUhJl",
+ "4FA5+DRS0Ce97W8gj2R5yRbrVp1xbClkOprDvBvRrgne9DcXmJ+ennqst/uYVrMpNs/+tHj/4ePnD797",
+ "09/0a/GuOoaSz5+Wnylt2NLVxGd1zUzlYHGnrN1NeZrObCjlxsrv+5v+Rh8dRwo4spmbt/VSZ0aUdfXE",
+ "TBnSH6tmsXNe/0JSUsiAzlUqYZmirxTlbRbyjWv9XzIlWCvL1lLOIPFL+IgeMg1gYxjYU5DigbL08COS",
+ "pYAZhPwYE2RcsQhnyDgyhQ4CWUjrGGzJkMmfLGAB9CQ9vKNAGAAFVgk3PCBgWRXqAC0w2uK4hvbwviR8",
+ "YCkJ4sARXEzkO4gpYCKgFQmQowldINuBLSmXrCXhyErJPdwWzuAZpKSRcwdjcRsOmHQvSlGT7kA4WB5K",
+ "ENhg4pLh15Il9rAIsEYLawWBOROMDoUQBrZSvNKxaEWlueDAI2fLYQUYRLM55u54VRweMh/XmEgS7knU",
+ "9eCjoyxMwH6kNLAy9VfeoG8JoePHgh4GRmUmYYZHzW1DjgVCDCAxSUxKCS8pDIfde7hLSJmCKEwK7I8A",
+ "SgoIm+iKjCiwoUABFXAjVz88lqTPWITjk5eUJtaXaNlxPtuk7qAf3VFfCzkO6EiFHTrl0VJC0cT0u4fP",
+ "JY8UBlaWHap5huhi6tSBmayom2uW1SqadQcbWrMtDkFbWxqKB8cPlGIPP8b0wECFs4/DqQx6uxrboeXA",
+ "2H8JX8JnGqoSJcOS1HwuPsRUAygeHZOKpOJ70NrwWB84kc/ZdUDlrFqa5OCK+lDd2cPdGjM51wpjpDSF",
+ "V5qrvCSwxGL5oTTCcb+PrjuN35CbpOMNpYTd+dZaJ8BDdyjEwA/rHn4WGMk5CkJZT44x5kJaSfsi6kGp",
+ "wH0VaNHtudw/aZ9WZbKrQA62CCVYkMRZ6sG0YUHq4YeSLQFJ7QZD4UMVaKfIlhwlrnCaf/cBXt1SsJrH",
+ "Fp8xgMeVpkxuUquHP5cW6qNT3Zp6VJp3jlC6Q/MBLFaLpK2c7NnSnswxNZlDNapZVGDg0B2hTIUbOPMe",
+ "cFYMlqUMrFBzRiiy99kkZNvpjLS6Xw93p8JU5iaMYyLh4k86VzNN6U78ra23/6JnnA4N9bxbDGZufuAw",
+ "6PlSj42kBFDKdQo5PywEV9r3YclOKMHD1ugwYObmsVDaHk96XWe6aWisc4mQr2fQ5RTVLmBKuNX/Wbb1",
+ "2NPxpA445wg8fmWvbbz4B0o60STKxUmFlepZ9g1Mjj3LGajfHEd39zoC5VFbS0X/5uZmP/dQaPPaOLpp",
+ "cpj9mhXi87W0Xxvm2iT3gojdxQA0ksAeTBuPllic/EN4XoPRxvorG5dAX0dtrdqD25rO5OI9pu2VAUKx",
+ "jTFfGTXeJ0KpM1ugJ127H8bqXKNncMOuS3Secy4+0XBh1neDetW06ZSyfB+H7b+Mhf1kfUnDHYl6DIdB",
+ "vw6wzemULKnQ7p/0zG9a5b/HGheC1/t1Hp0987BrFnEkV17A2nWNzRxWrr61wANqm43NNYtbyEVzuuKR",
+ "2xrdbPJqR1vcag8Zm7YTlql/6AB9bB88XCj9rV5y/W3qspd8d5m1Amkohv8kIW8PYlQVtrC4VXivv1Cc",
+ "K3bQcXH7rePn+2299/frtSSx63+bXP+zZfxC0aZ+XUJps5fp/K14/1Len7zZ6uvp7n73twAAAP//",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -630,7 +675,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -648,12 +693,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -679,3 +724,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/examples/petstore-expanded/strict/api/petstore-types.gen.go b/examples/petstore-expanded/strict/api/petstore-types.gen.go
index 551af8d9d0..0e4954f349 100644
--- a/examples/petstore-expanded/strict/api/petstore-types.gen.go
+++ b/examples/petstore-expanded/strict/api/petstore-types.gen.go
@@ -1,6 +1,6 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
// Error defines model for Error.
diff --git a/examples/petstore-expanded/strict/api/petstore.go b/examples/petstore-expanded/strict/api/petstore.go
index 29b7bd291b..fc5c9fda2f 100644
--- a/examples/petstore-expanded/strict/api/petstore.go
+++ b/examples/petstore-expanded/strict/api/petstore.go
@@ -1,5 +1,5 @@
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../../petstore-expanded.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../../petstore-expanded.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../../petstore-expanded.yaml
package api
diff --git a/examples/petstore-expanded/strict/api/server.cfg.yaml b/examples/petstore-expanded/strict/api/server.cfg.yaml
index f3c71c63f5..48d2bf90b3 100644
--- a/examples/petstore-expanded/strict/api/server.cfg.yaml
+++ b/examples/petstore-expanded/strict/api/server.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
chi-server: true
diff --git a/examples/petstore-expanded/strict/api/types.cfg.yaml b/examples/petstore-expanded/strict/api/types.cfg.yaml
index 9ac30e11e9..cf5128b726 100644
--- a/examples/petstore-expanded/strict/api/types.cfg.yaml
+++ b/examples/petstore-expanded/strict/api/types.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
models: true
diff --git a/examples/petstore-expanded/strict/petstore.go b/examples/petstore-expanded/strict/petstore.go
index 1ab30c41c3..e7dc41a97f 100644
--- a/examples/petstore-expanded/strict/petstore.go
+++ b/examples/petstore-expanded/strict/petstore.go
@@ -12,16 +12,16 @@ import (
"net/http"
"os"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/strict/api"
- middleware "github.com/oapi-codegen/nethttp-middleware"
"github.com/go-chi/chi/v5"
+ middleware "github.com/oapi-codegen/nethttp-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/strict/api"
)
func main() {
port := flag.String("port", "8080", "Port for test HTTP server")
flag.Parse()
- swagger, err := api.GetSwagger()
+ swagger, err := api.GetSpec()
if err != nil {
fmt.Fprintf(os.Stderr, "Error loading swagger spec\n: %s", err)
os.Exit(1)
diff --git a/examples/petstore-expanded/strict/petstore_test.go b/examples/petstore-expanded/strict/petstore_test.go
index d449ed7037..1ec6a76ea4 100644
--- a/examples/petstore-expanded/strict/petstore_test.go
+++ b/examples/petstore-expanded/strict/petstore_test.go
@@ -7,10 +7,10 @@ import (
"net/http/httptest"
"testing"
- "github.com/deepmap/oapi-codegen/examples/petstore-expanded/strict/api"
- middleware "github.com/oapi-codegen/nethttp-middleware"
- "github.com/deepmap/oapi-codegen/pkg/testutil"
"github.com/go-chi/chi/v5"
+ middleware "github.com/oapi-codegen/nethttp-middleware"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/strict/api"
+ "github.com/oapi-codegen/testutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -24,7 +24,7 @@ func TestPetStore(t *testing.T) {
var err error
// Get the swagger description of our API
- swagger, err := api.GetSwagger()
+ swagger, err := api.GetSpec()
require.NoError(t, err)
// Clear out the servers array in the swagger spec, that skips validating
diff --git a/examples/streaming/README.md b/examples/streaming/README.md
new file mode 100644
index 0000000000..aeb445a82b
--- /dev/null
+++ b/examples/streaming/README.md
@@ -0,0 +1,17 @@
+OpenAPI Code Generation Example - Streaming
+-------------------------------------------
+
+This directory contains an example server using our code generator which implements
+a simple streaming API with a single endpoint.
+
+This is the structure:
+- `sse.yaml`: Contains the OpenAPI 3.0 specification
+- `stdhttp/`: Contains the written and generated code for the server using the standard http package
+- `client/`: Contains a client which reads the server stream and prints out the messages
+
+You can run both together to demonstrate the end-to-end behavior from
+both client and server side. Run these commands in parallel:
+
+ go run ./stdhttp
+ go run ./client
+
diff --git a/examples/streaming/client/main.go b/examples/streaming/client/main.go
new file mode 100644
index 0000000000..78cf097a6c
--- /dev/null
+++ b/examples/streaming/client/main.go
@@ -0,0 +1,52 @@
+package main
+
+import (
+ "bufio"
+ "context"
+ "flag"
+ "fmt"
+ "log/slog"
+ "net/http"
+ "os"
+ "os/signal"
+ "syscall"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/streaming/client/sse"
+)
+
+func main() {
+ serverURL := flag.String("url", "http://localhost:8080", "server base URL")
+ flag.Parse()
+
+ ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
+ defer cancel()
+
+ client, err := sse.NewClient(*serverURL)
+ if err != nil {
+ slog.Error("NewClient failed", "error", err)
+ os.Exit(1)
+ }
+
+ // Use the plain Client (not ClientWithResponses) so the response body stays
+ // an open io.Reader — ClientWithResponses would io.ReadAll the stream.
+ resp, err := client.GetStream(ctx)
+ if err != nil {
+ slog.Error("GetStream failed", "error", err)
+ os.Exit(1)
+ }
+ defer func() { _ = resp.Body.Close() }()
+
+ if resp.StatusCode != http.StatusOK {
+ slog.Error("unexpected status", "status", resp.Status)
+ os.Exit(1)
+ }
+
+ scanner := bufio.NewScanner(resp.Body)
+ for scanner.Scan() {
+ fmt.Println(scanner.Text())
+ }
+ if err := scanner.Err(); err != nil && ctx.Err() == nil {
+ slog.Error("scan failed", "error", err)
+ os.Exit(1)
+ }
+}
diff --git a/examples/streaming/client/sse/cfg.yaml b/examples/streaming/client/sse/cfg.yaml
new file mode 100644
index 0000000000..1e318e2d6e
--- /dev/null
+++ b/examples/streaming/client/sse/cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: sse
+output: streaming.gen.go
+generate:
+ client: true
+ models: true
diff --git a/examples/streaming/client/sse/generate.go b/examples/streaming/client/sse/generate.go
new file mode 100644
index 0000000000..22de846215
--- /dev/null
+++ b/examples/streaming/client/sse/generate.go
@@ -0,0 +1,3 @@
+package sse
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../sse.yaml
diff --git a/examples/streaming/client/sse/streaming.gen.go b/examples/streaming/client/sse/streaming.gen.go
new file mode 100644
index 0000000000..31b195d7e2
--- /dev/null
+++ b/examples/streaming/client/sse/streaming.gen.go
@@ -0,0 +1,235 @@
+// Package sse provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package sse
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetStream request
+ GetStream(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetStream(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetStreamRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetStreamRequest generates requests for GetStream
+func NewGetStreamRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetStreamWithResponse request
+ GetStreamWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetStreamResponse, error)
+}
+
+type GetStreamResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetStreamResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetStreamResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetStreamResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetStreamResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetStreamWithResponse request returning *GetStreamResponse
+func (c *ClientWithResponses) GetStreamWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetStreamResponse, error) {
+ rsp, err := c.GetStream(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetStreamResponse(rsp)
+}
+
+// ParseGetStreamResponse parses an HTTP response from a GetStreamWithResponse call
+func ParseGetStreamResponse(rsp *http.Response) (*GetStreamResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetStreamResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
diff --git a/examples/streaming/sse.yaml b/examples/streaming/sse.yaml
new file mode 100644
index 0000000000..ed972393d6
--- /dev/null
+++ b/examples/streaming/sse.yaml
@@ -0,0 +1,28 @@
+openapi: 3.0.0
+info:
+ title: Simple JSONL Streaming Service
+ version: 1.0.0
+paths:
+ /:
+ get:
+ summary: JSON Lines Stream
+ description: Provides a stream of JSON documents (one per line, application/jsonl) containing a timestamp and sequence number.
+ operationId: getStream
+ responses:
+ 200:
+ description: JSONL Stream
+ content:
+ application/jsonl:
+ schema:
+ type: object
+ properties:
+ time:
+ type: string
+ format: date-time
+ description: Timestamp of the event.
+ sequence:
+ type: integer
+ description: Sequence number of the event.
+ example:
+ time: "2023-11-20T10:30:00Z"
+ sequence: 1
\ No newline at end of file
diff --git a/examples/streaming/stdhttp/main.go b/examples/streaming/stdhttp/main.go
new file mode 100644
index 0000000000..385097fda3
--- /dev/null
+++ b/examples/streaming/stdhttp/main.go
@@ -0,0 +1,25 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "github.com/oapi-codegen/oapi-codegen/v2/examples/streaming/stdhttp/sse"
+ "log/slog"
+ "os"
+ "os/signal"
+ "syscall"
+)
+
+func main() {
+ port := flag.String("port", "8080", "port to serve on")
+ flag.Parse()
+
+ server := sse.NewServer(*port)
+ ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
+ defer cancel()
+ err := server.Run(ctx)
+ if err != nil {
+ slog.Error("server run failed", "error", err)
+ os.Exit(1)
+ }
+}
diff --git a/examples/streaming/stdhttp/sse/cfg.yaml b/examples/streaming/stdhttp/sse/cfg.yaml
new file mode 100644
index 0000000000..14ddeb0c2c
--- /dev/null
+++ b/examples/streaming/stdhttp/sse/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: sse
+output: streaming.gen.go
+generate:
+ std-http-server: true
+ strict-server: true
+ models: true
+ embedded-spec: true
diff --git a/examples/streaming/stdhttp/sse/generate.go b/examples/streaming/stdhttp/sse/generate.go
new file mode 100644
index 0000000000..22de846215
--- /dev/null
+++ b/examples/streaming/stdhttp/sse/generate.go
@@ -0,0 +1,3 @@
+package sse
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml ../../sse.yaml
diff --git a/examples/streaming/stdhttp/sse/impl.go b/examples/streaming/stdhttp/sse/impl.go
new file mode 100644
index 0000000000..4dfdaed6d6
--- /dev/null
+++ b/examples/streaming/stdhttp/sse/impl.go
@@ -0,0 +1,89 @@
+package sse
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "log/slog"
+ "net/http"
+ "time"
+)
+
+type Server struct {
+ httpServer *http.Server
+}
+
+func NewServer(port string) *Server {
+ s := &Server{}
+ strictHandler := NewStrictHandler(s, nil)
+ handler := Handler(strictHandler)
+ s.httpServer = &http.Server{
+ Handler: handler,
+ Addr: ":" + port,
+ }
+ return s
+}
+func (s Server) Run(ctx context.Context) error {
+ go func() {
+ <-ctx.Done()
+ slog.Warn("context cancelled, shutting down")
+ ctxTimeout, cancel := context.WithTimeout(context.Background(), 5*time.Second)
+ err := s.httpServer.Shutdown(ctxTimeout)
+ cancel()
+ if err != nil {
+ slog.Error("httpServer.Shutdown() error", "error", err)
+ }
+ }()
+
+ err := s.httpServer.ListenAndServe()
+ if err != nil && !errors.Is(err, http.ErrServerClosed) {
+ return fmt.Errorf("httpServer.ListenAndServe() error: %w", err)
+ }
+ return nil
+}
+
+type SObject struct {
+ Time time.Time `json:"time"`
+ Sequence int `json:"sequence"`
+}
+
+// GetStream handles GET / and will stream a JSON object every second.
+func (Server) GetStream(ctx context.Context, _ GetStreamRequestObject) (GetStreamResponseObject, error) {
+ r, w := io.Pipe() // creates a pipe so that we can write to the response body asynchronously
+ go func() {
+ defer func() { _ = w.Close() }()
+ seq := 1
+ ticker := time.NewTicker(time.Second)
+ for {
+ select {
+ case <-ctx.Done():
+ slog.Info("request context done, closing stream")
+ return
+ case <-ticker.C:
+ content := getContent(seq)
+ if _, err := w.Write(content); err != nil {
+ return
+ }
+ if _, err := w.Write([]byte("\n")); err != nil {
+ return
+ }
+ seq++
+ }
+ }
+ }()
+ return GetStream200ApplicationjsonlResponse{
+ Body: r,
+ ContentLength: 0,
+ }, nil
+}
+
+func getContent(seq int) []byte {
+ streamObject := SObject{
+ Time: time.Now(),
+ Sequence: seq,
+ }
+ bytes, _ := json.Marshal(streamObject)
+ return bytes
+}
diff --git a/examples/streaming/stdhttp/sse/streaming.gen.go b/examples/streaming/stdhttp/sse/streaming.gen.go
new file mode 100644
index 0000000000..cd2a15e01c
--- /dev/null
+++ b/examples/streaming/stdhttp/sse/streaming.gen.go
@@ -0,0 +1,390 @@
+//go:build go1.22
+
+// Package sse provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package sse
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // JSON Lines Stream
+ // (GET /)
+ GetStream(w http.ResponseWriter, r *http.Request)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetStream operation middleware
+func (siw *ServerInterfaceWrapper) GetStream(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetStream(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{})
+}
+
+// ServeMux is an abstraction of [http.ServeMux].
+type ServeMux interface {
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+ http.Handler
+}
+
+type StdHTTPServerOptions struct {
+ BaseURL string
+ BaseRouter ServeMux
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/{$}", wrapper.GetStream)
+
+ return m
+}
+
+type GetStreamRequestObject struct {
+}
+
+type GetStreamResponseObject interface {
+ VisitGetStreamResponse(w http.ResponseWriter) error
+}
+
+type GetStream200ApplicationjsonlResponse struct {
+ Body io.Reader
+ ContentLength int64
+}
+
+func (response GetStream200ApplicationjsonlResponse) VisitGetStreamResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "application/jsonl")
+ if response.ContentLength != 0 {
+ w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
+ }
+ w.WriteHeader(200)
+
+ if closer, ok := response.Body.(io.ReadCloser); ok {
+ defer closer.Close()
+ }
+ flusher, ok := w.(http.Flusher)
+ if !ok {
+ // If w doesn't support flushing, fall back to io.Copy.
+ _, err := io.Copy(w, response.Body)
+ return err
+ }
+ // text/event-stream messages are typically small; use a
+ // modest buffer and flush after each chunk so clients see
+ // events immediately instead of waiting on OS buffering.
+ buf := make([]byte, 4096)
+ for {
+ n, err := response.Body.Read(buf)
+ if n > 0 {
+ if _, writeErr := w.Write(buf[:n]); writeErr != nil {
+ return writeErr
+ }
+ flusher.Flush()
+ }
+ if err != nil {
+ if err == io.EOF {
+ return nil
+ }
+ return err
+ }
+ }
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+ // JSON Lines Stream
+ // (GET /)
+ GetStream(ctx context.Context, request GetStreamRequestObject) (GetStreamResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// GetStream operation middleware
+func (sh *strictHandler) GetStream(w http.ResponseWriter, r *http.Request) {
+ var request GetStreamRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetStream(ctx, request.(GetStreamRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetStream")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetStreamResponseObject); ok {
+ if err := validResponse.VisitGetStreamResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "ZJJBb9swDIX/CsHTBjipnNz0B4YNxTbAPe2m2kzCwqI0iQlWFP7vA+UtXbKLZVB473t80BuyHBL6N1TW",
+ "mdDjwDHPBF+Gb18fYdBCIbIcYaBy4ZGwwwuVyknQY791W4dLhymThMzocd9GHeagp2q2D/Y5ktoxUR0L",
+ "Z13V30u68EQVAtSGgXRoWJjSeI4kWuFDEoJMBWYW6iDkPPMYzODhpSaZP8KYRAOLRQygHKlqiBmCTFDp",
+ "55lkJJBzfKayxRa0NPnnCT1+Il0XxA4L1ZykUgu9c84O8yZp0f8j25B+BevKfv+y0PcdWgz0uHO7/abv",
+ "Nzv31Du/d965H9ZWHU8Ug6lysUDKK/Xd476q4XYTK0pPBHQhUVtLX7MBWZSOVIyxRrj3ebr2c+9wSCUG",
+ "RY9TUNo09dW2amE54rJcJ+n5hUbFxUa3hH+fTVPUc4yhvP65gkcWqu/3y/I7AAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/examples/tools.go b/examples/tools.go
index f584776b08..8615cb4c57 100644
--- a/examples/tools.go
+++ b/examples/tools.go
@@ -4,5 +4,5 @@
package tools
import (
- _ "github.com/deepmap/oapi-codegen/cmd/oapi-codegen"
+ _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen"
)
diff --git a/go.mod b/go.mod
index d1dcc2c285..c28ff81291 100644
--- a/go.mod
+++ b/go.mod
@@ -1,96 +1,28 @@
-module github.com/deepmap/oapi-codegen
+module github.com/oapi-codegen/oapi-codegen/v2
-go 1.20
+go 1.25.9
require (
- github.com/apapsch/go-jsonmerge/v2 v2.0.0
- github.com/getkin/kin-openapi v0.118.0
- github.com/gin-gonic/gin v1.9.1
- github.com/go-chi/chi/v5 v5.0.10
- github.com/gofiber/fiber/v2 v2.49.1
- github.com/google/uuid v1.3.1
- github.com/kataras/iris/v12 v12.2.6-0.20230908161203-24ba4e8933b9
- github.com/labstack/echo/v4 v4.11.1
- github.com/stretchr/testify v1.8.4
- golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
- golang.org/x/text v0.13.0
- golang.org/x/tools v0.12.0
- gopkg.in/yaml.v2 v2.4.0
+ github.com/getkin/kin-openapi v0.140.0
+ github.com/speakeasy-api/openapi v1.23.0
+ github.com/stretchr/testify v1.11.1
+ go.yaml.in/yaml/v3 v3.0.4
+ golang.org/x/mod v0.36.0
+ golang.org/x/text v0.37.0
+ golang.org/x/tools v0.45.0
+ gopkg.in/yaml.v3 v3.0.1
)
require (
- github.com/BurntSushi/toml v1.3.2 // indirect
- github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 // indirect
- github.com/CloudyKit/jet/v6 v6.2.0 // indirect
- github.com/Joker/jade v1.1.3 // indirect
- github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect
- github.com/andybalholm/brotli v1.0.5 // indirect
- github.com/aymerick/douceur v0.2.0 // indirect
- github.com/bytedance/sonic v1.9.1 // indirect
- github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/fatih/structs v1.1.0 // indirect
- github.com/flosch/pongo2/v4 v4.0.2 // indirect
- github.com/gabriel-vasile/mimetype v1.4.2 // indirect
- github.com/gin-contrib/sse v0.1.0 // indirect
- github.com/go-openapi/jsonpointer v0.19.5 // indirect
- github.com/go-openapi/swag v0.19.5 // indirect
- github.com/go-playground/locales v0.14.1 // indirect
- github.com/go-playground/universal-translator v0.18.1 // indirect
- github.com/go-playground/validator/v10 v10.14.0 // indirect
- github.com/goccy/go-json v0.10.2 // indirect
- github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
- github.com/golang/snappy v0.0.4 // indirect
- github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 // indirect
- github.com/gorilla/css v1.0.0 // indirect
- github.com/gorilla/mux v1.8.0 // indirect
- github.com/invopop/yaml v0.1.0 // indirect
- github.com/iris-contrib/schema v0.0.6 // indirect
- github.com/josharian/intern v1.0.0 // indirect
- github.com/json-iterator/go v1.1.12 // indirect
- github.com/kataras/blocks v0.0.7 // indirect
- github.com/kataras/golog v0.1.9 // indirect
- github.com/kataras/pio v0.0.12 // indirect
- github.com/kataras/sitemap v0.0.6 // indirect
- github.com/kataras/tunnel v0.0.4 // indirect
- github.com/klauspost/compress v1.16.7 // indirect
- github.com/klauspost/cpuid/v2 v2.2.4 // indirect
- github.com/labstack/gommon v0.4.0 // indirect
- github.com/leodido/go-urn v1.2.4 // indirect
- github.com/mailgun/raymond/v2 v2.0.48 // indirect
- github.com/mailru/easyjson v0.7.7 // indirect
- github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.19 // indirect
- github.com/mattn/go-runewidth v0.0.15 // indirect
- github.com/microcosm-cc/bluemonday v1.0.25 // indirect
- github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
- github.com/modern-go/reflect2 v1.0.2 // indirect
- github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
- github.com/pelletier/go-toml/v2 v2.0.8 // indirect
- github.com/perimeterx/marshmallow v1.1.4 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/rivo/uniseg v0.2.0 // indirect
- github.com/russross/blackfriday/v2 v2.1.0 // indirect
- github.com/schollz/closestmatch v2.1.0+incompatible // indirect
- github.com/sirupsen/logrus v1.8.1 // indirect
- github.com/tdewolff/minify/v2 v2.12.9 // indirect
- github.com/tdewolff/parse/v2 v2.6.8 // indirect
- github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
- github.com/ugorji/go/codec v1.2.11 // indirect
- github.com/valyala/bytebufferpool v1.0.0 // indirect
- github.com/valyala/fasthttp v1.49.0 // indirect
- github.com/valyala/fasttemplate v1.2.2 // indirect
- github.com/valyala/tcplisten v1.0.0 // indirect
- github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
- github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
- github.com/yosssi/ace v0.0.5 // indirect
- golang.org/x/arch v0.3.0 // indirect
- golang.org/x/crypto v0.13.0 // indirect
- golang.org/x/mod v0.12.0 // indirect
- golang.org/x/net v0.15.0 // indirect
- golang.org/x/sys v0.12.0 // indirect
- golang.org/x/time v0.3.0 // indirect
- google.golang.org/protobuf v1.31.0 // indirect
- gopkg.in/ini.v1 v1.67.0 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
+ github.com/go-openapi/jsonpointer v0.23.1 // indirect
+ github.com/go-openapi/swag/jsonname v0.26.0 // indirect
+ github.com/oasdiff/yaml v0.1.0 // indirect
+ github.com/oasdiff/yaml3 v0.0.13 // indirect
+ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
+ github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
+ github.com/speakeasy-api/jsonpath v0.6.3 // indirect
+ github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
+ golang.org/x/sync v0.20.0 // indirect
)
diff --git a/go.sum b/go.sum
index 6371882e0b..7637121b6a 100644
--- a/go.sum
+++ b/go.sum
@@ -1,285 +1,169 @@
-github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
-github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
-github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c=
-github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
-github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME=
-github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4=
-github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc=
-github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
-github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk=
-github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM=
-github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
-github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0=
-github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM=
-github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
-github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
-github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
-github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
-github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
-github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
-github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
-github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
-github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
-github.com/bytedance/sonic v1.9.1 h1:6iJ6NqdoxCDr6mbY8h18oSO+cShGSMRGCEo7F2h0x8s=
-github.com/bytedance/sonic v1.9.1/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
-github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
-github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
-github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
-github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
-github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
-github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw=
-github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
-github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
-github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
-github.com/getkin/kin-openapi v0.118.0 h1:z43njxPmJ7TaPpMSCQb7PN0dEYno4tyBPQcrFdHoLuM=
-github.com/getkin/kin-openapi v0.118.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc=
-github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
-github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
-github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
-github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
-github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
-github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
-github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
-github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
-github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
-github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
-github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
-github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
-github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
-github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.14.0 h1:vgvQWe3XCz3gIeFDm/HnTIbj6UGmg/+t63MyGU2n5js=
-github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
-github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
-github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
-github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
-github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
-github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
-github.com/gofiber/fiber/v2 v2.49.1 h1:0W2DRWevSirc8pJl4o8r8QejDR8TV6ZUCawHxwbIdOk=
-github.com/gofiber/fiber/v2 v2.49.1/go.mod h1:nPUeEBUeeYGgwbDm59Gp7vS8MDyScL6ezr/Np9A13WU=
-github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
-github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
+github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58=
+github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w=
+github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/getkin/kin-openapi v0.140.0 h1:JFn675aXRFjyiZKa/BFWploGldQlI0gobp4J5k0EZ2g=
+github.com/getkin/kin-openapi v0.140.0/go.mod h1:lISrB64F0CPcuDJ3LdtPTMJBY8VENjR9wJBdrcT6J3g=
+github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4=
+github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY=
+github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w=
+github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M=
+github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4=
+github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
-github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 h1:uK3X/2mt4tbSGoHvbLBHUny7CKiuwUip3MArtukol4E=
-github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
-github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
-github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
-github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
-github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
-github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
-github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
-github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
-github.com/invopop/yaml v0.1.0 h1:YW3WGUoJEXYfzWBjn00zIlrw7brGVD0fUKRYDPAPhrc=
-github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
-github.com/iris-contrib/httpexpect/v2 v2.15.2 h1:T9THsdP1woyAqKHwjkEsbCnMefsAFvk8iJJKokcJ3Go=
-github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw=
-github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA=
-github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
-github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
-github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
-github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
-github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
-github.com/kataras/blocks v0.0.7 h1:cF3RDY/vxnSRezc7vLFlQFTYXG/yAr1o7WImJuZbzC4=
-github.com/kataras/blocks v0.0.7/go.mod h1:UJIU97CluDo0f+zEjbnbkeMRlvYORtmc1304EeyXf4I=
-github.com/kataras/golog v0.1.9 h1:vLvSDpP7kihFGKFAvBSofYo7qZNULYSHOH2D7rPTKJk=
-github.com/kataras/golog v0.1.9/go.mod h1:jlpk/bOaYCyqDqH18pgDHdaJab72yBE6i0O3s30hpWY=
-github.com/kataras/iris/v12 v12.2.6-0.20230908161203-24ba4e8933b9 h1:Vx8kDVhO2qepK8w44lBtp+RzN3ld743i+LYPzODJSpQ=
-github.com/kataras/iris/v12 v12.2.6-0.20230908161203-24ba4e8933b9/go.mod h1:ldkoR3iXABBeqlTibQ3MYaviA1oSlPvim6f55biwBh4=
-github.com/kataras/pio v0.0.12 h1:o52SfVYauS3J5X08fNjlGS5arXHjW/ItLkyLcKjoH6w=
-github.com/kataras/pio v0.0.12/go.mod h1:ODK/8XBhhQ5WqrAhKy+9lTPS7sBf6O3KcLhc9klfRcY=
-github.com/kataras/sitemap v0.0.6 h1:w71CRMMKYMJh6LR2wTgnk5hSgjVNB9KL60n5e2KHvLY=
-github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4=
-github.com/kataras/tunnel v0.0.4 h1:sCAqWuJV7nPzGrlb0os3j49lk2JhILT0rID38NHNLpA=
-github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw=
-github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
-github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
-github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.4 h1:acbojRNwl3o09bUq+yDCtZFc1aiwaAAxtcn8YkZXnvk=
-github.com/klauspost/cpuid/v2 v2.2.4/go.mod h1:RVVoqg1df56z8g3pUjL/3lE5UfnlrJX8tyFgg4nqhuY=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
-github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4=
-github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ=
-github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
-github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
-github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
-github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
-github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw=
-github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18=
-github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
-github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
-github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
-github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
-github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
-github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
-github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg=
-github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE=
-github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
-github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
-github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
-github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
-github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
-github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
-github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ=
-github.com/pelletier/go-toml/v2 v2.0.8/go.mod h1:vuYfssBdrU2XDZ9bYydBu6t+6a6PYNcZljzZR9VXg+4=
-github.com/perimeterx/marshmallow v1.1.4 h1:pZLDH9RjlLGGorbXhcaQLhfuV0pFMNfPO55FuFkxqLw=
-github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/oasdiff/yaml v0.1.0 h1:0bqZjfKc/8S9urj4JuwepX41WX9EoA6ifhU3SV06cXg=
+github.com/oasdiff/yaml v0.1.0/go.mod h1:kOlRmMdL2X3vucLCEQO5u61SU22RysnfXvcttrZA1O0=
+github.com/oasdiff/yaml3 v0.0.13 h1:06svmvOHOVBqF81+sY2EUScvUI/iS/vl2VIeUUxZQwg=
+github.com/oasdiff/yaml3 v0.0.13/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
+github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
+github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
-github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
-github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
-github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
-github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
-github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
-github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
-github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
-github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
-github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
+github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
+github.com/speakeasy-api/jsonpath v0.6.3 h1:c+QPwzAOdrWvzycuc9HFsIZcxKIaWcNpC+xhOW9rJxU=
+github.com/speakeasy-api/jsonpath v0.6.3/go.mod h1:2cXloNuQ+RSXi5HTRaeBh7JEmjRXTiaKpFTdZiL7URI=
+github.com/speakeasy-api/openapi v1.23.0 h1:BlnHqUR/8uIs4tp3d2B4QDN03gw1/QY2R2MHg6fLhRU=
+github.com/speakeasy-api/openapi v1.23.0/go.mod h1:Ih+ZzaTCCPyB2ykiDXaxhqk6jsY84ke3n5p6fobMDXk=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
-github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
-github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/tdewolff/minify/v2 v2.12.9 h1:dvn5MtmuQ/DFMwqf5j8QhEVpPX6fi3WGImhv8RUB4zA=
-github.com/tdewolff/minify/v2 v2.12.9/go.mod h1:qOqdlDfL+7v0/fyymB+OP497nIxJYSvX4MQWA8OoiXU=
-github.com/tdewolff/parse/v2 v2.6.8 h1:mhNZXYCx//xG7Yq2e/kVLNZw4YfYmeHbhx+Zc0OvFMA=
-github.com/tdewolff/parse/v2 v2.6.8/go.mod h1:XHDhaU6IBgsryfdnpzUXBlT6leW/l25yrFBTEb4eIyM=
-github.com/tdewolff/test v1.0.9 h1:SswqJCmeN4B+9gEAi/5uqT0qpi1y2/2O47V/1hhGZT0=
-github.com/tdewolff/test v1.0.9/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
-github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
-github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
-github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
-github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
-github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
-github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
-github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
-github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.49.0 h1:9FdvCpmxB74LH4dPb7IJ1cOSsluR07XG3I1txXWwJpE=
-github.com/valyala/fasthttp v1.49.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
-github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
-github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
-github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
-github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
-github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
-github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
-github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
-github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
-github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
-github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
-github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
-github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
-github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
-github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
-github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
-github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
-github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
-github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
-golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k=
-golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk=
+github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
+go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
-golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
-golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
-golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
-golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
-golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
+golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
-golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
+golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
-golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
+golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
-golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
-golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
+golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
-golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
-golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
-golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
+golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
+golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
-google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
-gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
-gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs=
-rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/internal/test/Makefile b/internal/test/Makefile
new file mode 100644
index 0000000000..5ec0edd058
--- /dev/null
+++ b/internal/test/Makefile
@@ -0,0 +1,17 @@
+lint:
+ $(GOBIN)/golangci-lint run ./...
+
+lint-ci:
+ $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m
+
+generate:
+ go generate ./...
+
+test:
+ go test -cover ./...
+
+tidy:
+ go mod tidy
+
+tidy-ci:
+ tidied -verbose
diff --git a/internal/test/all_of/config1.yaml b/internal/test/all_of/config1.yaml
index 5e023c1f47..1cc8fe87c7 100644
--- a/internal/test/all_of/config1.yaml
+++ b/internal/test/all_of/config1.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
package: v1
generate:
models: true
diff --git a/internal/test/all_of/config2.yaml b/internal/test/all_of/config2.yaml
index bd93f3c391..b5b9d64be7 100644
--- a/internal/test/all_of/config2.yaml
+++ b/internal/test/all_of/config2.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
package: v2
generate:
models: true
diff --git a/internal/test/all_of/doc.go b/internal/test/all_of/doc.go
index 0388e17ebf..b154cb2245 100644
--- a/internal/test/all_of/doc.go
+++ b/internal/test/all_of/doc.go
@@ -1,4 +1,4 @@
package allof
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config1.yaml openapi.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config2.yaml openapi.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config1.yaml openapi.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config2.yaml openapi.yaml
diff --git a/internal/test/all_of/openapi.yaml b/internal/test/all_of/openapi.yaml
index f73a8e5f1b..e1c780752f 100644
--- a/internal/test/all_of/openapi.yaml
+++ b/internal/test/all_of/openapi.yaml
@@ -51,3 +51,14 @@ components:
type: integer
format: int64
required: [ ID ]
+ PersonWithMorePropertiesOutsideOfAllOf:
+ type: object
+ description: |
+ This is a person record as returned from a Create endpoint. It contains
+ all the fields of a Person, with an additional property outside of allOf directives.
+ properties:
+ additionalProperty:
+ type: string
+ required: [ additionalProperty ]
+ allOf:
+ - $ref: "#/components/schemas/Person"
diff --git a/internal/test/all_of/v1/openapi.gen.go b/internal/test/all_of/v1/openapi.gen.go
index fbb1146829..2f16c10b84 100644
--- a/internal/test/all_of/v1/openapi.gen.go
+++ b/internal/test/all_of/v1/openapi.gen.go
@@ -1,11 +1,11 @@
// Package v1 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package v1
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/url"
@@ -15,7 +15,9 @@ import (
"github.com/getkin/kin-openapi/openapi3"
)
-// Person defines model for Person.
+// Person This is a person, with mandatory first and last name, but optional ID
+// number. This would be returned by a `Get` style API. We merge the person
+// properties with another Schema which only provides required fields.
type Person struct {
// Embedded struct due to allOf(#/components/schemas/PersonProperties)
PersonProperties `yaml:",inline"`
@@ -30,7 +32,8 @@ type PersonProperties struct {
LastName *string `json:"LastName,omitempty"`
}
-// PersonWithID defines model for PersonWithID.
+// PersonWithID This is a person record as returned from a Create endpoint. It contains
+// all the fields of a Person, with an additional resource UUID.
type PersonWithID struct {
// Embedded struct due to allOf(#/components/schemas/Person)
Person `yaml:",inline"`
@@ -38,37 +41,49 @@ type PersonWithID struct {
ID int64 `json:"ID"`
}
-// Base64 encoded, gzipped, json marshaled Swagger object
-var swaggerSpec = []string{
+// PersonWithMorePropertiesOutsideOfAllOf This is a person record as returned from a Create endpoint. It contains
+// all the fields of a Person, with an additional property outside of allOf directives.
+type PersonWithMorePropertiesOutsideOfAllOf struct {
+ // Embedded struct due to allOf(#/components/schemas/Person)
+ Person `yaml:",inline"`
+ // Embedded fields due to inline allOf schema
+ AdditionalProperty string `json:"additionalProperty"`
+}
- "H4sIAAAAAAAC/5SUT2/bOBDFv8qAu0dBTrCLPegWrNtAQJEaaNIc4gAZSyOLKTVkyVEMwfB3L0jJ/+AW",
- "aX0awOTjvDe/0VZVtnOWiSWoYqtC1VKHqVyQD5ZjhcZ8blTxtFV/e2pUof6aHW/Npiuz8fzCW0deNAW1",
- "y7bK0/dee6pV8aQ+ah/kDjtSmfqEU/m8e85UTaHy2omO76n7VgfQARBcksxgo6WFDrlGsX6AJgoBcg0G",
- "gwBjRxmsegGbJNBAOV8y992KfA5JbmN7U8OKwJP0nqmG1QAIL7ckLxBkMAQ3izKHR4KO/JpAWpqeX7I7",
- "eBo7QbbSkocvyTlsWl21YNkM4Lx90zUF2PuGRpOpQ75klSkZHKlC2dUrVaJ2mbqIrNheZEGBAD1NQiAt",
- "CgRHlW6GQ0LRJA3pGBpziCGLGS354L0Pk2+Glw+1PnUOxLWzmiWDTUuegLBq4xD2WqMDd9bqcaDFdm8u",
- "iNe8juZu7Rt57oilnN+lWcRjjfUdiiqUZvnv32MomoXW5OPFAxuXqrtfhviopS3nf0prYvTc1Cjybpu7",
- "7Iztcv47JIOnyvoaMBw5bLztAOF/Tyh0GEMOpUBlWVBzWHKcaiRygsA2gLA4XQ5kwLrWE/6egu19RfDw",
- "UM5/yl7sX3NjU8ZaTPzvnoIEuInxQUosJD2VqTfyYXR0nV/lVzF164jRaVWof/Kr/DqygdKmBGfOYEWt",
- "NfU48jXJJdhf0ei0zgE2yAIoYChus2WCKJVBsCAxwA6/UQSfOmjRuWE0FGeGUaysVaEWJ0/GyQRnOewX",
- "qsHepBZioMSpROeMrpLA7HX6zo1sxOp9cibeUpDnzk7d79LvRwAAAP//lzc18GUFAAA=",
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "zFXNjts2EH6VAdujIG/QogfdgroNBLRZA02aQ7zAjsWRxZQasuTIhmD43QtS8h+8bbq3+DSAOR/n++Ho",
+ "oBrXe8fEElV1ULHpqMdcrihEx6lCax9bVX0+qO8DtapS3y0uXYu5ZTGdXwXnKYihqI7FQQX6ezCBtKo+",
+ "q19NiPIee1KF+g3n8un4VChNsQnGi0n3qQ+diWAiIPgMWcDeSAc9skZxYYQ2AQGyBotRgLGnAjaDgMsQ",
+ "aKFerpmHfkOhhAy3d4PVsCEIJENg0rAZAeH5HckzRBktwdtVXcIngp7ClkA6mq9fsz9zmiZBdtJRgD8y",
+ "c9h3punAsR3BB7czmiKceENryOpYrlkVSkZPqlJu84UaUcdC3UlWHe60oEiAgWYgkA4FoqfGtONZoUSS",
+ "xnwMrT3LUCSN1nzmPsSZN8PzL9pcMwdi7Z1hKWDfUSAgbLpkwglrYuBvRr0YWh1O5KIEw9tE7p3bUeCe",
+ "WOrl++xFOta60KOoShmWn368iGJYaEshNZ6zcY96/FcRPxnp6uVr05ozektqAvnqmMfiJtv18v8kGQI1",
+ "LmjAeMlhG1wPCD8HQqGzDSXUAo1jQcNxzcnVlMg5BK4FhNX140AG1NrM8Q8U3RAago8f6+V/Zi/J9rsL",
+ "dMng4yDRaHps3046vlbQb0aE2dYR3MQoNyQqoE2gRsyO4kupvkDMoowvB/Ha/hd6nu40T02GW5fhjNj0",
+ "3weKEiFLDVnUmHFUoXYU4iTgm/KhfEiWOU+M3qhK/VA+lG/S5ChdHnrhLTbUOaunZ7YluV8mf6I1eYVG",
+ "2CMLoICltEEdEySoAqIDSX71+BelZUM9dOj9OAmVqGECq7Wq1OrqyiRH9I7jaYm1ONg8QvKPOJfovTVN",
+ "Blh8mb8tU3xS9fVwzW88C3nL7Jr9Mf/+CQAA//8=",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -76,7 +91,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -94,12 +109,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -125,3 +140,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/all_of/v2/openapi.gen.go b/internal/test/all_of/v2/openapi.gen.go
index 0facf14460..965051eec5 100644
--- a/internal/test/all_of/v2/openapi.gen.go
+++ b/internal/test/all_of/v2/openapi.gen.go
@@ -1,11 +1,11 @@
// Package v2 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package v2
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/url"
@@ -15,7 +15,9 @@ import (
"github.com/getkin/kin-openapi/openapi3"
)
-// Person defines model for Person.
+// Person This is a person, with mandatory first and last name, but optional ID
+// number. This would be returned by a `Get` style API. We merge the person
+// properties with another Schema which only provides required fields.
type Person struct {
FirstName string `json:"FirstName"`
GovernmentIDNumber *int64 `json:"GovernmentIDNumber,omitempty"`
@@ -30,7 +32,8 @@ type PersonProperties struct {
LastName *string `json:"LastName,omitempty"`
}
-// PersonWithID defines model for PersonWithID.
+// PersonWithID This is a person record as returned from a Create endpoint. It contains
+// all the fields of a Person, with an additional resource UUID.
type PersonWithID struct {
FirstName string `json:"FirstName"`
GovernmentIDNumber *int64 `json:"GovernmentIDNumber,omitempty"`
@@ -38,37 +41,49 @@ type PersonWithID struct {
LastName string `json:"LastName"`
}
-// Base64 encoded, gzipped, json marshaled Swagger object
-var swaggerSpec = []string{
+// PersonWithMorePropertiesOutsideOfAllOf This is a person record as returned from a Create endpoint. It contains
+// all the fields of a Person, with an additional property outside of allOf directives.
+type PersonWithMorePropertiesOutsideOfAllOf struct {
+ FirstName string `json:"FirstName"`
+ GovernmentIDNumber *int64 `json:"GovernmentIDNumber,omitempty"`
+ LastName string `json:"LastName"`
+ AdditionalProperty string `json:"additionalProperty"`
+}
- "H4sIAAAAAAAC/5SUT2/bOBDFv8qAu0dBTrCLPegWrNtAQJEaaNIc4gAZSyOLKTVkyVEMwfB3L0jJ/+AW",
- "aX0awOTjvDe/0VZVtnOWiSWoYqtC1VKHqVyQD5ZjhcZ8blTxtFV/e2pUof6aHW/Npiuz8fzCW0deNAW1",
- "y7bK0/dee6pV8aQ+ah/kDjtSmfqEU/m8e85UTaHy2omO76n7VgfQARBcksxgo6WFDrlGsX6AJgoBcg0G",
- "gwBjRxmsegGbJNBAOV8y992KfA5JbmN7U8OKwJP0nqmG1QAIL7ckLxBkMAQ3izKHR4KO/JpAWpqeX7I7",
- "eBo7QbbSkocvyTlsWl21YNkM4Lx90zUF2PuGRpOpQ75klSkZHKlC2dUrVaJ2mbqIrNheZEGBAD1NQiAt",
- "CgRHlW6GQ0LRJA3pGBpziCGLGS354L0Pk2+Glw+1PnUOxLWzmiWDTUuegLBq4xD2WqMDd9bqcaDFdm8u",
- "iNe8juZu7Rt57oilnN+lWcRjjfUdiiqUZvnv32MomoXW5OPFAxuXqrtfhviopS3nf0prYvTc1Cjybpu7",
- "7Iztcv47JIOnyvoaMBw5bLztAOF/Tyh0GEMOpUBlWVBzWHKcaiRygsA2gLA4XQ5kwLrWE/6egu19RfDw",
- "UM5/yl7sX3NjU8ZaTPzvnoIEuInxQUosJD2VqTfyYXR0nV/lVzF164jRaVWof/Kr/DqygdKmBGfOYEWt",
- "NfU48jXJJdhf0ei0zgE2yAIoYChus2WCKJVBsCAxwA6/UQSfOmjRuWE0FGeGUaysVaEWJ0/GyQRnOewX",
- "qsHepBZioMSpROeMrpLA7HX6zo1sxOp9cibeUpDnzk7d79LvRwAAAP//lzc18GUFAAA=",
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "zFXNjts2EH6VAdujIG/QogfdgroNBLRZA02aQ7zAjsWRxZQasuTIhmD43QtS8h+8bbq3+DSAOR/n++Ho",
+ "oBrXe8fEElV1ULHpqMdcrihEx6lCax9bVX0+qO8DtapS3y0uXYu5ZTGdXwXnKYihqI7FQQX6ezCBtKo+",
+ "q19NiPIee1KF+g3n8un4VChNsQnGi0n3qQ+diWAiIPgMWcDeSAc9skZxYYQ2AQGyBotRgLGnAjaDgMsQ",
+ "aKFerpmHfkOhhAy3d4PVsCEIJENg0rAZAeH5HckzRBktwdtVXcIngp7ClkA6mq9fsz9zmiZBdtJRgD8y",
+ "c9h3punAsR3BB7czmiKceENryOpYrlkVSkZPqlJu84UaUcdC3UlWHe60oEiAgWYgkA4FoqfGtONZoUSS",
+ "xnwMrT3LUCSN1nzmPsSZN8PzL9pcMwdi7Z1hKWDfUSAgbLpkwglrYuBvRr0YWh1O5KIEw9tE7p3bUeCe",
+ "WOrl++xFOta60KOoShmWn368iGJYaEshNZ6zcY96/FcRPxnp6uVr05ozektqAvnqmMfiJtv18v8kGQI1",
+ "LmjAeMlhG1wPCD8HQqGzDSXUAo1jQcNxzcnVlMg5BK4FhNX140AG1NrM8Q8U3RAago8f6+V/Zi/J9rsL",
+ "dMng4yDRaHps3046vlbQb0aE2dYR3MQoNyQqoE2gRsyO4kupvkDMoowvB/Ha/hd6nu40T02GW5fhjNj0",
+ "3weKEiFLDVnUmHFUoXYU4iTgm/KhfEiWOU+M3qhK/VA+lG/S5ChdHnrhLTbUOaunZ7YluV8mf6I1eYVG",
+ "2CMLoICltEEdEySoAqIDSX71+BelZUM9dOj9OAmVqGECq7Wq1OrqyiRH9I7jaYm1ONg8QvKPOJfovTVN",
+ "Blh8mb8tU3xS9fVwzW88C3nL7Jr9Mf/+CQAA//8=",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -76,7 +91,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -94,12 +109,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -125,3 +140,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/anonymous_inner_hoisting/cfg.yaml b/internal/test/anonymous_inner_hoisting/cfg.yaml
new file mode 100644
index 0000000000..bbdee926a3
--- /dev/null
+++ b/internal/test/anonymous_inner_hoisting/cfg.yaml
@@ -0,0 +1,5 @@
+package: anonymous_inner_hoisting
+output: client.gen.go
+generate:
+ models: true
+ client: true
diff --git a/internal/test/anonymous_inner_hoisting/client.gen.go b/internal/test/anonymous_inner_hoisting/client.gen.go
new file mode 100644
index 0000000000..f022093572
--- /dev/null
+++ b/internal/test/anonymous_inner_hoisting/client.gen.go
@@ -0,0 +1,1376 @@
+// Package anonymous_inner_hoisting provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package anonymous_inner_hoisting
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// Defines values for CatKind.
+const (
+ CatKindCat CatKind = "cat"
+)
+
+// Valid indicates whether the value is a known member of the CatKind enum.
+func (e CatKind) Valid() bool {
+ switch e {
+ case CatKindCat:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for DogKind.
+const (
+ DogKindDog DogKind = "dog"
+)
+
+// Valid indicates whether the value is a known member of the DogKind enum.
+func (e DogKind) Valid() bool {
+ switch e {
+ case DogKindDog:
+ return true
+ default:
+ return false
+ }
+}
+
+// Cat defines model for Cat.
+type Cat struct {
+ Kind CatKind `json:"kind"`
+ Name *string `json:"name,omitempty"`
+}
+
+// CatKind defines model for Cat.Kind.
+type CatKind string
+
+// Dog defines model for Dog.
+type Dog struct {
+ Kind DogKind `json:"kind"`
+ Name *string `json:"name,omitempty"`
+}
+
+// DogKind defines model for Dog.Kind.
+type DogKind string
+
+// PostBodyPropertyOneOfJSONBody defines parameters for PostBodyPropertyOneOf.
+type PostBodyPropertyOneOfJSONBody struct {
+ Pet *PostBodyPropertyOneOfJSONBody_Pet `json:"pet,omitempty"`
+}
+
+// PostBodyPropertyOneOfJSONBody_Pet defines parameters for PostBodyPropertyOneOf.
+type PostBodyPropertyOneOfJSONBody_Pet struct {
+ union json.RawMessage
+}
+
+// PostBodyRootOneOfJSONBody defines parameters for PostBodyRootOneOf.
+type PostBodyRootOneOfJSONBody struct {
+ union json.RawMessage
+}
+
+// GetResponseDeepNested200JSONResponseBody_Wrapper_Inner defines parameters for GetResponseDeepNested.
+type GetResponseDeepNested200JSONResponseBody_Wrapper_Inner struct {
+ union json.RawMessage
+}
+
+// GetResponseItemsOneOf200JSONResponseBody_Items_Item defines parameters for GetResponseItemsOneOf.
+type GetResponseItemsOneOf200JSONResponseBody_Items_Item struct {
+ union json.RawMessage
+}
+
+// GetResponseRootAnyOf200JSONResponseBody defines parameters for GetResponseRootAnyOf.
+type GetResponseRootAnyOf200JSONResponseBody struct {
+ union json.RawMessage
+}
+
+// GetResponseRootOneOf200JSONResponseBody defines parameters for GetResponseRootOneOf.
+type GetResponseRootOneOf200JSONResponseBody struct {
+ union json.RawMessage
+}
+
+// PostBodyPropertyOneOfJSONRequestBody defines body for PostBodyPropertyOneOf for application/json ContentType.
+type PostBodyPropertyOneOfJSONRequestBody PostBodyPropertyOneOfJSONBody
+
+// PostBodyRootOneOfJSONRequestBody defines body for PostBodyRootOneOf for application/json ContentType.
+type PostBodyRootOneOfJSONRequestBody PostBodyRootOneOfJSONBody
+
+// AsCat returns the union data inside the PostBodyPropertyOneOfJSONBody_Pet as a Cat
+func (t PostBodyPropertyOneOfJSONBody_Pet) AsCat() (Cat, error) {
+ var body Cat
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromCat overwrites any union data inside the PostBodyPropertyOneOfJSONBody_Pet as the provided Cat
+func (t *PostBodyPropertyOneOfJSONBody_Pet) FromCat(v Cat) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeCat performs a merge with any union data inside the PostBodyPropertyOneOfJSONBody_Pet, using the provided Cat
+func (t *PostBodyPropertyOneOfJSONBody_Pet) MergeCat(v Cat) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsDog returns the union data inside the PostBodyPropertyOneOfJSONBody_Pet as a Dog
+func (t PostBodyPropertyOneOfJSONBody_Pet) AsDog() (Dog, error) {
+ var body Dog
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromDog overwrites any union data inside the PostBodyPropertyOneOfJSONBody_Pet as the provided Dog
+func (t *PostBodyPropertyOneOfJSONBody_Pet) FromDog(v Dog) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeDog performs a merge with any union data inside the PostBodyPropertyOneOfJSONBody_Pet, using the provided Dog
+func (t *PostBodyPropertyOneOfJSONBody_Pet) MergeDog(v Dog) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t PostBodyPropertyOneOfJSONBody_Pet) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *PostBodyPropertyOneOfJSONBody_Pet) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// AsCat returns the union data inside the PostBodyRootOneOfJSONBody as a Cat
+func (t PostBodyRootOneOfJSONBody) AsCat() (Cat, error) {
+ var body Cat
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromCat overwrites any union data inside the PostBodyRootOneOfJSONBody as the provided Cat
+func (t *PostBodyRootOneOfJSONBody) FromCat(v Cat) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeCat performs a merge with any union data inside the PostBodyRootOneOfJSONBody, using the provided Cat
+func (t *PostBodyRootOneOfJSONBody) MergeCat(v Cat) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsDog returns the union data inside the PostBodyRootOneOfJSONBody as a Dog
+func (t PostBodyRootOneOfJSONBody) AsDog() (Dog, error) {
+ var body Dog
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromDog overwrites any union data inside the PostBodyRootOneOfJSONBody as the provided Dog
+func (t *PostBodyRootOneOfJSONBody) FromDog(v Dog) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeDog performs a merge with any union data inside the PostBodyRootOneOfJSONBody, using the provided Dog
+func (t *PostBodyRootOneOfJSONBody) MergeDog(v Dog) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t PostBodyRootOneOfJSONBody) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *PostBodyRootOneOfJSONBody) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// AsCat returns the union data inside the GetResponseDeepNested200JSONResponseBody_Wrapper_Inner as a Cat
+func (t GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) AsCat() (Cat, error) {
+ var body Cat
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromCat overwrites any union data inside the GetResponseDeepNested200JSONResponseBody_Wrapper_Inner as the provided Cat
+func (t *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) FromCat(v Cat) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeCat performs a merge with any union data inside the GetResponseDeepNested200JSONResponseBody_Wrapper_Inner, using the provided Cat
+func (t *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) MergeCat(v Cat) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsDog returns the union data inside the GetResponseDeepNested200JSONResponseBody_Wrapper_Inner as a Dog
+func (t GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) AsDog() (Dog, error) {
+ var body Dog
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromDog overwrites any union data inside the GetResponseDeepNested200JSONResponseBody_Wrapper_Inner as the provided Dog
+func (t *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) FromDog(v Dog) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeDog performs a merge with any union data inside the GetResponseDeepNested200JSONResponseBody_Wrapper_Inner, using the provided Dog
+func (t *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) MergeDog(v Dog) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// AsCat returns the union data inside the GetResponseItemsOneOf200JSONResponseBody_Items_Item as a Cat
+func (t GetResponseItemsOneOf200JSONResponseBody_Items_Item) AsCat() (Cat, error) {
+ var body Cat
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromCat overwrites any union data inside the GetResponseItemsOneOf200JSONResponseBody_Items_Item as the provided Cat
+func (t *GetResponseItemsOneOf200JSONResponseBody_Items_Item) FromCat(v Cat) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeCat performs a merge with any union data inside the GetResponseItemsOneOf200JSONResponseBody_Items_Item, using the provided Cat
+func (t *GetResponseItemsOneOf200JSONResponseBody_Items_Item) MergeCat(v Cat) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsDog returns the union data inside the GetResponseItemsOneOf200JSONResponseBody_Items_Item as a Dog
+func (t GetResponseItemsOneOf200JSONResponseBody_Items_Item) AsDog() (Dog, error) {
+ var body Dog
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromDog overwrites any union data inside the GetResponseItemsOneOf200JSONResponseBody_Items_Item as the provided Dog
+func (t *GetResponseItemsOneOf200JSONResponseBody_Items_Item) FromDog(v Dog) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeDog performs a merge with any union data inside the GetResponseItemsOneOf200JSONResponseBody_Items_Item, using the provided Dog
+func (t *GetResponseItemsOneOf200JSONResponseBody_Items_Item) MergeDog(v Dog) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t GetResponseItemsOneOf200JSONResponseBody_Items_Item) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *GetResponseItemsOneOf200JSONResponseBody_Items_Item) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// AsCat returns the union data inside the GetResponseRootAnyOf200JSONResponseBody as a Cat
+func (t GetResponseRootAnyOf200JSONResponseBody) AsCat() (Cat, error) {
+ var body Cat
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromCat overwrites any union data inside the GetResponseRootAnyOf200JSONResponseBody as the provided Cat
+func (t *GetResponseRootAnyOf200JSONResponseBody) FromCat(v Cat) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeCat performs a merge with any union data inside the GetResponseRootAnyOf200JSONResponseBody, using the provided Cat
+func (t *GetResponseRootAnyOf200JSONResponseBody) MergeCat(v Cat) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsDog returns the union data inside the GetResponseRootAnyOf200JSONResponseBody as a Dog
+func (t GetResponseRootAnyOf200JSONResponseBody) AsDog() (Dog, error) {
+ var body Dog
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromDog overwrites any union data inside the GetResponseRootAnyOf200JSONResponseBody as the provided Dog
+func (t *GetResponseRootAnyOf200JSONResponseBody) FromDog(v Dog) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeDog performs a merge with any union data inside the GetResponseRootAnyOf200JSONResponseBody, using the provided Dog
+func (t *GetResponseRootAnyOf200JSONResponseBody) MergeDog(v Dog) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t GetResponseRootAnyOf200JSONResponseBody) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *GetResponseRootAnyOf200JSONResponseBody) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// AsCat returns the union data inside the GetResponseRootOneOf200JSONResponseBody as a Cat
+func (t GetResponseRootOneOf200JSONResponseBody) AsCat() (Cat, error) {
+ var body Cat
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromCat overwrites any union data inside the GetResponseRootOneOf200JSONResponseBody as the provided Cat
+func (t *GetResponseRootOneOf200JSONResponseBody) FromCat(v Cat) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeCat performs a merge with any union data inside the GetResponseRootOneOf200JSONResponseBody, using the provided Cat
+func (t *GetResponseRootOneOf200JSONResponseBody) MergeCat(v Cat) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsDog returns the union data inside the GetResponseRootOneOf200JSONResponseBody as a Dog
+func (t GetResponseRootOneOf200JSONResponseBody) AsDog() (Dog, error) {
+ var body Dog
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromDog overwrites any union data inside the GetResponseRootOneOf200JSONResponseBody as the provided Dog
+func (t *GetResponseRootOneOf200JSONResponseBody) FromDog(v Dog) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeDog performs a merge with any union data inside the GetResponseRootOneOf200JSONResponseBody, using the provided Dog
+func (t *GetResponseRootOneOf200JSONResponseBody) MergeDog(v Dog) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t GetResponseRootOneOf200JSONResponseBody) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *GetResponseRootOneOf200JSONResponseBody) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // PostBodyPropertyOneOfWithBody request with any body
+ PostBodyPropertyOneOfWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PostBodyPropertyOneOf(ctx context.Context, body PostBodyPropertyOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // PostBodyRootOneOfWithBody request with any body
+ PostBodyRootOneOfWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PostBodyRootOneOf(ctx context.Context, body PostBodyRootOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // GetResponseDeepNested request
+ GetResponseDeepNested(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // GetResponseItemsOneOf request
+ GetResponseItemsOneOf(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // GetResponseRootAnyOf request
+ GetResponseRootAnyOf(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // GetResponseRootOneOf request
+ GetResponseRootOneOf(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) PostBodyPropertyOneOfWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostBodyPropertyOneOfRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostBodyPropertyOneOf(ctx context.Context, body PostBodyPropertyOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostBodyPropertyOneOfRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostBodyRootOneOfWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostBodyRootOneOfRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostBodyRootOneOf(ctx context.Context, body PostBodyRootOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostBodyRootOneOfRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) GetResponseDeepNested(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetResponseDeepNestedRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) GetResponseItemsOneOf(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetResponseItemsOneOfRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) GetResponseRootAnyOf(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetResponseRootAnyOfRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) GetResponseRootOneOf(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetResponseRootOneOfRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewPostBodyPropertyOneOfRequest calls the generic PostBodyPropertyOneOf builder with application/json body
+func NewPostBodyPropertyOneOfRequest(server string, body PostBodyPropertyOneOfJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPostBodyPropertyOneOfRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewPostBodyPropertyOneOfRequestWithBody generates requests for PostBodyPropertyOneOf with any type of body
+func NewPostBodyPropertyOneOfRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/body-property-oneof")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewPostBodyRootOneOfRequest calls the generic PostBodyRootOneOf builder with application/json body
+func NewPostBodyRootOneOfRequest(server string, body PostBodyRootOneOfJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPostBodyRootOneOfRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewPostBodyRootOneOfRequestWithBody generates requests for PostBodyRootOneOf with any type of body
+func NewPostBodyRootOneOfRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/body-root-oneof")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewGetResponseDeepNestedRequest generates requests for GetResponseDeepNested
+func NewGetResponseDeepNestedRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/response-deep-nested")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewGetResponseItemsOneOfRequest generates requests for GetResponseItemsOneOf
+func NewGetResponseItemsOneOfRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/response-items-oneof")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewGetResponseRootAnyOfRequest generates requests for GetResponseRootAnyOf
+func NewGetResponseRootAnyOfRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/response-root-anyof")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewGetResponseRootOneOfRequest generates requests for GetResponseRootOneOf
+func NewGetResponseRootOneOfRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/response-root-oneof")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // PostBodyPropertyOneOfWithBodyWithResponse request with any body
+ PostBodyPropertyOneOfWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostBodyPropertyOneOfResponse, error)
+
+ PostBodyPropertyOneOfWithResponse(ctx context.Context, body PostBodyPropertyOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*PostBodyPropertyOneOfResponse, error)
+
+ // PostBodyRootOneOfWithBodyWithResponse request with any body
+ PostBodyRootOneOfWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostBodyRootOneOfResponse, error)
+
+ PostBodyRootOneOfWithResponse(ctx context.Context, body PostBodyRootOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*PostBodyRootOneOfResponse, error)
+
+ // GetResponseDeepNestedWithResponse request
+ GetResponseDeepNestedWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseDeepNestedResponse, error)
+
+ // GetResponseItemsOneOfWithResponse request
+ GetResponseItemsOneOfWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseItemsOneOfResponse, error)
+
+ // GetResponseRootAnyOfWithResponse request
+ GetResponseRootAnyOfWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseRootAnyOfResponse, error)
+
+ // GetResponseRootOneOfWithResponse request
+ GetResponseRootOneOfWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseRootOneOfResponse, error)
+}
+
+type PostBodyPropertyOneOfResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r PostBodyPropertyOneOfResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r PostBodyPropertyOneOfResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PostBodyPropertyOneOfResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostBodyPropertyOneOfResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type PostBodyRootOneOfResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r PostBodyRootOneOfResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r PostBodyRootOneOfResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PostBodyRootOneOfResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostBodyRootOneOfResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetResponseDeepNestedResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *struct {
+ Wrapper *struct {
+ Inner *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner `json:"inner,omitempty"`
+ } `json:"wrapper,omitempty"`
+ }
+}
+
+// GetJSON200 returns JSON200
+func (r GetResponseDeepNestedResponse) GetJSON200() *struct {
+ Wrapper *struct {
+ Inner *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner `json:"inner,omitempty"`
+ } `json:"wrapper,omitempty"`
+} {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetResponseDeepNestedResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetResponseDeepNestedResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetResponseDeepNestedResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetResponseDeepNestedResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetResponseItemsOneOfResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *struct {
+ Items []GetResponseItemsOneOf200JSONResponseBody_Items_Item `json:"items"`
+ }
+}
+
+// GetJSON200 returns JSON200
+func (r GetResponseItemsOneOfResponse) GetJSON200() *struct {
+ Items []GetResponseItemsOneOf200JSONResponseBody_Items_Item `json:"items"`
+} {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetResponseItemsOneOfResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetResponseItemsOneOfResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetResponseItemsOneOfResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetResponseItemsOneOfResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetResponseRootAnyOfResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *GetResponseRootAnyOf200JSONResponseBody
+}
+
+// GetJSON200 returns JSON200
+func (r GetResponseRootAnyOfResponse) GetJSON200() *GetResponseRootAnyOf200JSONResponseBody {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetResponseRootAnyOfResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetResponseRootAnyOfResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetResponseRootAnyOfResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetResponseRootAnyOfResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetResponseRootOneOfResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *GetResponseRootOneOf200JSONResponseBody
+}
+
+// GetJSON200 returns JSON200
+func (r GetResponseRootOneOfResponse) GetJSON200() *GetResponseRootOneOf200JSONResponseBody {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetResponseRootOneOfResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetResponseRootOneOfResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetResponseRootOneOfResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetResponseRootOneOfResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// PostBodyPropertyOneOfWithBodyWithResponse request with arbitrary body returning *PostBodyPropertyOneOfResponse
+func (c *ClientWithResponses) PostBodyPropertyOneOfWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostBodyPropertyOneOfResponse, error) {
+ rsp, err := c.PostBodyPropertyOneOfWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostBodyPropertyOneOfResponse(rsp)
+}
+
+func (c *ClientWithResponses) PostBodyPropertyOneOfWithResponse(ctx context.Context, body PostBodyPropertyOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*PostBodyPropertyOneOfResponse, error) {
+ rsp, err := c.PostBodyPropertyOneOf(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostBodyPropertyOneOfResponse(rsp)
+}
+
+// PostBodyRootOneOfWithBodyWithResponse request with arbitrary body returning *PostBodyRootOneOfResponse
+func (c *ClientWithResponses) PostBodyRootOneOfWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostBodyRootOneOfResponse, error) {
+ rsp, err := c.PostBodyRootOneOfWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostBodyRootOneOfResponse(rsp)
+}
+
+func (c *ClientWithResponses) PostBodyRootOneOfWithResponse(ctx context.Context, body PostBodyRootOneOfJSONRequestBody, reqEditors ...RequestEditorFn) (*PostBodyRootOneOfResponse, error) {
+ rsp, err := c.PostBodyRootOneOf(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostBodyRootOneOfResponse(rsp)
+}
+
+// GetResponseDeepNestedWithResponse request returning *GetResponseDeepNestedResponse
+func (c *ClientWithResponses) GetResponseDeepNestedWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseDeepNestedResponse, error) {
+ rsp, err := c.GetResponseDeepNested(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetResponseDeepNestedResponse(rsp)
+}
+
+// GetResponseItemsOneOfWithResponse request returning *GetResponseItemsOneOfResponse
+func (c *ClientWithResponses) GetResponseItemsOneOfWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseItemsOneOfResponse, error) {
+ rsp, err := c.GetResponseItemsOneOf(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetResponseItemsOneOfResponse(rsp)
+}
+
+// GetResponseRootAnyOfWithResponse request returning *GetResponseRootAnyOfResponse
+func (c *ClientWithResponses) GetResponseRootAnyOfWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseRootAnyOfResponse, error) {
+ rsp, err := c.GetResponseRootAnyOf(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetResponseRootAnyOfResponse(rsp)
+}
+
+// GetResponseRootOneOfWithResponse request returning *GetResponseRootOneOfResponse
+func (c *ClientWithResponses) GetResponseRootOneOfWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetResponseRootOneOfResponse, error) {
+ rsp, err := c.GetResponseRootOneOf(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetResponseRootOneOfResponse(rsp)
+}
+
+// ParsePostBodyPropertyOneOfResponse parses an HTTP response from a PostBodyPropertyOneOfWithResponse call
+func ParsePostBodyPropertyOneOfResponse(rsp *http.Response) (*PostBodyPropertyOneOfResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &PostBodyPropertyOneOfResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
+// ParsePostBodyRootOneOfResponse parses an HTTP response from a PostBodyRootOneOfWithResponse call
+func ParsePostBodyRootOneOfResponse(rsp *http.Response) (*PostBodyRootOneOfResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &PostBodyRootOneOfResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
+// ParseGetResponseDeepNestedResponse parses an HTTP response from a GetResponseDeepNestedWithResponse call
+func ParseGetResponseDeepNestedResponse(rsp *http.Response) (*GetResponseDeepNestedResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetResponseDeepNestedResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest struct {
+ Wrapper *struct {
+ Inner *GetResponseDeepNested200JSONResponseBody_Wrapper_Inner `json:"inner,omitempty"`
+ } `json:"wrapper,omitempty"`
+ }
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseGetResponseItemsOneOfResponse parses an HTTP response from a GetResponseItemsOneOfWithResponse call
+func ParseGetResponseItemsOneOfResponse(rsp *http.Response) (*GetResponseItemsOneOfResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetResponseItemsOneOfResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest struct {
+ Items []GetResponseItemsOneOf200JSONResponseBody_Items_Item `json:"items"`
+ }
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseGetResponseRootAnyOfResponse parses an HTTP response from a GetResponseRootAnyOfWithResponse call
+func ParseGetResponseRootAnyOfResponse(rsp *http.Response) (*GetResponseRootAnyOfResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetResponseRootAnyOfResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest GetResponseRootAnyOf200JSONResponseBody
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseGetResponseRootOneOfResponse parses an HTTP response from a GetResponseRootOneOfWithResponse call
+func ParseGetResponseRootOneOfResponse(rsp *http.Response) (*GetResponseRootOneOfResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetResponseRootOneOfResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest GetResponseRootOneOf200JSONResponseBody
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
diff --git a/internal/test/anonymous_inner_hoisting/client_test.go b/internal/test/anonymous_inner_hoisting/client_test.go
new file mode 100644
index 0000000000..abdf532440
--- /dev/null
+++ b/internal/test/anonymous_inner_hoisting/client_test.go
@@ -0,0 +1,141 @@
+package anonymous_inner_hoisting
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func ptr[T any](v T) *T { return &v }
+
+func TestResponseRootOneOf_RoundTripCat(t *testing.T) {
+ cat := Cat{Kind: CatKindCat, Name: ptr("whiskers")}
+
+ var u GetResponseRootOneOf200JSONResponseBody
+ require.NoError(t, u.FromCat(cat))
+
+ b, err := json.Marshal(u)
+ require.NoError(t, err)
+
+ var decoded GetResponseRootOneOf200JSONResponseBody
+ require.NoError(t, json.Unmarshal(b, &decoded))
+
+ got, err := decoded.AsCat()
+ require.NoError(t, err)
+ require.Equal(t, cat, got)
+}
+
+func TestResponseRootAnyOf_RoundTripDog(t *testing.T) {
+ dog := Dog{Kind: DogKindDog, Name: ptr("rex")}
+
+ var u GetResponseRootAnyOf200JSONResponseBody
+ require.NoError(t, u.FromDog(dog))
+
+ b, err := json.Marshal(u)
+ require.NoError(t, err)
+
+ var decoded GetResponseRootAnyOf200JSONResponseBody
+ require.NoError(t, json.Unmarshal(b, &decoded))
+
+ got, err := decoded.AsDog()
+ require.NoError(t, err)
+ require.Equal(t, dog, got)
+}
+
+func TestResponseItemsOneOf_RoundTripBothBranches(t *testing.T) {
+ cat := Cat{Kind: CatKindCat, Name: ptr("whiskers")}
+ dog := Dog{Kind: DogKindDog, Name: ptr("rex")}
+
+ var catItem GetResponseItemsOneOf200JSONResponseBody_Items_Item
+ require.NoError(t, catItem.FromCat(cat))
+ var dogItem GetResponseItemsOneOf200JSONResponseBody_Items_Item
+ require.NoError(t, dogItem.FromDog(dog))
+
+ bCat, err := json.Marshal(catItem)
+ require.NoError(t, err)
+ bDog, err := json.Marshal(dogItem)
+ require.NoError(t, err)
+
+ var decodedCat, decodedDog GetResponseItemsOneOf200JSONResponseBody_Items_Item
+ require.NoError(t, json.Unmarshal(bCat, &decodedCat))
+ require.NoError(t, json.Unmarshal(bDog, &decodedDog))
+
+ gotCat, err := decodedCat.AsCat()
+ require.NoError(t, err)
+ require.Equal(t, cat, gotCat)
+
+ gotDog, err := decodedDog.AsDog()
+ require.NoError(t, err)
+ require.Equal(t, dog, gotDog)
+}
+
+func TestResponseDeepNested_RoundTrip(t *testing.T) {
+ cat := Cat{Kind: CatKindCat, Name: ptr("whiskers")}
+
+ var inner GetResponseDeepNested200JSONResponseBody_Wrapper_Inner
+ require.NoError(t, inner.FromCat(cat))
+
+ b, err := json.Marshal(inner)
+ require.NoError(t, err)
+
+ var decoded GetResponseDeepNested200JSONResponseBody_Wrapper_Inner
+ require.NoError(t, json.Unmarshal(b, &decoded))
+
+ got, err := decoded.AsCat()
+ require.NoError(t, err)
+ require.Equal(t, cat, got)
+}
+
+func TestBodyRootOneOf_RoundTripCat(t *testing.T) {
+ cat := Cat{Kind: CatKindCat, Name: ptr("whiskers")}
+
+ var body PostBodyRootOneOfJSONBody
+ require.NoError(t, body.FromCat(cat))
+
+ b, err := json.Marshal(body)
+ require.NoError(t, err)
+
+ var decoded PostBodyRootOneOfJSONBody
+ require.NoError(t, json.Unmarshal(b, &decoded))
+
+ got, err := decoded.AsCat()
+ require.NoError(t, err)
+ require.Equal(t, cat, got)
+}
+
+func TestBodyPropertyOneOf_RoundTripDog(t *testing.T) {
+ dog := Dog{Kind: DogKindDog, Name: ptr("rex")}
+
+ var pet PostBodyPropertyOneOfJSONBody_Pet
+ require.NoError(t, pet.FromDog(dog))
+
+ b, err := json.Marshal(pet)
+ require.NoError(t, err)
+
+ var decoded PostBodyPropertyOneOfJSONBody_Pet
+ require.NoError(t, json.Unmarshal(b, &decoded))
+
+ got, err := decoded.AsDog()
+ require.NoError(t, err)
+ require.Equal(t, dog, got)
+}
+
+func TestMergeOverwritesPriorBranch(t *testing.T) {
+ cat := Cat{Kind: CatKindCat, Name: ptr("whiskers")}
+ dog := Dog{Kind: DogKindDog, Name: ptr("rex")}
+
+ var u GetResponseRootOneOf200JSONResponseBody
+ require.NoError(t, u.FromCat(cat))
+ require.NoError(t, u.MergeDog(dog))
+
+ b, err := json.Marshal(u)
+ require.NoError(t, err)
+
+ var decoded GetResponseRootOneOf200JSONResponseBody
+ require.NoError(t, json.Unmarshal(b, &decoded))
+
+ gotDog, err := decoded.AsDog()
+ require.NoError(t, err)
+ require.Equal(t, dog, gotDog)
+}
diff --git a/internal/test/anonymous_inner_hoisting/generate.go b/internal/test/anonymous_inner_hoisting/generate.go
new file mode 100644
index 0000000000..19ff037202
--- /dev/null
+++ b/internal/test/anonymous_inner_hoisting/generate.go
@@ -0,0 +1,3 @@
+package anonymous_inner_hoisting
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=cfg.yaml spec.yaml
diff --git a/internal/test/anonymous_inner_hoisting/spec.yaml b/internal/test/anonymous_inner_hoisting/spec.yaml
new file mode 100644
index 0000000000..a6febff103
--- /dev/null
+++ b/internal/test/anonymous_inner_hoisting/spec.yaml
@@ -0,0 +1,132 @@
+openapi: 3.0.3
+info:
+ version: 1.0.0
+ title: Anonymous Inner Hoisting
+ description: |
+ Exercises inline oneOf / anyOf schemas at every operation root and at
+ nested positions. Each generated wrapper type should receive
+ As() / From() / Merge() accessor methods.
+paths:
+
+ /response-root-oneof:
+ get:
+ operationId: getResponseRootOneOf
+ responses:
+ '200':
+ description: inline oneOf as the response body root
+ content:
+ application/json:
+ schema:
+ oneOf:
+ - $ref: '#/components/schemas/Cat'
+ - $ref: '#/components/schemas/Dog'
+
+ /response-root-anyof:
+ get:
+ operationId: getResponseRootAnyOf
+ responses:
+ '200':
+ description: inline anyOf as the response body root
+ content:
+ application/json:
+ schema:
+ anyOf:
+ - $ref: '#/components/schemas/Cat'
+ - $ref: '#/components/schemas/Dog'
+
+ /response-items-oneof:
+ get:
+ operationId: getResponseItemsOneOf
+ responses:
+ '200':
+ description: inline oneOf as items of an array property
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - items
+ properties:
+ items:
+ type: array
+ items:
+ oneOf:
+ - $ref: '#/components/schemas/Cat'
+ - $ref: '#/components/schemas/Dog'
+
+ /response-deep-nested:
+ get:
+ operationId: getResponseDeepNested
+ responses:
+ '200':
+ description: inline oneOf nested inside a property of a property
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ wrapper:
+ type: object
+ properties:
+ inner:
+ oneOf:
+ - $ref: '#/components/schemas/Cat'
+ - $ref: '#/components/schemas/Dog'
+
+ /body-root-oneof:
+ post:
+ operationId: postBodyRootOneOf
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ oneOf:
+ - $ref: '#/components/schemas/Cat'
+ - $ref: '#/components/schemas/Dog'
+ responses:
+ '200':
+ description: ok
+
+ /body-property-oneof:
+ post:
+ operationId: postBodyPropertyOneOf
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ pet:
+ oneOf:
+ - $ref: '#/components/schemas/Cat'
+ - $ref: '#/components/schemas/Dog'
+ responses:
+ '200':
+ description: ok
+
+components:
+ schemas:
+ Cat:
+ type: object
+ required:
+ - kind
+ properties:
+ kind:
+ type: string
+ enum:
+ - cat
+ name:
+ type: string
+ Dog:
+ type: object
+ required:
+ - kind
+ properties:
+ kind:
+ type: string
+ enum:
+ - dog
+ name:
+ type: string
diff --git a/internal/test/any_of/codegen/inline/config.yaml b/internal/test/any_of/codegen/inline/config.yaml
new file mode 100644
index 0000000000..9066c3fa38
--- /dev/null
+++ b/internal/test/any_of/codegen/inline/config.yaml
@@ -0,0 +1,6 @@
+package: inline
+generate:
+ models: true
+ client: true
+ echo-server: true
+output: openapi.gen.go
diff --git a/internal/test/any_of/codegen/inline/generate.go b/internal/test/any_of/codegen/inline/generate.go
new file mode 100644
index 0000000000..020b7dc9d8
--- /dev/null
+++ b/internal/test/any_of/codegen/inline/generate.go
@@ -0,0 +1,3 @@
+package inline
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/any_of/codegen/inline/openapi.gen.go b/internal/test/any_of/codegen/inline/openapi.gen.go
new file mode 100644
index 0000000000..e1bb5cfbd7
--- /dev/null
+++ b/internal/test/any_of/codegen/inline/openapi.gen.go
@@ -0,0 +1,461 @@
+// Package inline provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package inline
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/labstack/echo/v4"
+ "github.com/oapi-codegen/runtime"
+)
+
+const (
+ ApiKeyAuthScopes apiKeyAuthContextKey = "ApiKeyAuth.Scopes"
+)
+
+// Cat This is a cat
+type Cat struct {
+ Breed *string `json:"breed,omitempty"`
+ Color *string `json:"color,omitempty"`
+ Id *string `json:"id,omitempty"`
+ Name *string `json:"name,omitempty"`
+ Purrs *bool `json:"purrs,omitempty"`
+}
+
+// Dog This is a dog
+type Dog struct {
+ Barks *bool `json:"barks,omitempty"`
+ Breed *string `json:"breed,omitempty"`
+ Color *string `json:"color,omitempty"`
+ Id *string `json:"id,omitempty"`
+ Name *string `json:"name,omitempty"`
+}
+
+// Rat This is a rat
+type Rat struct {
+ Color *string `json:"color,omitempty"`
+ Id *string `json:"id,omitempty"`
+ Name *string `json:"name,omitempty"`
+ Squeaks *bool `json:"squeaks,omitempty"`
+}
+
+// apiKeyAuthContextKey is the context key for ApiKeyAuth security scheme
+type apiKeyAuthContextKey string
+
+// GetPets200JSONResponseBody_Data_Item defines parameters for GetPets.
+type GetPets200JSONResponseBody_Data_Item struct {
+ union json.RawMessage
+}
+
+// AsCat returns the union data inside the GetPets200JSONResponseBody_Data_Item as a Cat
+func (t GetPets200JSONResponseBody_Data_Item) AsCat() (Cat, error) {
+ var body Cat
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromCat overwrites any union data inside the GetPets200JSONResponseBody_Data_Item as the provided Cat
+func (t *GetPets200JSONResponseBody_Data_Item) FromCat(v Cat) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeCat performs a merge with any union data inside the GetPets200JSONResponseBody_Data_Item, using the provided Cat
+func (t *GetPets200JSONResponseBody_Data_Item) MergeCat(v Cat) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsDog returns the union data inside the GetPets200JSONResponseBody_Data_Item as a Dog
+func (t GetPets200JSONResponseBody_Data_Item) AsDog() (Dog, error) {
+ var body Dog
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromDog overwrites any union data inside the GetPets200JSONResponseBody_Data_Item as the provided Dog
+func (t *GetPets200JSONResponseBody_Data_Item) FromDog(v Dog) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeDog performs a merge with any union data inside the GetPets200JSONResponseBody_Data_Item, using the provided Dog
+func (t *GetPets200JSONResponseBody_Data_Item) MergeDog(v Dog) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsRat returns the union data inside the GetPets200JSONResponseBody_Data_Item as a Rat
+func (t GetPets200JSONResponseBody_Data_Item) AsRat() (Rat, error) {
+ var body Rat
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromRat overwrites any union data inside the GetPets200JSONResponseBody_Data_Item as the provided Rat
+func (t *GetPets200JSONResponseBody_Data_Item) FromRat(v Rat) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeRat performs a merge with any union data inside the GetPets200JSONResponseBody_Data_Item, using the provided Rat
+func (t *GetPets200JSONResponseBody_Data_Item) MergeRat(v Rat) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t GetPets200JSONResponseBody_Data_Item) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *GetPets200JSONResponseBody_Data_Item) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetPets request
+ GetPets(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetPets(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetPetsRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetPetsRequest generates requests for GetPets
+func NewGetPetsRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/pets")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetPetsWithResponse request
+ GetPetsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetPetsResponse, error)
+}
+
+type GetPetsResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *struct {
+ Data *[]GetPets200JSONResponseBody_Data_Item `json:"data,omitempty"`
+ }
+}
+
+// GetJSON200 returns JSON200
+func (r GetPetsResponse) GetJSON200() *struct {
+ Data *[]GetPets200JSONResponseBody_Data_Item `json:"data,omitempty"`
+} {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetPetsResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetPetsResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetPetsResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetPetsResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetPetsWithResponse request returning *GetPetsResponse
+func (c *ClientWithResponses) GetPetsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetPetsResponse, error) {
+ rsp, err := c.GetPets(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetPetsResponse(rsp)
+}
+
+// ParseGetPetsResponse parses an HTTP response from a GetPetsWithResponse call
+func ParseGetPetsResponse(rsp *http.Response) (*GetPetsResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetPetsResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest struct {
+ Data *[]GetPets200JSONResponseBody_Data_Item `json:"data,omitempty"`
+ }
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // Get a list of pets
+ // (GET /pets)
+ GetPets(ctx echo.Context) error
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+// GetPets converts echo context to params.
+func (w *ServerInterfaceWrapper) GetPets(ctx echo.Context) error {
+ var err error
+
+ ctx.Set(string(ApiKeyAuthScopes), []string{})
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetPets(ctx)
+ return err
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+}
+
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
+}
+
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.GET(options.BaseURL+"/pets", wrapper.GetPets, options.OperationMiddlewares["getPets"]...)
+
+}
diff --git a/internal/test/any_of/codegen/inline/spec.yaml b/internal/test/any_of/codegen/inline/spec.yaml
new file mode 100644
index 0000000000..bb0e44448c
--- /dev/null
+++ b/internal/test/any_of/codegen/inline/spec.yaml
@@ -0,0 +1,81 @@
+openapi: 3.0.0
+info:
+ version: 1.0.0
+ title: Cats, Dogs and Rats API
+ description: This API allows the client to receive information about cats, dogs and rats.
+servers:
+ - url: https://example.com/api
+security:
+ - ApiKeyAuth: []
+paths:
+ /pets:
+ get:
+ summary: Get a list of pets
+ description: This endpoint returns a list of pets. Each pet can be either a cat, dog or a rat.
+ operationId: getPets
+ responses:
+ '200':
+ description: Successful response
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ data:
+ type: array
+ items:
+ anyOf:
+ - $ref: '#/components/schemas/Cat'
+ - $ref: '#/components/schemas/Dog'
+ - $ref: '#/components/schemas/Rat'
+ '401':
+ description: Unauthorized
+ '500':
+ description: Internal Server Error
+components:
+ securitySchemes:
+ ApiKeyAuth:
+ type: apiKey
+ in: header
+ name: X-API-Key
+ schemas:
+ Cat:
+ type: object
+ description: This is a cat
+ properties:
+ id:
+ type: string
+ name:
+ type: string
+ breed:
+ type: string
+ color:
+ type: string
+ purrs:
+ type: boolean
+ Dog:
+ type: object
+ description: This is a dog
+ properties:
+ id:
+ type: string
+ name:
+ type: string
+ breed:
+ type: string
+ color:
+ type: string
+ barks:
+ type: boolean
+ Rat:
+ type: object
+ description: This is a rat
+ properties:
+ id:
+ type: string
+ name:
+ type: string
+ color:
+ type: string
+ squeaks:
+ type: boolean
diff --git a/internal/test/any_of/codegen/ref_schema/config.yaml b/internal/test/any_of/codegen/ref_schema/config.yaml
new file mode 100644
index 0000000000..07176c2906
--- /dev/null
+++ b/internal/test/any_of/codegen/ref_schema/config.yaml
@@ -0,0 +1,6 @@
+package: ref_schema
+generate:
+ models: true
+ client: true
+ echo-server: true
+output: openapi.gen.go
diff --git a/internal/test/any_of/codegen/ref_schema/generate.go b/internal/test/any_of/codegen/ref_schema/generate.go
new file mode 100644
index 0000000000..061e2a828d
--- /dev/null
+++ b/internal/test/any_of/codegen/ref_schema/generate.go
@@ -0,0 +1,3 @@
+package ref_schema
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/any_of/codegen/ref_schema/openapi.gen.go b/internal/test/any_of/codegen/ref_schema/openapi.gen.go
new file mode 100644
index 0000000000..c69077123e
--- /dev/null
+++ b/internal/test/any_of/codegen/ref_schema/openapi.gen.go
@@ -0,0 +1,460 @@
+// Package ref_schema provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package ref_schema
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/labstack/echo/v4"
+ "github.com/oapi-codegen/runtime"
+)
+
+const (
+ ApiKeyAuthScopes apiKeyAuthContextKey = "ApiKeyAuth.Scopes"
+)
+
+// Cat This is a cat
+type Cat struct {
+ Breed *string `json:"breed,omitempty"`
+ Color *string `json:"color,omitempty"`
+ Id *string `json:"id,omitempty"`
+ Name *string `json:"name,omitempty"`
+ Purrs *bool `json:"purrs,omitempty"`
+}
+
+// Dog This is a dog
+type Dog struct {
+ Barks *bool `json:"barks,omitempty"`
+ Breed *string `json:"breed,omitempty"`
+ Color *string `json:"color,omitempty"`
+ Id *string `json:"id,omitempty"`
+ Name *string `json:"name,omitempty"`
+}
+
+// GetPetsDto defines model for GetPetsDto.
+type GetPetsDto struct {
+ Data *GetPetsDto_Data `json:"data,omitempty"`
+}
+
+// GetPetsDto_Data defines model for GetPetsDto.Data.
+type GetPetsDto_Data struct {
+ union json.RawMessage
+}
+
+// Rat This is a rat
+type Rat struct {
+ Color *string `json:"color,omitempty"`
+ Id *string `json:"id,omitempty"`
+ Name *string `json:"name,omitempty"`
+ Squeaks *bool `json:"squeaks,omitempty"`
+}
+
+// apiKeyAuthContextKey is the context key for ApiKeyAuth security scheme
+type apiKeyAuthContextKey string
+
+// AsCat returns the union data inside the GetPetsDto_Data as a Cat
+func (t GetPetsDto_Data) AsCat() (Cat, error) {
+ var body Cat
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromCat overwrites any union data inside the GetPetsDto_Data as the provided Cat
+func (t *GetPetsDto_Data) FromCat(v Cat) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeCat performs a merge with any union data inside the GetPetsDto_Data, using the provided Cat
+func (t *GetPetsDto_Data) MergeCat(v Cat) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsDog returns the union data inside the GetPetsDto_Data as a Dog
+func (t GetPetsDto_Data) AsDog() (Dog, error) {
+ var body Dog
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromDog overwrites any union data inside the GetPetsDto_Data as the provided Dog
+func (t *GetPetsDto_Data) FromDog(v Dog) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeDog performs a merge with any union data inside the GetPetsDto_Data, using the provided Dog
+func (t *GetPetsDto_Data) MergeDog(v Dog) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsRat returns the union data inside the GetPetsDto_Data as a Rat
+func (t GetPetsDto_Data) AsRat() (Rat, error) {
+ var body Rat
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromRat overwrites any union data inside the GetPetsDto_Data as the provided Rat
+func (t *GetPetsDto_Data) FromRat(v Rat) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeRat performs a merge with any union data inside the GetPetsDto_Data, using the provided Rat
+func (t *GetPetsDto_Data) MergeRat(v Rat) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t GetPetsDto_Data) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *GetPetsDto_Data) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetPets request
+ GetPets(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetPets(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetPetsRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetPetsRequest generates requests for GetPets
+func NewGetPetsRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/pets")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetPetsWithResponse request
+ GetPetsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetPetsResponse, error)
+}
+
+type GetPetsResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *GetPetsDto
+}
+
+// GetJSON200 returns JSON200
+func (r GetPetsResponse) GetJSON200() *GetPetsDto {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetPetsResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetPetsResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetPetsResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetPetsResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetPetsWithResponse request returning *GetPetsResponse
+func (c *ClientWithResponses) GetPetsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetPetsResponse, error) {
+ rsp, err := c.GetPets(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetPetsResponse(rsp)
+}
+
+// ParseGetPetsResponse parses an HTTP response from a GetPetsWithResponse call
+func ParseGetPetsResponse(rsp *http.Response) (*GetPetsResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetPetsResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest GetPetsDto
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // Get a list of pets
+ // (GET /pets)
+ GetPets(ctx echo.Context) error
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+// GetPets converts echo context to params.
+func (w *ServerInterfaceWrapper) GetPets(ctx echo.Context) error {
+ var err error
+
+ ctx.Set(string(ApiKeyAuthScopes), []string{})
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetPets(ctx)
+ return err
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+}
+
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
+}
+
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.GET(options.BaseURL+"/pets", wrapper.GetPets, options.OperationMiddlewares["getPets"]...)
+
+}
diff --git a/internal/test/any_of/codegen/ref_schema/spec.yaml b/internal/test/any_of/codegen/ref_schema/spec.yaml
new file mode 100644
index 0000000000..f571db0134
--- /dev/null
+++ b/internal/test/any_of/codegen/ref_schema/spec.yaml
@@ -0,0 +1,81 @@
+openapi: 3.0.0
+info:
+ version: 1.0.0
+ title: Cats, Dogs and Rats API
+ description: This API allows the client to receive information about cats, dogs and rats.
+servers:
+ - url: https://example.com/api
+security:
+ - ApiKeyAuth: []
+paths:
+ /pets:
+ get:
+ summary: Get a list of pets
+ description: This endpoint returns a list of pets. Each pet can be either a cat, dog or a rat.
+ operationId: getPets
+ responses:
+ '200':
+ description: Successful response
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GetPetsDto'
+ '401':
+ description: Unauthorized
+ '500':
+ description: Internal Server Error
+components:
+ securitySchemes:
+ ApiKeyAuth:
+ type: apiKey
+ in: header
+ name: X-API-Key
+ schemas:
+ GetPetsDto:
+ type: object
+ properties:
+ data:
+ anyOf:
+ - $ref: '#/components/schemas/Cat'
+ - $ref: '#/components/schemas/Dog'
+ - $ref: '#/components/schemas/Rat'
+ Cat:
+ type: object
+ description: This is a cat
+ properties:
+ id:
+ type: string
+ name:
+ type: string
+ breed:
+ type: string
+ color:
+ type: string
+ purrs:
+ type: boolean
+ Dog:
+ type: object
+ description: This is a dog
+ properties:
+ id:
+ type: string
+ name:
+ type: string
+ breed:
+ type: string
+ color:
+ type: string
+ barks:
+ type: boolean
+ Rat:
+ type: object
+ description: This is a rat
+ properties:
+ id:
+ type: string
+ name:
+ type: string
+ color:
+ type: string
+ squeaks:
+ type: boolean
diff --git a/internal/test/any_of/param/config.yaml b/internal/test/any_of/param/config.yaml
index 7b2827042a..1e35ec88ba 100644
--- a/internal/test/any_of/param/config.yaml
+++ b/internal/test/any_of/param/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: param
generate:
models: true
diff --git a/internal/test/any_of/param/doc.go b/internal/test/any_of/param/doc.go
index 63ff22389a..657385e03f 100644
--- a/internal/test/any_of/param/doc.go
+++ b/internal/test/any_of/param/doc.go
@@ -1,3 +1,3 @@
package param
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/any_of/param/param.gen.go b/internal/test/any_of/param/param.gen.go
index 6c0c55ae93..69e50dd32e 100644
--- a/internal/test/any_of/param/param.gen.go
+++ b/internal/test/any_of/param/param.gen.go
@@ -1,6 +1,6 @@
// Package param provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package param
import (
@@ -70,7 +70,7 @@ func (t *Test) MergeTest0(v Test0) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -96,7 +96,7 @@ func (t *Test) MergeTest1(v Test1) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -132,7 +132,7 @@ func (t *Test2) MergeTest20(v Test20) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -158,7 +158,7 @@ func (t *Test2) MergeTest21(v Test21) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -282,19 +282,21 @@ func NewGetTestRequest(server string, params *GetTestParams) (*http.Request, err
}
if params != nil {
+ // queryValues collects non-styled parameters (passthrough, JSON)
+ // that are safe to round-trip through url.Values.Encode().
queryValues := queryURL.Query()
+ // rawQueryFragments collects pre-encoded query fragments from
+ // styled parameters, preserving literal commas as delimiters
+ // per the OpenAPI spec (e.g. "color=blue,black,brown").
+ var rawQueryFragments []string
if params.Test != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "test", runtime.ParamLocationQuery, *params.Test); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "test", *params.Test, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "", Format: ""}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
@@ -302,24 +304,23 @@ func NewGetTestRequest(server string, params *GetTestParams) (*http.Request, err
if params.Test2 != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "test2", runtime.ParamLocationQuery, *params.Test2); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "test2", *params.Test2, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "array", Format: ""}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
}
- queryURL.RawQuery = queryValues.Encode()
+ if encoded := queryValues.Encode(); encoded != "" {
+ rawQueryFragments = append(rawQueryFragments, encoded)
+ }
+ queryURL.RawQuery = strings.Join(rawQueryFragments, "&")
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -379,6 +380,11 @@ type GetTestResponse struct {
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetTestResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetTestResponse) Status() string {
if r.HTTPResponse != nil {
@@ -395,6 +401,14 @@ func (r GetTestResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetTestResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// GetTestWithResponse request returning *GetTestResponse
func (c *ClientWithResponses) GetTestWithResponse(ctx context.Context, params *GetTestParams, reqEditors ...RequestEditorFn) (*GetTestResponse, error) {
rsp, err := c.GetTest(ctx, params, reqEditors...)
diff --git a/internal/test/any_of/param/param_test.go b/internal/test/any_of/param/param_test.go
index 748ebc54e2..94641b3650 100644
--- a/internal/test/any_of/param/param_test.go
+++ b/internal/test/any_of/param/param_test.go
@@ -3,7 +3,7 @@ package param_test
import (
"testing"
- "github.com/deepmap/oapi-codegen/internal/test/any_of/param"
+ "github.com/oapi-codegen/oapi-codegen/v2/internal/test/any_of/param"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
diff --git a/internal/test/client/client.gen.go b/internal/test/client/client.gen.go
index 3820fe9119..aa6d0a4c7d 100644
--- a/internal/test/client/client.gen.go
+++ b/internal/test/client/client.gen.go
@@ -1,6 +1,6 @@
// Package client provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package client
import (
@@ -15,7 +15,7 @@ import (
)
const (
- OpenIdScopes = "OpenId.Scopes"
+ OpenIdScopes openIdContextKey = "OpenId.Scopes"
)
// SchemaObject defines model for SchemaObject.
@@ -24,6 +24,9 @@ type SchemaObject struct {
Role string `json:"role"`
}
+// openIdContextKey is the context key for OpenId security scheme
+type openIdContextKey string
+
// PostVendorJsonApplicationVndAPIPlusJSONBody defines parameters for PostVendorJson.
type PostVendorJsonApplicationVndAPIPlusJSONBody = map[string]interface{}
@@ -302,7 +305,7 @@ func NewPostBothRequestWithBody(server string, contentType string, body io.Reade
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -331,7 +334,7 @@ func NewGetBothRequest(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -369,7 +372,7 @@ func NewPostJsonRequestWithBody(server string, contentType string, body io.Reade
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -398,7 +401,7 @@ func NewGetJsonRequest(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -425,7 +428,7 @@ func NewPostOtherRequestWithBody(server string, contentType string, body io.Read
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -454,7 +457,7 @@ func NewGetOtherRequest(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -481,7 +484,7 @@ func NewGetJsonWithTrailingSlashRequest(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -519,7 +522,7 @@ func NewPostVendorJsonRequestWithBody(server string, contentType string, body io
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -608,6 +611,11 @@ type PostBothResponse struct {
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r PostBothResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r PostBothResponse) Status() string {
if r.HTTPResponse != nil {
@@ -624,11 +632,24 @@ func (r PostBothResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostBothResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type GetBothResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetBothResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetBothResponse) Status() string {
if r.HTTPResponse != nil {
@@ -645,11 +666,24 @@ func (r GetBothResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetBothResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type PostJsonResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r PostJsonResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r PostJsonResponse) Status() string {
if r.HTTPResponse != nil {
@@ -666,11 +700,24 @@ func (r PostJsonResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostJsonResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type GetJsonResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetJsonResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetJsonResponse) Status() string {
if r.HTTPResponse != nil {
@@ -687,11 +734,24 @@ func (r GetJsonResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetJsonResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type PostOtherResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r PostOtherResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r PostOtherResponse) Status() string {
if r.HTTPResponse != nil {
@@ -708,11 +768,24 @@ func (r PostOtherResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostOtherResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type GetOtherResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetOtherResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetOtherResponse) Status() string {
if r.HTTPResponse != nil {
@@ -729,11 +802,24 @@ func (r GetOtherResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetOtherResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type GetJsonWithTrailingSlashResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetJsonWithTrailingSlashResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetJsonWithTrailingSlashResponse) Status() string {
if r.HTTPResponse != nil {
@@ -750,11 +836,24 @@ func (r GetJsonWithTrailingSlashResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetJsonWithTrailingSlashResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type PostVendorJsonResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r PostVendorJsonResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r PostVendorJsonResponse) Status() string {
if r.HTTPResponse != nil {
@@ -771,6 +870,14 @@ func (r PostVendorJsonResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostVendorJsonResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// PostBothWithBodyWithResponse request with arbitrary body returning *PostBothResponse
func (c *ClientWithResponses) PostBothWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostBothResponse, error) {
rsp, err := c.PostBothWithBody(ctx, contentType, body, reqEditors...)
diff --git a/internal/test/client/client.yaml b/internal/test/client/client.yaml
index ea4c1c3b1e..15119e593e 100644
--- a/internal/test/client/client.yaml
+++ b/internal/test/client/client.yaml
@@ -90,6 +90,10 @@ paths:
schema:
type: object
components:
+ securitySchemes:
+ OpenId:
+ type: openIdConnect
+ openIdConnectUrl: https://example.com/.well-known/openid-configuration
schemas:
SchemaObject:
properties:
diff --git a/internal/test/client/client_test.go b/internal/test/client/client_test.go
index 473bc37fee..ef7c5df169 100644
--- a/internal/test/client/client_test.go
+++ b/internal/test/client/client_test.go
@@ -3,7 +3,7 @@ package client
import (
"testing"
- "github.com/deepmap/oapi-codegen/pkg/securityprovider"
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/securityprovider"
"github.com/stretchr/testify/assert"
)
diff --git a/internal/test/client/doc.go b/internal/test/client/doc.go
index e7a3a106d8..930039dadd 100644
--- a/internal/test/client/doc.go
+++ b/internal/test/client/doc.go
@@ -1,3 +1,3 @@
package client
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=client --generate=client,types -o client.gen.go client.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --package=client --generate=client,types -o client.gen.go client.yaml
diff --git a/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/api.yaml b/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/api.yaml
new file mode 100644
index 0000000000..ace3dbd4b9
--- /dev/null
+++ b/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/api.yaml
@@ -0,0 +1,24 @@
+openapi: "3.0.0"
+info:
+ title: "my spec"
+ version: 1.0.0
+paths:
+ /pet:
+ get:
+ operationId: getPet
+ responses:
+ 200:
+ content:
+ application/json:
+ schema:
+ type: string
+ delete:
+ # Via https://spec.openapis.org/oas/v3.0.3.html
+ # operationId: Unique string used to identify the operation. The id MUST be unique among all operations described in the API. The operationId value is case-sensitive. Tools and libraries MAY use the operationId to uniquely identify an operation, therefore, it is RECOMMENDED to follow common programming naming conventions.
+ operationId: this-is-a-kebabAndCamel_SNAKE
+ responses:
+ 200:
+ content:
+ application/json:
+ schema:
+ type: string
diff --git a/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/cfg.yaml b/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/cfg.yaml
new file mode 100644
index 0000000000..055e75c884
--- /dev/null
+++ b/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/cfg.yaml
@@ -0,0 +1,9 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: preserveoriginaloperationidcasinginembeddedspec
+output: spec.gen.go
+generate:
+ embedded-spec: true
+output-options:
+ skip-prune: false
+compatibility:
+ preserve-original-operation-id-casing-in-embedded-spec: true
diff --git a/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/generate.go b/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/generate.go
new file mode 100644
index 0000000000..5a48f1eece
--- /dev/null
+++ b/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/generate.go
@@ -0,0 +1,3 @@
+package preserveoriginaloperationidcasinginembeddedspec
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/spec.gen.go b/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/spec.gen.go
new file mode 100644
index 0000000000..f11ee94195
--- /dev/null
+++ b/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/spec.gen.go
@@ -0,0 +1,118 @@
+// Package preserveoriginaloperationidcasinginembeddedspec provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package preserveoriginaloperationidcasinginembeddedspec
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "fmt"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+)
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "tI7BSsVADEV/Re56+l7V3ewe4kIEEfwAmdfGNtpmQhOEUubfZcaVH2A2NwRy7jnA8pERDzj7QohY9xtT",
+ "GhDwTZtxFkTcnvpTjxKQlSQpI+K+nQI0+Wz1/6zkNUdayKluWWlLzlmeRkT4zNaxdan7omu6XmR8SCst",
+ "728vl+dHBGxkmsWowe76vsaQxUkaNqkuPDTc+dOq1QEbZlpTk9+1uptvLBNKm4Dp1+ivx0T+Sv4fhaWU",
+ "nwAAAP//",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/spec_test.go b/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/spec_test.go
new file mode 100644
index 0000000000..01b7f91c59
--- /dev/null
+++ b/internal/test/compatibility/preserve-original-operation-id-casing-in-embedded-spec/spec_test.go
@@ -0,0 +1,29 @@
+package preserveoriginaloperationidcasinginembeddedspec
+
+import (
+ "net/http"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestSpecReturnsOperationIdAsOriginallySpecified(t *testing.T) {
+ spec, err := GetSpec()
+ require.NoError(t, err)
+
+ path := spec.Paths.Find("/pet")
+ require.NotNil(t, path, "The path /pet could not be found")
+
+ operation := path.GetOperation(http.MethodGet)
+ require.NotNil(t, operation, "The GET operation on the path /pet could not be found")
+
+ // this should be the raw operationId from the spec
+ assert.Equal(t, "getPet", operation.OperationID)
+
+ operation = path.GetOperation(http.MethodDelete)
+ require.NotNil(t, operation, "The DELETE operation on the path /pet could not be found")
+
+ // this should be the raw operationId from the spec
+ assert.Equal(t, "this-is-a-kebabAndCamel_SNAKE", operation.OperationID)
+}
diff --git a/internal/test/components/components.gen.go b/internal/test/components/components.gen.go
index 3160275e33..85680e232c 100644
--- a/internal/test/components/components.gen.go
+++ b/internal/test/components/components.gen.go
@@ -1,6 +1,6 @@
// Package components provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package components
import (
@@ -18,6 +18,20 @@ const (
Enum1Two Enum1 = "Two"
)
+// Valid indicates whether the value is a known member of the Enum1 enum.
+func (e Enum1) Valid() bool {
+ switch e {
+ case Enum1One:
+ return true
+ case Enum1Three:
+ return true
+ case Enum1Two:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for Enum2.
const (
Enum2Four Enum2 = "Four"
@@ -25,6 +39,20 @@ const (
Enum2Two Enum2 = "Two"
)
+// Valid indicates whether the value is a known member of the Enum2 enum.
+func (e Enum2) Valid() bool {
+ switch e {
+ case Enum2Four:
+ return true
+ case Enum2Three:
+ return true
+ case Enum2Two:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for Enum3.
const (
Enum3Bar Enum3 = "Bar"
@@ -32,6 +60,20 @@ const (
Enum3Foo Enum3 = "Foo"
)
+// Valid indicates whether the value is a known member of the Enum3 enum.
+func (e Enum3) Valid() bool {
+ switch e {
+ case Enum3Bar:
+ return true
+ case Enum3Enum1One:
+ return true
+ case Enum3Foo:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for Enum4.
const (
Cat Enum4 = "Cat"
@@ -39,6 +81,20 @@ const (
Mouse Enum4 = "Mouse"
)
+// Valid indicates whether the value is a known member of the Enum4 enum.
+func (e Enum4) Valid() bool {
+ switch e {
+ case Cat:
+ return true
+ case Dog:
+ return true
+ case Mouse:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for Enum5.
const (
Enum5N5 Enum5 = 5
@@ -46,6 +102,20 @@ const (
Enum5N7 Enum5 = 7
)
+// Valid indicates whether the value is a known member of the Enum5 enum.
+func (e Enum5) Valid() bool {
+ switch e {
+ case Enum5N5:
+ return true
+ case Enum5N6:
+ return true
+ case Enum5N7:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for EnumUnion.
const (
EnumUnionFour EnumUnion = "Four"
@@ -54,6 +124,22 @@ const (
EnumUnionTwo EnumUnion = "Two"
)
+// Valid indicates whether the value is a known member of the EnumUnion enum.
+func (e EnumUnion) Valid() bool {
+ switch e {
+ case EnumUnionFour:
+ return true
+ case EnumUnionOne:
+ return true
+ case EnumUnionThree:
+ return true
+ case EnumUnionTwo:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for EnumUnion2.
const (
EnumUnion2One EnumUnion2 = "One"
@@ -62,6 +148,22 @@ const (
EnumUnion2Two EnumUnion2 = "Two"
)
+// Valid indicates whether the value is a known member of the EnumUnion2 enum.
+func (e EnumUnion2) Valid() bool {
+ switch e {
+ case EnumUnion2One:
+ return true
+ case EnumUnion2Seven:
+ return true
+ case EnumUnion2Three:
+ return true
+ case EnumUnion2Two:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for FunnyValues.
const (
FunnyValuesAnd FunnyValues = "&"
@@ -71,6 +173,24 @@ const (
FunnyValuesPercent FunnyValues = "%"
)
+// Valid indicates whether the value is a known member of the FunnyValues enum.
+func (e FunnyValues) Valid() bool {
+ switch e {
+ case FunnyValuesAnd:
+ return true
+ case FunnyValuesAsterisk:
+ return true
+ case FunnyValuesEmpty:
+ return true
+ case FunnyValuesN5:
+ return true
+ case FunnyValuesPercent:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for EnumParam1.
const (
EnumParam1Both EnumParam1 = "both"
@@ -78,6 +198,20 @@ const (
EnumParam1On EnumParam1 = "on"
)
+// Valid indicates whether the value is a known member of the EnumParam1 enum.
+func (e EnumParam1) Valid() bool {
+ switch e {
+ case EnumParam1Both:
+ return true
+ case EnumParam1Off:
+ return true
+ case EnumParam1On:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for EnumParam2.
const (
EnumParam2Both EnumParam2 = "both"
@@ -85,6 +219,20 @@ const (
EnumParam2On EnumParam2 = "on"
)
+// Valid indicates whether the value is a known member of the EnumParam2 enum.
+func (e EnumParam2) Valid() bool {
+ switch e {
+ case EnumParam2Both:
+ return true
+ case EnumParam2Off:
+ return true
+ case EnumParam2On:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for EnumParam3.
const (
Alice EnumParam3 = "alice"
@@ -92,6 +240,20 @@ const (
Eve EnumParam3 = "eve"
)
+// Valid indicates whether the value is a known member of the EnumParam3 enum.
+func (e EnumParam3) Valid() bool {
+ switch e {
+ case Alice:
+ return true
+ case Bob:
+ return true
+ case Eve:
+ return true
+ default:
+ return false
+ }
+}
+
// AdditionalPropertiesObject1 Has additional properties of type int
type AdditionalPropertiesObject1 struct {
Id int `json:"id"`
@@ -157,10 +319,10 @@ type Enum4 string
// Enum5 Numerical enum
type Enum5 int
-// EnumUnion defines model for EnumUnion.
+// EnumUnion Two enums of the same type combined with allOf.
type EnumUnion string
-// EnumUnion2 defines model for EnumUnion2.
+// EnumUnion2 Two enums of the same type combined with allOf.
type EnumUnion2 string
// FunnyValues Edge cases for enum names
@@ -209,7 +371,7 @@ type OneOfObject11_AdditionalProperties struct {
union json.RawMessage
}
-// OneOfObject12 defines model for OneOfObject12.
+// OneOfObject12 allOf of oneOfs
type OneOfObject12 struct {
union json.RawMessage
}
@@ -293,7 +455,7 @@ type OneOfObject8 struct {
union json.RawMessage
}
-// OneOfObject9 oneOf with fixed descriminator
+// OneOfObject9 oneOf with fixed discriminator
type OneOfObject9 struct {
Type string `json:"type"`
union json.RawMessage
@@ -329,7 +491,7 @@ type OneOfVariant6 struct {
// ReferenceToRenameMe When a Schema is renamed, $ref should refer to the new name
type ReferenceToRenameMe struct {
- // ToNewName This schema should be renamed via x-go-name when generating
+ // NewName This schema should be renamed via x-go-name when generating
NewName NewName `json:"ToNewName"`
}
@@ -425,85 +587,6 @@ type EnsureEverythingIsReferencedTextRequestBody = EnsureEverythingIsReferencedT
// BodyWithAddPropsJSONRequestBody defines body for BodyWithAddProps for application/json ContentType.
type BodyWithAddPropsJSONRequestBody BodyWithAddPropsJSONBody
-// Getter for additional properties for BodyWithAddPropsJSONBody. Returns the specified
-// element and whether it was found
-func (a BodyWithAddPropsJSONBody) Get(fieldName string) (value interface{}, found bool) {
- if a.AdditionalProperties != nil {
- value, found = a.AdditionalProperties[fieldName]
- }
- return
-}
-
-// Setter for additional properties for BodyWithAddPropsJSONBody
-func (a *BodyWithAddPropsJSONBody) Set(fieldName string, value interface{}) {
- if a.AdditionalProperties == nil {
- a.AdditionalProperties = make(map[string]interface{})
- }
- a.AdditionalProperties[fieldName] = value
-}
-
-// Override default JSON handling for BodyWithAddPropsJSONBody to handle AdditionalProperties
-func (a *BodyWithAddPropsJSONBody) UnmarshalJSON(b []byte) error {
- object := make(map[string]json.RawMessage)
- err := json.Unmarshal(b, &object)
- if err != nil {
- return err
- }
-
- if raw, found := object["inner"]; found {
- err = json.Unmarshal(raw, &a.Inner)
- if err != nil {
- return fmt.Errorf("error reading 'inner': %w", err)
- }
- delete(object, "inner")
- }
-
- if raw, found := object["name"]; found {
- err = json.Unmarshal(raw, &a.Name)
- if err != nil {
- return fmt.Errorf("error reading 'name': %w", err)
- }
- delete(object, "name")
- }
-
- if len(object) != 0 {
- a.AdditionalProperties = make(map[string]interface{})
- for fieldName, fieldBuf := range object {
- var fieldVal interface{}
- err := json.Unmarshal(fieldBuf, &fieldVal)
- if err != nil {
- return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
- }
- a.AdditionalProperties[fieldName] = fieldVal
- }
- }
- return nil
-}
-
-// Override default JSON handling for BodyWithAddPropsJSONBody to handle AdditionalProperties
-func (a BodyWithAddPropsJSONBody) MarshalJSON() ([]byte, error) {
- var err error
- object := make(map[string]json.RawMessage)
-
- object["inner"], err = json.Marshal(a.Inner)
- if err != nil {
- return nil, fmt.Errorf("error marshaling 'inner': %w", err)
- }
-
- object["name"], err = json.Marshal(a.Name)
- if err != nil {
- return nil, fmt.Errorf("error marshaling 'name': %w", err)
- }
-
- for fieldName, field := range a.AdditionalProperties {
- object[fieldName], err = json.Marshal(field)
- if err != nil {
- return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
- }
- }
- return json.Marshal(object)
-}
-
// Getter for additional properties for AdditionalPropertiesObject1. Returns the specified
// element and whether it was found
func (a AdditionalPropertiesObject1) Get(fieldName string) (value int, found bool) {
@@ -826,6 +909,87 @@ func (a *OneOfObject13) Set(fieldName string, value interface{}) {
a.AdditionalProperties[fieldName] = value
}
+// Getter for additional properties for BodyWithAddPropsJSONBody. Returns the specified
+// element and whether it was found
+func (a BodyWithAddPropsJSONBody) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for BodyWithAddPropsJSONBody
+func (a *BodyWithAddPropsJSONBody) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for BodyWithAddPropsJSONBody to handle AdditionalProperties
+func (a *BodyWithAddPropsJSONBody) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["inner"]; found {
+ err = json.Unmarshal(raw, &a.Inner)
+ if err != nil {
+ return fmt.Errorf("error reading 'inner': %w", err)
+ }
+ delete(object, "inner")
+ }
+
+ if raw, found := object["name"]; found {
+ err = json.Unmarshal(raw, &a.Name)
+ if err != nil {
+ return fmt.Errorf("error reading 'name': %w", err)
+ }
+ delete(object, "name")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for BodyWithAddPropsJSONBody to handle AdditionalProperties
+func (a BodyWithAddPropsJSONBody) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Inner != nil {
+ object["inner"], err = json.Marshal(a.Inner)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'inner': %w", err)
+ }
+ }
+
+ object["name"], err = json.Marshal(a.Name)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'name': %w", err)
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
// AsOneOfVariant4 returns the union data inside the AnyOfObject1 as a OneOfVariant4
func (t AnyOfObject1) AsOneOfVariant4() (OneOfVariant4, error) {
var body OneOfVariant4
@@ -847,7 +1011,7 @@ func (t *AnyOfObject1) MergeOneOfVariant4(v OneOfVariant4) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -873,7 +1037,7 @@ func (t *AnyOfObject1) MergeOneOfVariant5(v OneOfVariant5) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -909,7 +1073,7 @@ func (t *OneOfObject1) MergeOneOfVariant1(v OneOfVariant1) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -935,7 +1099,7 @@ func (t *OneOfObject1) MergeOneOfVariant2(v OneOfVariant2) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -961,7 +1125,7 @@ func (t *OneOfObject1) MergeOneOfVariant3(v OneOfVariant3) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -997,7 +1161,7 @@ func (t *OneOfObject10) MergeOneOfObject100(v OneOfObject100) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1023,7 +1187,7 @@ func (t *OneOfObject10) MergeOneOfObject101(v OneOfObject101) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1121,7 +1285,7 @@ func (t *OneOfObject11_AdditionalProperties) MergeOneOfObject110(v OneOfObject11
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1147,7 +1311,7 @@ func (t *OneOfObject11_AdditionalProperties) MergeOneOfObject111(v OneOfObject11
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1173,7 +1337,7 @@ func (t *OneOfObject11_AdditionalProperties) MergeOneOfObject112(v OneOfObject11
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1209,7 +1373,7 @@ func (t *OneOfObject12) MergeOneOfObject120(v OneOfObject120) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1235,7 +1399,7 @@ func (t *OneOfObject12) MergeOneOfObject121(v OneOfObject121) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1261,7 +1425,7 @@ func (t *OneOfObject12) MergeOneOfVariant3(v OneOfVariant3) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1287,7 +1451,7 @@ func (t *OneOfObject12) MergeOneOfVariant4(v OneOfVariant4) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1327,7 +1491,7 @@ func (t *OneOfObject13) MergeOneOfVariant1(v OneOfVariant1) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1357,7 +1521,7 @@ func (t *OneOfObject13) MergeOneOfVariant6(v OneOfVariant6) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1406,7 +1570,7 @@ func (t *OneOfObject2) MergeOneOfObject20(v OneOfObject20) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1432,7 +1596,7 @@ func (t *OneOfObject2) MergeOneOfObject21(v OneOfObject21) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1458,7 +1622,7 @@ func (t *OneOfObject2) MergeOneOfObject22(v OneOfObject22) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1494,7 +1658,7 @@ func (t *OneOfObject3_Union) MergeOneOfVariant1(v OneOfVariant1) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1520,7 +1684,7 @@ func (t *OneOfObject3_Union) MergeOneOfVariant2(v OneOfVariant2) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1546,7 +1710,7 @@ func (t *OneOfObject3_Union) MergeOneOfVariant3(v OneOfVariant3) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1582,7 +1746,7 @@ func (t *OneOfObject4) MergeOneOfVariant1(v OneOfVariant1) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1608,7 +1772,7 @@ func (t *OneOfObject4) MergeOneOfVariant2(v OneOfVariant2) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1634,7 +1798,7 @@ func (t *OneOfObject4) MergeOneOfVariant3(v OneOfVariant3) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1706,7 +1870,7 @@ func (t *OneOfObject5) MergeOneOfVariant4(v OneOfVariant4) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1734,7 +1898,7 @@ func (t *OneOfObject5) MergeOneOfVariant5(v OneOfVariant5) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1795,7 +1959,7 @@ func (t *OneOfObject6) MergeOneOfVariant4(v OneOfVariant4) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1823,7 +1987,7 @@ func (t *OneOfObject6) MergeOneOfVariant5(v OneOfVariant5) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1884,7 +2048,7 @@ func (t *OneOfObject61) MergeOneOfVariant4(v OneOfVariant4) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1912,7 +2076,7 @@ func (t *OneOfObject61) MergeOneOfVariant5(v OneOfVariant5) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -1973,7 +2137,7 @@ func (t *OneOfObject62) MergeOneOfVariant4(v OneOfVariant4) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -2001,7 +2165,7 @@ func (t *OneOfObject62) MergeOneOfVariant51(v OneOfVariant51) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -2060,7 +2224,7 @@ func (t *OneOfObject7_Item) MergeOneOfVariant1(v OneOfVariant1) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -2086,7 +2250,7 @@ func (t *OneOfObject7_Item) MergeOneOfVariant2(v OneOfVariant2) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -2122,7 +2286,7 @@ func (t *OneOfObject8) MergeOneOfVariant1(v OneOfVariant1) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -2148,7 +2312,7 @@ func (t *OneOfObject8) MergeOneOfVariant2(v OneOfVariant2) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -2222,7 +2386,7 @@ func (t *OneOfObject9) MergeOneOfVariant1(v OneOfVariant1) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -2252,7 +2416,7 @@ func (t *OneOfObject9) MergeOneOfVariant6(v OneOfVariant6) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
diff --git a/internal/test/components/components.yaml b/internal/test/components/components.yaml
index f755a6a356..f711510e37 100644
--- a/internal/test/components/components.yaml
+++ b/internal/test/components/components.yaml
@@ -321,7 +321,7 @@ components:
- $ref: '#/components/schemas/OneOfVariant1'
- $ref: '#/components/schemas/OneOfVariant2'
OneOfObject9:
- description: oneOf with fixed descriminator
+ description: oneOf with fixed discriminator
type: object
properties:
type:
diff --git a/internal/test/components/config.yaml b/internal/test/components/config.yaml
index 1250e0f66a..185203a501 100644
--- a/internal/test/components/config.yaml
+++ b/internal/test/components/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
package: components
generate:
models: true
diff --git a/internal/test/components/doc.go b/internal/test/components/doc.go
index b70ba3d7ab..64f995a9c0 100644
--- a/internal/test/components/doc.go
+++ b/internal/test/components/doc.go
@@ -1,3 +1,3 @@
package components
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml components.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml components.yaml
diff --git a/internal/test/cookies/config.yaml b/internal/test/cookies/config.yaml
new file mode 100644
index 0000000000..2d1cbd4300
--- /dev/null
+++ b/internal/test/cookies/config.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: cookies
+generate:
+ chi-server: true
+ models: true
+output: cookies.gen.go
diff --git a/internal/test/cookies/cookies.gen.go b/internal/test/cookies/cookies.gen.go
new file mode 100644
index 0000000000..1efbec0cdf
--- /dev/null
+++ b/internal/test/cookies/cookies.gen.go
@@ -0,0 +1,216 @@
+// Package cookies provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package cookies
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/go-chi/chi/v5"
+ "github.com/oapi-codegen/runtime"
+)
+
+// CookieParamsParams defines parameters for CookieParams.
+type CookieParamsParams struct {
+ // AuthId Cookie parameter
+ AuthId *string `form:"authId,omitempty" json:"authId,omitempty"`
+
+ // ServerId Another cookie parameter
+ ServerId *string `form:"serverId,omitempty" json:"serverId,omitempty"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /cookies)
+ CookieParams(w http.ResponseWriter, r *http.Request, params CookieParamsParams)
+}
+
+// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
+
+type Unimplemented struct{}
+
+// (GET /cookies)
+func (_ Unimplemented) CookieParams(w http.ResponseWriter, r *http.Request, params CookieParamsParams) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// CookieParams operation middleware
+func (siw *ServerInterfaceWrapper) CookieParams(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params CookieParamsParams
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("authId"); err == nil {
+ var value string
+ err = runtime.BindStyledParameterWithOptions("simple", "authId", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "authId", Err: err})
+ return
+ }
+ params.AuthId = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("serverId"); err == nil {
+ var value string
+ err = runtime.BindStyledParameterWithOptions("simple", "serverId", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "serverId", Err: err})
+ return
+ }
+ params.ServerId = &value
+
+ }
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.CookieParams(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{})
+}
+
+type ChiServerOptions struct {
+ BaseURL string
+ BaseRouter chi.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = chi.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/cookies", wrapper.CookieParams)
+ })
+
+ return r
+}
diff --git a/internal/test/cookies/generate.go b/internal/test/cookies/generate.go
new file mode 100644
index 0000000000..46a9a52676
--- /dev/null
+++ b/internal/test/cookies/generate.go
@@ -0,0 +1,3 @@
+package cookies
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/cookies/spec.yaml b/internal/test/cookies/spec.yaml
new file mode 100644
index 0000000000..f30596224f
--- /dev/null
+++ b/internal/test/cookies/spec.yaml
@@ -0,0 +1,24 @@
+openapi: "3.0.1"
+info:
+ version: 1.0.0
+ title: Cookie parameters
+paths:
+ /cookies:
+ get:
+ operationId: cookieParams
+ parameters:
+ - name: authId
+ description: Cookie parameter
+ in: cookie
+ required: false
+ schema:
+ type: string
+ - name: serverId
+ description: Another cookie parameter
+ in: cookie
+ required: false
+ schema:
+ type: string
+ responses:
+ 204:
+ description: no content
diff --git a/internal/test/extensions/allof-merge-extensions/allof_merge_extensions.gen.go b/internal/test/extensions/allof-merge-extensions/allof_merge_extensions.gen.go
new file mode 100644
index 0000000000..642a693039
--- /dev/null
+++ b/internal/test/extensions/allof-merge-extensions/allof_merge_extensions.gen.go
@@ -0,0 +1,19 @@
+// Package allofmergeextensions provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package allofmergeextensions
+
+// BaseOnly defines model for BaseOnly.
+type BaseOnly = OverlayBaseOnly
+
+// Client defines model for Client.
+type Client = OverlayClient
+
+// ClientWithId defines model for ClientWithId.
+type ClientWithId = OverlayClientWithId
+
+// DerivedNoOverride defines model for DerivedNoOverride.
+type DerivedNoOverride struct {
+ Extra string `json:"extra"`
+ Name string `json:"name"`
+}
diff --git a/internal/test/extensions/allof-merge-extensions/config.yaml b/internal/test/extensions/allof-merge-extensions/config.yaml
new file mode 100644
index 0000000000..5b8d45626e
--- /dev/null
+++ b/internal/test/extensions/allof-merge-extensions/config.yaml
@@ -0,0 +1,9 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: allofmergeextensions
+generate:
+ models: true
+output: allof_merge_extensions.gen.go
+output-options:
+ skip-prune: true
+ overlay:
+ path: overlay.yaml
diff --git a/internal/test/extensions/allof-merge-extensions/generate.go b/internal/test/extensions/allof-merge-extensions/generate.go
new file mode 100644
index 0000000000..04f81f1634
--- /dev/null
+++ b/internal/test/extensions/allof-merge-extensions/generate.go
@@ -0,0 +1,3 @@
+package allofmergeextensions
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/extensions/allof-merge-extensions/overlay.yaml b/internal/test/extensions/allof-merge-extensions/overlay.yaml
new file mode 100644
index 0000000000..dec7115862
--- /dev/null
+++ b/internal/test/extensions/allof-merge-extensions/overlay.yaml
@@ -0,0 +1,14 @@
+overlay: 1.0.0
+info:
+ title: "Example to indicate how to use the OpenAPI Overlay specification (https://github.com/OAI/Overlay-Specification)"
+ version: 1.0.0
+actions:
+ - target: $.components.schemas.Client
+ update:
+ x-go-type: OverlayClient
+ - target: $.components.schemas.ClientWithId
+ update:
+ x-go-type: OverlayClientWithId
+ - target: $.components.schemas.BaseOnly
+ update:
+ x-go-type: OverlayBaseOnly
diff --git a/internal/test/extensions/allof-merge-extensions/overlays.go b/internal/test/extensions/allof-merge-extensions/overlays.go
new file mode 100644
index 0000000000..c2c4c37077
--- /dev/null
+++ b/internal/test/extensions/allof-merge-extensions/overlays.go
@@ -0,0 +1,20 @@
+package allofmergeextensions
+
+// OverlayClient defines model for OverlayClient.
+type OverlayClient struct {
+ Name string `json:"name"`
+}
+
+// OverlayClientWithId defines model for OverlayClientWithId.
+type OverlayClientWithId struct {
+ Id int `json:"id"`
+ Name string `json:"name"`
+}
+
+// OverlayBaseOnly is the user-provided override for the BaseOnly schema.
+// DerivedNoOverride composes BaseOnly via allOf and must NOT be aliased
+// to this type — it has to remain its own struct so the Extra field is
+// preserved.
+type OverlayBaseOnly struct {
+ Name string `json:"name"`
+}
diff --git a/internal/test/extensions/allof-merge-extensions/overlays_test.go b/internal/test/extensions/allof-merge-extensions/overlays_test.go
new file mode 100644
index 0000000000..33b8c72f58
--- /dev/null
+++ b/internal/test/extensions/allof-merge-extensions/overlays_test.go
@@ -0,0 +1,38 @@
+package allofmergeextensions
+
+import "testing"
+
+func TestAllOfOverlay(t *testing.T) {
+ var inner any = Client{}
+ _, ok := inner.(OverlayClient)
+ if !ok {
+ t.Errorf("expected Client to be of type OverlayClient")
+ }
+
+ var outer any = ClientWithId{}
+ _, ok = outer.(OverlayClientWithId)
+ if !ok {
+ t.Errorf("expected ClientWithId to be of type OverlayClientWithId")
+ }
+}
+
+// TestBaseOnlyOverlay covers the harder regression path: when only the
+// base schema has x-go-type (via overlay) and the derived allOf schema
+// has no override of its own, the derived schema must still be emitted
+// as a distinct struct containing all composed fields. The previous
+// bug leaked BaseOnly's x-go-type up through the allOf merge, producing
+// `type DerivedNoOverride = OverlayBaseOnly` and silently dropping the
+// Extra field. The struct literal below would fail to compile under
+// the buggy codegen because OverlayBaseOnly has no Extra field.
+func TestBaseOnlyOverlay(t *testing.T) {
+ d := DerivedNoOverride{Name: "x", Extra: "y"}
+
+ var asAny any = d
+ if _, ok := asAny.(OverlayBaseOnly); ok {
+ t.Error("DerivedNoOverride must not be aliased to OverlayBaseOnly; composition would drop the Extra field")
+ }
+
+ if d.Name != "x" || d.Extra != "y" {
+ t.Errorf("field values not preserved through composed struct: %+v", d)
+ }
+}
diff --git a/internal/test/extensions/allof-merge-extensions/spec.yaml b/internal/test/extensions/allof-merge-extensions/spec.yaml
new file mode 100644
index 0000000000..f8c6453ef7
--- /dev/null
+++ b/internal/test/extensions/allof-merge-extensions/spec.yaml
@@ -0,0 +1,43 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Regression test for allOf + x-go-type interaction (issue #2335)
+components:
+ schemas:
+ Client:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ ClientWithId:
+ allOf:
+ - $ref: '#/components/schemas/Client'
+ - properties:
+ id:
+ type: integer
+ required:
+ - id
+
+ # Second scenario: only the BASE schema receives an x-go-type overlay;
+ # the derived allOf schema has no override of its own. It must still
+ # be emitted as a distinct struct (with both Name and Extra), not
+ # aliased to the base's overlay target. Regression test for the case
+ # where the codegen used to leak the base's x-go-type up through the
+ # allOf merge, silently dropping the derived schema's extra fields.
+ BaseOnly:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ DerivedNoOverride:
+ allOf:
+ - $ref: '#/components/schemas/BaseOnly'
+ - properties:
+ extra:
+ type: string
+ required:
+ - extra
diff --git a/internal/test/extensions/param-ref-sibling-omitempty/config.yaml b/internal/test/extensions/param-ref-sibling-omitempty/config.yaml
new file mode 100644
index 0000000000..0b135b9755
--- /dev/null
+++ b/internal/test/extensions/param-ref-sibling-omitempty/config.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: paramrefsiblingomitempty
+generate:
+ models: true
+ client: true
+output: issue.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/extensions/param-ref-sibling-omitempty/generate.go b/internal/test/extensions/param-ref-sibling-omitempty/generate.go
new file mode 100644
index 0000000000..589a73584b
--- /dev/null
+++ b/internal/test/extensions/param-ref-sibling-omitempty/generate.go
@@ -0,0 +1,3 @@
+package paramrefsiblingomitempty
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/extensions/param-ref-sibling-omitempty/issue.gen.go b/internal/test/extensions/param-ref-sibling-omitempty/issue.gen.go
new file mode 100644
index 0000000000..3ee44a323d
--- /dev/null
+++ b/internal/test/extensions/param-ref-sibling-omitempty/issue.gen.go
@@ -0,0 +1,272 @@
+// Package paramrefsiblingomitempty provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package paramrefsiblingomitempty
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// FilterValue defines model for FilterValue.
+type FilterValue = string
+
+// ListThingsParams defines parameters for ListThings.
+type ListThingsParams struct {
+ Filter *FilterValue `form:"filter" json:"filter"`
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // ListThings request
+ ListThings(ctx context.Context, params *ListThingsParams, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) ListThings(ctx context.Context, params *ListThingsParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewListThingsRequest(c.Server, params)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewListThingsRequest generates requests for ListThings
+func NewListThingsRequest(server string, params *ListThingsParams) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/things")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ if params != nil {
+ // queryValues collects non-styled parameters (passthrough, JSON)
+ // that are safe to round-trip through url.Values.Encode().
+ queryValues := queryURL.Query()
+ // rawQueryFragments collects pre-encoded query fragments from
+ // styled parameters, preserving literal commas as delimiters
+ // per the OpenAPI spec (e.g. "color=blue,black,brown").
+ var rawQueryFragments []string
+
+ if params.Filter != nil {
+
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "filter", *params.Filter, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "string", Format: ""}); err != nil {
+ return nil, err
+ } else {
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
+ }
+ }
+
+ }
+
+ if encoded := queryValues.Encode(); encoded != "" {
+ rawQueryFragments = append(rawQueryFragments, encoded)
+ }
+ queryURL.RawQuery = strings.Join(rawQueryFragments, "&")
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // ListThingsWithResponse request
+ ListThingsWithResponse(ctx context.Context, params *ListThingsParams, reqEditors ...RequestEditorFn) (*ListThingsResponse, error)
+}
+
+type ListThingsResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r ListThingsResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r ListThingsResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r ListThingsResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r ListThingsResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// ListThingsWithResponse request returning *ListThingsResponse
+func (c *ClientWithResponses) ListThingsWithResponse(ctx context.Context, params *ListThingsParams, reqEditors ...RequestEditorFn) (*ListThingsResponse, error) {
+ rsp, err := c.ListThings(ctx, params, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseListThingsResponse(rsp)
+}
+
+// ParseListThingsResponse parses an HTTP response from a ListThingsWithResponse call
+func ParseListThingsResponse(rsp *http.Response) (*ListThingsResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &ListThingsResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
diff --git a/internal/test/extensions/param-ref-sibling-omitempty/spec.yaml b/internal/test/extensions/param-ref-sibling-omitempty/spec.yaml
new file mode 100644
index 0000000000..bd4d17cf89
--- /dev/null
+++ b/internal/test/extensions/param-ref-sibling-omitempty/spec.yaml
@@ -0,0 +1,22 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Regression test for sibling x-omitempty on parameter $ref
+paths:
+ /things:
+ get:
+ operationId: listThings
+ parameters:
+ - name: filter
+ in: query
+ required: false
+ schema:
+ $ref: '#/components/schemas/FilterValue'
+ x-omitempty: false
+ responses:
+ '200':
+ description: OK
+components:
+ schemas:
+ FilterValue:
+ type: string
diff --git a/internal/test/extensions/x-go-type-skip-optional-pointer/config.yaml b/internal/test/extensions/x-go-type-skip-optional-pointer/config.yaml
new file mode 100644
index 0000000000..b2846a10b0
--- /dev/null
+++ b/internal/test/extensions/x-go-type-skip-optional-pointer/config.yaml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: xgotypeskipoptionalpointer
+generate:
+ models: true
+output: issue.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/extensions/x-go-type-skip-optional-pointer/generate.go b/internal/test/extensions/x-go-type-skip-optional-pointer/generate.go
new file mode 100644
index 0000000000..43f0c15780
--- /dev/null
+++ b/internal/test/extensions/x-go-type-skip-optional-pointer/generate.go
@@ -0,0 +1,3 @@
+package xgotypeskipoptionalpointer
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/extensions/x-go-type-skip-optional-pointer/issue.gen.go b/internal/test/extensions/x-go-type-skip-optional-pointer/issue.gen.go
new file mode 100644
index 0000000000..10373fc27e
--- /dev/null
+++ b/internal/test/extensions/x-go-type-skip-optional-pointer/issue.gen.go
@@ -0,0 +1,17 @@
+// Package xgotypeskipoptionalpointer provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xgotypeskipoptionalpointer
+
+// Default defines model for Default.
+type Default = int
+
+// SkipOptionalTrue defines model for SkipOptionalTrue.
+type SkipOptionalTrue = int
+
+// SomeObject defines model for SomeObject.
+type SomeObject struct {
+ SkipOptional SkipOptionalTrue `json:"skip_optional,omitempty"`
+ SkipOptionalNextToRef Default `json:"skip_optional_next_to_ref,omitempty"`
+ SkipOptionalOverrideToFalse *SkipOptionalTrue `json:"skip_optional_override_to_false,omitempty"`
+}
diff --git a/internal/test/extensions/x-go-type-skip-optional-pointer/spec.yaml b/internal/test/extensions/x-go-type-skip-optional-pointer/spec.yaml
new file mode 100644
index 0000000000..7e4abdca38
--- /dev/null
+++ b/internal/test/extensions/x-go-type-skip-optional-pointer/spec.yaml
@@ -0,0 +1,18 @@
+components:
+ schemas:
+ Default:
+ type: integer
+ SkipOptionalTrue:
+ type: integer
+ x-go-type-skip-optional-pointer: true
+ SomeObject:
+ type: object
+ properties:
+ skip_optional:
+ $ref: '#/components/schemas/SkipOptionalTrue'
+ skip_optional_override_to_false:
+ $ref: '#/components/schemas/SkipOptionalTrue'
+ x-go-type-skip-optional-pointer: false
+ skip_optional_next_to_ref:
+ $ref: '#/components/schemas/Default'
+ x-go-type-skip-optional-pointer: true
diff --git a/internal/test/extensions/x-go-type/config.yaml b/internal/test/extensions/x-go-type/config.yaml
new file mode 100644
index 0000000000..22d11384c6
--- /dev/null
+++ b/internal/test/extensions/x-go-type/config.yaml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: xgotype
+generate:
+ models: true
+output: issue.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/extensions/x-go-type/generate.go b/internal/test/extensions/x-go-type/generate.go
new file mode 100644
index 0000000000..32bf4d8403
--- /dev/null
+++ b/internal/test/extensions/x-go-type/generate.go
@@ -0,0 +1,3 @@
+package xgotype
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/extensions/x-go-type/issue.gen.go b/internal/test/extensions/x-go-type/issue.gen.go
new file mode 100644
index 0000000000..98de310ce2
--- /dev/null
+++ b/internal/test/extensions/x-go-type/issue.gen.go
@@ -0,0 +1,19 @@
+// Package xgotype provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xgotype
+
+import (
+ googleuuid "github.com/google/uuid"
+ rate "golang.org/x/time/rate"
+)
+
+// SomeInteger defines model for SomeInteger.
+type SomeInteger = int
+
+// SomeObject defines model for SomeObject.
+type SomeObject struct {
+ IntAsRateLimit *rate.Limit `json:"int_as_rate_limit,omitempty"`
+ IntAsString string `json:"int_as_string"`
+ IntAsUuid *googleuuid.UUID `json:"int_as_uuid,omitempty"`
+}
diff --git a/internal/test/extensions/x-go-type/spec.yaml b/internal/test/extensions/x-go-type/spec.yaml
new file mode 100644
index 0000000000..fefccfd273
--- /dev/null
+++ b/internal/test/extensions/x-go-type/spec.yaml
@@ -0,0 +1,25 @@
+components:
+ schemas:
+ SomeInteger:
+ type: integer
+ x-go-type-import:
+ name: rate
+ path: golang.org/x/time/rate
+ SomeObject:
+ type: object
+ required:
+ - int_as_string
+ - int_as_big_int
+ properties:
+ int_as_string:
+ $ref: '#/components/schemas/SomeInteger'
+ x-go-type: string
+ int_as_rate_limit:
+ $ref: '#/components/schemas/SomeInteger'
+ x-go-type: rate.Limit
+ int_as_uuid:
+ $ref: '#/components/schemas/SomeInteger'
+ x-go-type: googleuuid.UUID
+ x-go-type-import:
+ path: github.com/google/uuid
+ name: googleuuid
diff --git a/internal/test/extensions/x-oapi-codegen-extra-tags/config.yaml b/internal/test/extensions/x-oapi-codegen-extra-tags/config.yaml
new file mode 100644
index 0000000000..58cb1a5395
--- /dev/null
+++ b/internal/test/extensions/x-oapi-codegen-extra-tags/config.yaml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: xextratags
+generate:
+ models: true
+output: issue.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/extensions/x-oapi-codegen-extra-tags/generate.go b/internal/test/extensions/x-oapi-codegen-extra-tags/generate.go
new file mode 100644
index 0000000000..72bf293b13
--- /dev/null
+++ b/internal/test/extensions/x-oapi-codegen-extra-tags/generate.go
@@ -0,0 +1,3 @@
+package xextratags
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/extensions/x-oapi-codegen-extra-tags/issue.gen.go b/internal/test/extensions/x-oapi-codegen-extra-tags/issue.gen.go
new file mode 100644
index 0000000000..804fbff16d
--- /dev/null
+++ b/internal/test/extensions/x-oapi-codegen-extra-tags/issue.gen.go
@@ -0,0 +1,14 @@
+// Package xextratags provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xextratags
+
+// Port defines model for Port.
+type Port = int
+
+// SomeObject defines model for SomeObject.
+type SomeObject struct {
+ Port *Port `bson:"port" json:"port,omitempty"`
+ StartPort *Port `bson:"start_port" json:"start_port,omitempty"`
+ EndPort *Port `bson:"end_port" json:"end_port,omitempty"`
+}
diff --git a/internal/test/extensions/x-oapi-codegen-extra-tags/spec.yaml b/internal/test/extensions/x-oapi-codegen-extra-tags/spec.yaml
new file mode 100644
index 0000000000..b87d3a21e0
--- /dev/null
+++ b/internal/test/extensions/x-oapi-codegen-extra-tags/spec.yaml
@@ -0,0 +1,22 @@
+components:
+ schemas:
+ Port:
+ type: integer
+ x-oapi-codegen-extra-tags:
+ bson: port
+ SomeObject:
+ type: object
+ properties:
+ port:
+ $ref: '#/components/schemas/Port'
+ x-order: 1
+ start_port:
+ $ref: '#/components/schemas/Port'
+ x-order: 2
+ x-oapi-codegen-extra-tags:
+ bson: start_port
+ end_port:
+ $ref: '#/components/schemas/Port'
+ x-order: 3
+ x-oapi-codegen-extra-tags:
+ bson: end_port
diff --git a/internal/test/extensions/x-omitempty/config.yaml b/internal/test/extensions/x-omitempty/config.yaml
new file mode 100644
index 0000000000..d44589c9d8
--- /dev/null
+++ b/internal/test/extensions/x-omitempty/config.yaml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: xomitempty
+generate:
+ models: true
+output: issue.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/extensions/x-omitempty/generate.go b/internal/test/extensions/x-omitempty/generate.go
new file mode 100644
index 0000000000..084b10e62c
--- /dev/null
+++ b/internal/test/extensions/x-omitempty/generate.go
@@ -0,0 +1,3 @@
+package xomitempty
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/extensions/x-omitempty/issue.gen.go b/internal/test/extensions/x-omitempty/issue.gen.go
new file mode 100644
index 0000000000..40e3f0b7fe
--- /dev/null
+++ b/internal/test/extensions/x-omitempty/issue.gen.go
@@ -0,0 +1,17 @@
+// Package xomitempty provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xomitempty
+
+// Default defines model for Default.
+type Default = int
+
+// OmitemptyTrue defines model for OmitemptyTrue.
+type OmitemptyTrue = int
+
+// SomeObject defines model for SomeObject.
+type SomeObject struct {
+ Omitempty *OmitemptyTrue `json:"omitempty,omitempty"`
+ OmitemptyNextToRef *Default `json:"omitempty_next_to_ref,omitempty"`
+ OmitemptyOverrideToFalse *OmitemptyTrue `json:"omitempty_override_to_false"`
+}
diff --git a/internal/test/extensions/x-omitempty/spec.yaml b/internal/test/extensions/x-omitempty/spec.yaml
new file mode 100644
index 0000000000..3ffe4571a1
--- /dev/null
+++ b/internal/test/extensions/x-omitempty/spec.yaml
@@ -0,0 +1,18 @@
+components:
+ schemas:
+ Default:
+ type: integer
+ OmitemptyTrue:
+ type: integer
+ x-omitempty: true
+ SomeObject:
+ type: object
+ properties:
+ omitempty:
+ $ref: '#/components/schemas/OmitemptyTrue'
+ omitempty_override_to_false:
+ $ref: '#/components/schemas/OmitemptyTrue'
+ x-omitempty: false
+ omitempty_next_to_ref:
+ $ref: '#/components/schemas/Default'
+ x-omitempty: true
diff --git a/internal/test/extensions/x-order/config.yaml b/internal/test/extensions/x-order/config.yaml
new file mode 100644
index 0000000000..357489f37d
--- /dev/null
+++ b/internal/test/extensions/x-order/config.yaml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: xorder
+generate:
+ models: true
+output: issue.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/extensions/x-order/generate.go b/internal/test/extensions/x-order/generate.go
new file mode 100644
index 0000000000..8970f968ac
--- /dev/null
+++ b/internal/test/extensions/x-order/generate.go
@@ -0,0 +1,3 @@
+package xorder
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/extensions/x-order/issue.gen.go b/internal/test/extensions/x-order/issue.gen.go
new file mode 100644
index 0000000000..c665ee8ad5
--- /dev/null
+++ b/internal/test/extensions/x-order/issue.gen.go
@@ -0,0 +1,27 @@
+// Package xorder provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package xorder
+
+import (
+ openapi_types "github.com/oapi-codegen/runtime/types"
+)
+
+// DateInterval defines model for DateInterval.
+type DateInterval struct {
+ Start *openapi_types.Date `json:"start,omitempty"`
+ End *openapi_types.Date `json:"end,omitempty"`
+}
+
+// Port defines model for Port.
+type Port = int
+
+// PortInterval defines model for PortInterval.
+type PortInterval struct {
+ Start Port `json:"start"`
+ End Port `json:"end"`
+ VeryEnd *LowPriorityPort `json:"very_end,omitempty"`
+}
+
+// LowPriorityPort defines model for LowPriorityPort.
+type LowPriorityPort = int
diff --git a/internal/test/extensions/x-order/spec.yaml b/internal/test/extensions/x-order/spec.yaml
new file mode 100644
index 0000000000..edc52625da
--- /dev/null
+++ b/internal/test/extensions/x-order/spec.yaml
@@ -0,0 +1,34 @@
+components:
+ schemas:
+ DateInterval:
+ type: object
+ required:
+ - name
+ properties:
+ end:
+ type: string
+ format: date
+ x-order: 2
+ start:
+ type: string
+ format: date
+ x-order: 1
+ Port:
+ type: integer
+ LowPriorityPort:
+ type: integer
+ x-order: 50
+ PortInterval:
+ type: object
+ required:
+ - start
+ - end
+ properties:
+ end:
+ $ref: '#/components/schemas/Port'
+ x-order: 2
+ very_end:
+ $ref: '#/components/schemas/LowPriorityPort'
+ start:
+ $ref: '#/components/schemas/Port'
+ x-order: 1
diff --git a/internal/test/externalref/doc.go b/internal/test/externalref/doc.go
index ea1d5f5ff5..c5aeaa5221 100644
--- a/internal/test/externalref/doc.go
+++ b/internal/test/externalref/doc.go
@@ -1,3 +1,3 @@
package externalref
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=externalref.cfg.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=externalref.cfg.yaml spec.yaml
diff --git a/internal/test/externalref/externalref.cfg.yaml b/internal/test/externalref/externalref.cfg.yaml
index cc772e9e99..56ecbbc41c 100644
--- a/internal/test/externalref/externalref.cfg.yaml
+++ b/internal/test/externalref/externalref.cfg.yaml
@@ -1,10 +1,12 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
package: externalref
generate:
models: true
embedded-spec: true
import-mapping:
- ./packageA/spec.yaml: github.com/deepmap/oapi-codegen/internal/test/externalref/packageA
- ./packageB/spec.yaml: github.com/deepmap/oapi-codegen/internal/test/externalref/packageB
+ ./packageA/spec.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageA
+ ./packageB/spec.yaml: package_b github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageB
+ https://raw.githubusercontent.com/swagger-api/swagger-petstore/refs/heads/master/src/main/resources/openapi.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/petstore
output: externalref.gen.go
output-options:
skip-prune: true
diff --git a/internal/test/externalref/externalref.gen.go b/internal/test/externalref/externalref.gen.go
index 5d2ddd995d..808391ca48 100644
--- a/internal/test/externalref/externalref.gen.go
+++ b/internal/test/externalref/externalref.gen.go
@@ -1,53 +1,62 @@
// Package externalref provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package externalref
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/url"
"path"
"strings"
- externalRef0 "github.com/deepmap/oapi-codegen/internal/test/externalref/packageA"
- externalRef1 "github.com/deepmap/oapi-codegen/internal/test/externalref/packageB"
"github.com/getkin/kin-openapi/openapi3"
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageA"
+ package_b "github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageB"
+ externalRef1 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/petstore"
)
// Container defines model for Container.
type Container struct {
ObjectA *externalRef0.ObjectA `json:"object_a,omitempty"`
- ObjectB *externalRef1.ObjectB `json:"object_b,omitempty"`
+ ObjectB *package_b.ObjectB `json:"object_b,omitempty"`
ObjectC *map[string]interface{} `json:"object_c,omitempty"`
+ Pet *externalRef1.Pet `json:"pet,omitempty"`
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/5yPQU7EMAxF72JYRtOR2GXHcAC4AfJkPNSotaPEIKEqd0dJKa1gQcUqtvzf/z8TBB2j",
- "Coll8BPk0NOIbXxQMWShVJeYNFIypnbS8ysFe8Y63ya6goebbjXqvly6x6a7h+IW5LwPOW2Q8BfyrSul",
- "OFgyf5UWHKm+9hEJPGRLLC//qrbGnHbHlB8fwsuFjVVweNrglt7ILegsn1GWqzZXtqHewME7pcwqdane",
- "kQQjg4e7w/FwBAcRra+NSvkMAAD//3vXjDblAQAA",
+ "vFVNb9swDP0rAbej62bYsINvbXdfDtupKAxGZhxt1scouk1R+L8PkmPHjTs0G7JeEkUUn/jeI5UnUM54",
+ "Z8lKgOIJgtqSwbS8cVZQW+L4w7PzxKIphdz6BykpMa7fM22ggHeXB6DLPcqlR/UTa7oqgydVfk1ZV9Bl",
+ "A8D6RIDrKcD1BEC9BjCe6zLwJK8dDw9Y18QX6HU5rD1JEMdUMm1CuSWsQmkwCHEZWJUGtS2ZgmtZUSid",
+ "JxuzVyTQdUeVYlVp0c5is5roKdxSBvLoCYr98VTui+LNvLBoKH7v84OwtvUZNO4OJRyFTi0hIpxP0BsU",
+ "qh0/zq/XVfykHRrfEBQfMtg4NihQgLby+ROM4morVBNHdYaaxzT44upwODqSOHYmg93FwIRdK8QXxlXU",
+ "RHiX7yP5wDFPsXwsPoOdaQ6agRoC5xVr1bf6c53URMG3GYKRdpfNXFr+o02Vq2tNc6My8Fsn7js3fVMI",
+ "mTBvymP9h5yp0ciME6ceGL2nqp/TZJOgtAm7oqBY+zjSEYtk0ccW2i5kS4skGWRAtjVQ3ALeo25w3cQ9",
+ "T7bqKwquqeDuBUKC9XMub+PaN+xvP0WNLgOmX63muHXbqzp14u4s4xPbeeZcemDPOTSR9x8el7/o1P/y",
+ "fsTSjgUQTG9sHC27celqLWlEIIN74tB3Zfor6BlCAR/zZb6MDqFsI7+u+x0AAP//",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -55,7 +64,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -70,15 +79,19 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
res[pathToFile] = rawSpec
}
- pathPrefix := path.Dir(pathToFile)
-
- for rawPath, rawFunc := range externalRef0.PathToRawSpec(path.Join(pathPrefix, "./packageA/spec.yaml")) {
+ for rawPath, rawFunc := range externalRef0.PathToRawSpec(path.Join(path.Dir(pathToFile), "./packageA/spec.yaml")) {
+ if _, ok := res[rawPath]; ok {
+ // it is not possible to compare functions in golang, so always overwrite the old value
+ }
+ res[rawPath] = rawFunc
+ }
+ for rawPath, rawFunc := range package_b.PathToRawSpec(path.Join(path.Dir(pathToFile), "./packageB/spec.yaml")) {
if _, ok := res[rawPath]; ok {
// it is not possible to compare functions in golang, so always overwrite the old value
}
res[rawPath] = rawFunc
}
- for rawPath, rawFunc := range externalRef1.PathToRawSpec(path.Join(pathPrefix, "./packageB/spec.yaml")) {
+ for rawPath, rawFunc := range externalRef1.PathToRawSpec(path.Join(path.Dir(pathToFile), "https://raw.githubusercontent.com/swagger-api/swagger-petstore/refs/heads/master/src/main/resources/openapi.yaml")) {
if _, ok := res[rawPath]; ok {
// it is not possible to compare functions in golang, so always overwrite the old value
}
@@ -87,12 +100,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -118,3 +131,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/externalref/imports_test.go b/internal/test/externalref/imports_test.go
index 607def3ffa..7b84c6d0ef 100644
--- a/internal/test/externalref/imports_test.go
+++ b/internal/test/externalref/imports_test.go
@@ -3,8 +3,9 @@ package externalref
import (
"testing"
- packageA "github.com/deepmap/oapi-codegen/internal/test/externalref/packageA"
- packageB "github.com/deepmap/oapi-codegen/internal/test/externalref/packageB"
+ packageA "github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageA"
+ packageB "github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageB"
+ petstore "github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/petstore"
"github.com/stretchr/testify/require"
)
@@ -17,12 +18,15 @@ func TestParameters(t *testing.T) {
}
func TestGetSwagger(t *testing.T) {
- _, err := packageB.GetSwagger()
+ _, err := packageB.GetSpec()
require.Nil(t, err)
- _, err = packageA.GetSwagger()
+ _, err = packageA.GetSpec()
require.Nil(t, err)
- _, err = GetSwagger()
+ _, err = petstore.GetSpec()
+ require.Nil(t, err)
+
+ _, err = GetSpec()
require.Nil(t, err)
}
diff --git a/internal/test/externalref/packageA/config.yaml b/internal/test/externalref/packageA/config.yaml
index 03240de6cd..6ee1a13699 100644
--- a/internal/test/externalref/packageA/config.yaml
+++ b/internal/test/externalref/packageA/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: packagea
generate:
models: true
@@ -5,5 +6,5 @@ generate:
output-options:
skip-prune: true
import-mapping:
- ../packageB/spec.yaml: github.com/deepmap/oapi-codegen/internal/test/externalref/packageB
+ ../packageB/spec.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageB
output: externalref.gen.go
diff --git a/internal/test/externalref/packageA/doc.go b/internal/test/externalref/packageA/doc.go
index 8a7bb68eb1..f05471ffbb 100644
--- a/internal/test/externalref/packageA/doc.go
+++ b/internal/test/externalref/packageA/doc.go
@@ -1,3 +1,3 @@
package packagea
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/externalref/packageA/externalref.gen.go b/internal/test/externalref/packageA/externalref.gen.go
index a890da2ddd..1738872708 100644
--- a/internal/test/externalref/packageA/externalref.gen.go
+++ b/internal/test/externalref/packageA/externalref.gen.go
@@ -1,50 +1,69 @@
// Package packagea provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package packagea
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/url"
"path"
"strings"
- externalRef0 "github.com/deepmap/oapi-codegen/internal/test/externalref/packageB"
"github.com/getkin/kin-openapi/openapi3"
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageB"
)
+// EnrichedUser defines model for EnrichedUser.
+type EnrichedUser struct {
+ ExtraField *string `json:"extra_field,omitempty"`
+ Id string `json:"id"`
+ Roles *[]externalRef0.Role `json:"roles,omitempty"`
+ Username string `json:"username"`
+}
+
// ObjectA defines model for ObjectA.
type ObjectA struct {
Name *string `json:"name,omitempty"`
ObjectB *externalRef0.ObjectB `json:"object_b,omitempty"`
}
-// Base64 encoded, gzipped, json marshaled Swagger object
-var swaggerSpec = []string{
+// StatusPostPayload defines model for StatusPostPayload.
+type StatusPostPayload struct {
+ Reason *string `json:"reason,omitempty"`
+ Status externalRef0.StatusEnum `json:"status"`
+}
- "H4sIAAAAAAAC/4yNQa7CMAxE7zL/LyN1nx1cgCOgtHJpUGtbiVmgyndHSUFsWXmsp3mzY5JNhYmtIu6o",
- "00Jb6vEy3mmyU4taRKlYpg44bdSuPZUQUa1kvsEDpDeuY4P/hWZE/A1f//CWD4f5DHcP+Dy/znhvZZ4F",
- "kR/rGiBKnDQjAgGabKkH8VcAAAD//0SMp77dAAAA",
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "nFPNbsIwDH4Xb8dIiGtuQ+IM2jQuCFUmcSFbmmRJOg1VefcpoQgqOqnsZtf21++n7UDYxllDJgbgHQRx",
+ "pAZLuTReiSPJ90A+96j1qga+7eDZUw0cnmbX21l/OHMoPvFAiyo4ElW5TawD560jHxUVaPqJHqtakZa5",
+ "jSdHwCFEr8wBUmKXJ3b/QSJC2iUGq1K/5P0hmMGGRlBYf13t83A65fN7FpAyj7eIsQ1rG+IaT9qi/K8R",
+ "Z6DNfMQMTxismezDONuprqQ7hFeryyKZtgG+BZSNMsCgzdHt2L2tY8KW5fgGRET1TcBAmb6cirSZDy0e",
+ "qgpl57FAbxhm9Z6+WuVJZpo93G6C0Ze/YMhHydEvz1vdzyM1D9IteVyjR+/xlPucx1+hDlUpCTfr9+Ly",
+ "vjK1BW5arRlYRwadAg6QVcdjOE/SbwAAAP//",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -52,7 +71,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -67,9 +86,7 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
res[pathToFile] = rawSpec
}
- pathPrefix := path.Dir(pathToFile)
-
- for rawPath, rawFunc := range externalRef0.PathToRawSpec(path.Join(pathPrefix, "../packageB/spec.yaml")) {
+ for rawPath, rawFunc := range externalRef0.PathToRawSpec(path.Join(path.Dir(pathToFile), "../packageB/spec.yaml")) {
if _, ok := res[rawPath]; ok {
// it is not possible to compare functions in golang, so always overwrite the old value
}
@@ -78,12 +95,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -109,3 +126,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/externalref/packageA/spec.yaml b/internal/test/externalref/packageA/spec.yaml
index b2386a097e..7b790839e5 100644
--- a/internal/test/externalref/packageA/spec.yaml
+++ b/internal/test/externalref/packageA/spec.yaml
@@ -5,4 +5,23 @@ components:
name:
type: string
object_b:
- $ref: ../packageB/spec.yaml#/components/schemas/ObjectB
\ No newline at end of file
+ $ref: ../packageB/spec.yaml#/components/schemas/ObjectB
+ # Reproduces https://github.com/oapi-codegen/oapi-codegen/issues/2288
+ # allOf extending a cross-file schema should qualify nested type refs
+ EnrichedUser:
+ allOf:
+ - $ref: '../packageB/spec.yaml#/components/schemas/User'
+ - type: object
+ properties:
+ extra_field:
+ type: string
+ # Reproduces https://github.com/oapi-codegen/oapi-codegen/issues/2288 (comment)
+ # allOf extending a cross-file schema whose own definition uses allOf
+ # with local refs — those inner refs must also be qualified.
+ StatusPostPayload:
+ allOf:
+ - $ref: '../packageB/spec.yaml#/components/schemas/StatusV1'
+ - type: object
+ properties:
+ reason:
+ type: string
\ No newline at end of file
diff --git a/internal/test/externalref/packageB/config.yaml b/internal/test/externalref/packageB/config.yaml
index 748a18858b..3dc9b7ce7b 100644
--- a/internal/test/externalref/packageB/config.yaml
+++ b/internal/test/externalref/packageB/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: packageb
generate:
models: true
diff --git a/internal/test/externalref/packageB/doc.go b/internal/test/externalref/packageB/doc.go
index 73641dad9f..0dc18f8255 100644
--- a/internal/test/externalref/packageB/doc.go
+++ b/internal/test/externalref/packageB/doc.go
@@ -1,3 +1,3 @@
package packageb
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/externalref/packageB/externalref.gen.go b/internal/test/externalref/packageB/externalref.gen.go
index 6214b1d9b5..c02df37aac 100644
--- a/internal/test/externalref/packageB/externalref.gen.go
+++ b/internal/test/externalref/packageB/externalref.gen.go
@@ -1,11 +1,11 @@
// Package packageb provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package packageb
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/url"
@@ -15,33 +15,91 @@ import (
"github.com/getkin/kin-openapi/openapi3"
)
+// Defines values for Role.
+const (
+ RoleAdmin Role = "admin"
+ RoleUser Role = "user"
+)
+
+// Valid indicates whether the value is a known member of the Role enum.
+func (e Role) Valid() bool {
+ switch e {
+ case RoleAdmin:
+ return true
+ case RoleUser:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for StatusEnum.
+const (
+ Active StatusEnum = "active"
+ Inactive StatusEnum = "inactive"
+)
+
+// Valid indicates whether the value is a known member of the StatusEnum enum.
+func (e StatusEnum) Valid() bool {
+ switch e {
+ case Active:
+ return true
+ case Inactive:
+ return true
+ default:
+ return false
+ }
+}
+
// ObjectB defines model for ObjectB.
type ObjectB struct {
Name *string `json:"name,omitempty"`
}
-// Base64 encoded, gzipped, json marshaled Swagger object
-var swaggerSpec = []string{
+// Role defines model for Role.
+type Role string
+
+// StatusEnum defines model for StatusEnum.
+type StatusEnum string
+
+// StatusV1 defines model for StatusV1.
+type StatusV1 struct {
+ Status StatusEnum `json:"status"`
+}
+
+// User defines model for User.
+type User struct {
+ Id string `json:"id"`
+ Roles *[]Role `json:"roles,omitempty"`
+ Username string `json:"username"`
+}
- "H4sIAAAAAAAC/yTJwQ0CMQxE0V7mnApypAFqCNHAGm1sKzYHtNreUZa5zJfegW7DTakZqAeibxztyvvj",
- "zZ63lT7NOVN4gbbB9fl1oiJyir5wrhWIPg1VP/teYE5tLqhAgbfc4i/nLwAA//8neaWPdgAAAA==",
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "hFFNS8NAFPwvo8eF4HWPgueCopfSw5q82JX9cvetUMr+d3lrsLG1eMqEmcmbmRwxRp9ioMAF+ogy7smb",
+ "Djev7zTyvcCUY6LMljoRjCd58iERNApnG97QWlN4jK5TFKqH3sJM3gYo1EIZO3VuUXhiw7U8dPnKNrL9",
+ "JCjYsMDr3pc7cRrnNjP09jxr6RpBt5lmaNwMp8LD0nZYpZAWmT6qzTRJlOUDp/uxz4K2awrPUutiHzv9",
+ "sY5Cjm7hmfy/kfqS7eeqydkc5F2WvPYDfie3E1byywKit2GO0KE6pxATBZMsNKCQDO/LN9O+AgAA//8=",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -49,7 +107,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -67,12 +125,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -98,3 +156,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/externalref/packageB/spec.yaml b/internal/test/externalref/packageB/spec.yaml
index 6f90634711..95a29f9b04 100644
--- a/internal/test/externalref/packageB/spec.yaml
+++ b/internal/test/externalref/packageB/spec.yaml
@@ -4,3 +4,31 @@ components:
properties:
name:
type: string
+ Role:
+ type: string
+ enum: [admin, user]
+ User:
+ type: object
+ required: [id, username]
+ properties:
+ id:
+ type: string
+ username:
+ type: string
+ roles:
+ type: array
+ items:
+ $ref: '#/components/schemas/Role'
+ StatusEnum:
+ type: string
+ enum: [active, inactive]
+ # StatusV1 uses allOf internally with a local ref to StatusEnum.
+ # This exercises the case where an external schema's own allOf
+ # sub-schemas contain local refs that must be rewritten.
+ StatusV1:
+ allOf:
+ - type: object
+ required: [status]
+ properties:
+ status:
+ $ref: '#/components/schemas/StatusEnum'
diff --git a/internal/test/externalref/petstore/config.yaml b/internal/test/externalref/petstore/config.yaml
new file mode 100644
index 0000000000..6ee1a13699
--- /dev/null
+++ b/internal/test/externalref/petstore/config.yaml
@@ -0,0 +1,10 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: packagea
+generate:
+ models: true
+ embedded-spec: true
+output-options:
+ skip-prune: true
+import-mapping:
+ ../packageB/spec.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageB
+output: externalref.gen.go
diff --git a/internal/test/externalref/petstore/doc.go b/internal/test/externalref/petstore/doc.go
new file mode 100644
index 0000000000..f05471ffbb
--- /dev/null
+++ b/internal/test/externalref/petstore/doc.go
@@ -0,0 +1,3 @@
+package packagea
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/externalref/petstore/externalref.gen.go b/internal/test/externalref/petstore/externalref.gen.go
new file mode 100644
index 0000000000..d70f4bec71
--- /dev/null
+++ b/internal/test/externalref/petstore/externalref.gen.go
@@ -0,0 +1,409 @@
+// Package packagea provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package packagea
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "fmt"
+ "net/url"
+ "path"
+ "strings"
+ "time"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageB"
+)
+
+const (
+ Api_keyScopes apiKeyContextKey = "api_key.Scopes"
+ Petstore_authScopes petstoreAuthContextKey = "petstore_auth.Scopes"
+)
+
+// Defines values for OrderStatus.
+const (
+ Approved OrderStatus = "approved"
+ Delivered OrderStatus = "delivered"
+ Placed OrderStatus = "placed"
+)
+
+// Valid indicates whether the value is a known member of the OrderStatus enum.
+func (e OrderStatus) Valid() bool {
+ switch e {
+ case Approved:
+ return true
+ case Delivered:
+ return true
+ case Placed:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for PetStatus.
+const (
+ PetStatusAvailable PetStatus = "available"
+ PetStatusPending PetStatus = "pending"
+ PetStatusSold PetStatus = "sold"
+)
+
+// Valid indicates whether the value is a known member of the PetStatus enum.
+func (e PetStatus) Valid() bool {
+ switch e {
+ case PetStatusAvailable:
+ return true
+ case PetStatusPending:
+ return true
+ case PetStatusSold:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for FindPetsByStatusParamsStatus.
+const (
+ FindPetsByStatusParamsStatusAvailable FindPetsByStatusParamsStatus = "available"
+ FindPetsByStatusParamsStatusPending FindPetsByStatusParamsStatus = "pending"
+ FindPetsByStatusParamsStatusSold FindPetsByStatusParamsStatus = "sold"
+)
+
+// Valid indicates whether the value is a known member of the FindPetsByStatusParamsStatus enum.
+func (e FindPetsByStatusParamsStatus) Valid() bool {
+ switch e {
+ case FindPetsByStatusParamsStatusAvailable:
+ return true
+ case FindPetsByStatusParamsStatusPending:
+ return true
+ case FindPetsByStatusParamsStatusSold:
+ return true
+ default:
+ return false
+ }
+}
+
+// Address defines model for Address.
+type Address struct {
+ City *string `json:"city,omitempty"`
+ State *string `json:"state,omitempty"`
+ Street *string `json:"street,omitempty"`
+ Zip *string `json:"zip,omitempty"`
+}
+
+// ApiResponse defines model for ApiResponse.
+type ApiResponse struct {
+ Code *int32 `json:"code,omitempty"`
+ Message *string `json:"message,omitempty"`
+ Type *string `json:"type,omitempty"`
+}
+
+// Category defines model for Category.
+type Category struct {
+ Id *int64 `json:"id,omitempty"`
+ Name *string `json:"name,omitempty"`
+}
+
+// Customer defines model for Customer.
+type Customer struct {
+ Address *[]Address `json:"address,omitempty"`
+ Id *int64 `json:"id,omitempty"`
+ Username *string `json:"username,omitempty"`
+}
+
+// Order defines model for Order.
+type Order struct {
+ Complete *bool `json:"complete,omitempty"`
+ Id *int64 `json:"id,omitempty"`
+ PetId *int64 `json:"petId,omitempty"`
+ Quantity *int32 `json:"quantity,omitempty"`
+ ShipDate *time.Time `json:"shipDate,omitempty"`
+
+ // Status Order Status
+ Status *OrderStatus `json:"status,omitempty"`
+}
+
+// OrderStatus Order Status
+type OrderStatus string
+
+// Pet defines model for Pet.
+type Pet struct {
+ Category *Category `json:"category,omitempty"`
+ Id *int64 `json:"id,omitempty"`
+ Name string `json:"name"`
+ PhotoUrls []string `json:"photoUrls"`
+
+ // Status pet status in the store
+ Status *PetStatus `json:"status,omitempty"`
+ Tags *[]Tag `json:"tags,omitempty"`
+}
+
+// PetStatus pet status in the store
+type PetStatus string
+
+// Tag defines model for Tag.
+type Tag struct {
+ Id *int64 `json:"id,omitempty"`
+ Name *string `json:"name,omitempty"`
+}
+
+// User defines model for User.
+type User struct {
+ Email *string `json:"email,omitempty"`
+ FirstName *string `json:"firstName,omitempty"`
+ Id *int64 `json:"id,omitempty"`
+ LastName *string `json:"lastName,omitempty"`
+ Password *string `json:"password,omitempty"`
+ Phone *string `json:"phone,omitempty"`
+
+ // UserStatus User Status
+ UserStatus *int32 `json:"userStatus,omitempty"`
+ Username *string `json:"username,omitempty"`
+}
+
+// UserArray defines model for UserArray.
+type UserArray = []User
+
+// apiKeyContextKey is the context key for api_key security scheme
+type apiKeyContextKey string
+
+// petstoreAuthContextKey is the context key for petstore_auth security scheme
+type petstoreAuthContextKey string
+
+// FindPetsByStatusParams defines parameters for FindPetsByStatus.
+type FindPetsByStatusParams struct {
+ // Status Status values that need to be considered for filter
+ Status *FindPetsByStatusParamsStatus `form:"status,omitempty" json:"status,omitempty"`
+}
+
+// FindPetsByStatusParamsStatus defines parameters for FindPetsByStatus.
+type FindPetsByStatusParamsStatus string
+
+// FindPetsByTagsParams defines parameters for FindPetsByTags.
+type FindPetsByTagsParams struct {
+ // Tags Tags to filter by
+ Tags *[]string `form:"tags,omitempty" json:"tags,omitempty"`
+}
+
+// DeletePetParams defines parameters for DeletePet.
+type DeletePetParams struct {
+ ApiKey *string `json:"api_key,omitempty"`
+}
+
+// UpdatePetWithFormParams defines parameters for UpdatePetWithForm.
+type UpdatePetWithFormParams struct {
+ // Name Name of pet that needs to be updated
+ Name *string `form:"name,omitempty" json:"name,omitempty"`
+
+ // Status Status of pet that needs to be updated
+ Status *string `form:"status,omitempty" json:"status,omitempty"`
+}
+
+// UploadFileParams defines parameters for UploadFile.
+type UploadFileParams struct {
+ // AdditionalMetadata Additional Metadata
+ AdditionalMetadata *string `form:"additionalMetadata,omitempty" json:"additionalMetadata,omitempty"`
+}
+
+// CreateUsersWithListInputJSONBody defines parameters for CreateUsersWithListInput.
+type CreateUsersWithListInputJSONBody = []User
+
+// LoginUserParams defines parameters for LoginUser.
+type LoginUserParams struct {
+ // Username The user name for login
+ Username *string `form:"username,omitempty" json:"username,omitempty"`
+
+ // Password The password for login in clear text
+ Password *string `form:"password,omitempty" json:"password,omitempty"`
+}
+
+// AddPetJSONRequestBody defines body for AddPet for application/json ContentType.
+type AddPetJSONRequestBody = Pet
+
+// AddPetFormdataRequestBody defines body for AddPet for application/x-www-form-urlencoded ContentType.
+type AddPetFormdataRequestBody = Pet
+
+// UpdatePetJSONRequestBody defines body for UpdatePet for application/json ContentType.
+type UpdatePetJSONRequestBody = Pet
+
+// UpdatePetFormdataRequestBody defines body for UpdatePet for application/x-www-form-urlencoded ContentType.
+type UpdatePetFormdataRequestBody = Pet
+
+// PlaceOrderJSONRequestBody defines body for PlaceOrder for application/json ContentType.
+type PlaceOrderJSONRequestBody = Order
+
+// PlaceOrderFormdataRequestBody defines body for PlaceOrder for application/x-www-form-urlencoded ContentType.
+type PlaceOrderFormdataRequestBody = Order
+
+// CreateUserJSONRequestBody defines body for CreateUser for application/json ContentType.
+type CreateUserJSONRequestBody = User
+
+// CreateUserFormdataRequestBody defines body for CreateUser for application/x-www-form-urlencoded ContentType.
+type CreateUserFormdataRequestBody = User
+
+// CreateUsersWithListInputJSONRequestBody defines body for CreateUsersWithListInput for application/json ContentType.
+type CreateUsersWithListInputJSONRequestBody = CreateUsersWithListInputJSONBody
+
+// UpdateUserJSONRequestBody defines body for UpdateUser for application/json ContentType.
+type UpdateUserJSONRequestBody = User
+
+// UpdateUserFormdataRequestBody defines body for UpdateUser for application/x-www-form-urlencoded ContentType.
+type UpdateUserFormdataRequestBody = User
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "7Fv/b+M2sv9X+NQH9BVwLCfZvr0aOKDZzbbIXbobNLt3PSRBQUtjiV2JVEnKjhvkfz8MScn6astOnLui",
+ "3R92tRLJGc585ivpBy8QaSY4cK286YMn4dcclH4jQgbmxRVo/CcQXAM3jzTLEhZQzQT3f1GC4zsVxJBS",
+ "fPpfCXNv6n3hr9f17Vfl41qPj6PaCvdpsusCjyMvBBVIluEK3hR5JGL2CwSa6JhqwgFCRbQgMyA0DCHE",
+ "Zx0DUVpI8B5H3icF8kxKutppb0xDqrbxiEsjCb3KwJt61FDpYPqSKU3EnOQKpOPeCMetg2TOwlCCMo+Z",
+ "FBlI7ZQSMG04h3uaZgmSuaKJIGeJFl5JWWnJeISsKE011Me/PeseKMHqez3y1elrcrnSWvCuGb+xrD78",
+ "m1enk+P2yLVA3FZHntM8p6mRk9srjjzL2I+gMsEVdOxdhObtXMiUam/qMa5PT9YUGdcQWRWkoBSNzOgW",
+ "4/bFw858fvFFCHOaJ1ZZb6mGSMhVm00W1uRyPKox/P+vOhm2NKriPBeR2kOaQcGXYTJXWqQg20zSNcAG",
+ "YbsAZBPePcoEZH0paZZB6E21zAHZaUpmgn8GiQdNpS2iOcRRvtpHSIVccOgHGXZJCIWQgK5CZSZEApR7",
+ "XVsZtI0M9EVj4jd/ef36ZNDkX3PKddP8X4+GmIOKWXbuPEE5PKQajjRLoc9x5EYOdd9lhEWu7deRBzxP",
+ "vemNlyU0gNAzDl6KhXkMIWELkBB6d6OK0iojdlWbMJrCcS42NTRWMclNWC5Nd289tqEYiihinZLMYqHF",
+ "J5nUba0+rLnRYk5VJg17axlXn8Yy0MR+I4xXYuFaeXRBWUJnCb7LgIeWIyUSo7m2/6TRcL/xkUbe0D08",
+ "jkwSwhAy0xsri6r87rbhI3NZBhLtccs7KHdXdGpqR5k0oEUeUsqSOmZ+ETH/1rwfByLtws6cSaXft8D2",
+ "NxF3huT9wJzQTho0BdWJZ6rUUsg6Ke/45PTV1z3w5zBwLHr56x4Yo1Qrfqcnuvb4v+7woWMwutrdEeUm",
+ "0zNWB0EumV5dI95daM3Yz5/BeCGGnMdAQ0OlCJHu+9oqMvZ3WLn4YIzzZ5rr2MA1EUuL3hTTU2ZT1VzH",
+ "QrLfTLKKXmLqxVpnaur7xQKnY7WkUQRyzIQvcIJfzEKbUoHIwGX9NJziLG9qnslK5JKYFxjAmYbiaypC",
+ "Nl+ZT+hIzDgaBCLnLjMvRIaETuwruNco+ORcBB0q/Y7xkIhck1RIIHSGj9eWbW/k5eXGpr6/3o3BOZ+L",
+ "In2nga6YF8pSA02/rU+o0/0YM0WYIpQoAwWCVcQ1io1cg1yAJDOqICTCussPGfCzqwtyOp4QlUHA5q5O",
+ "GBPyL5GTgHIyb2/llru9EKrJTWsfd//XevXVmFxYkjpmMiRMgzSEsFjA19aVCwkjsoQvF0DUkukgXlc5",
+ "ISgWITdSaWICLQ3i/7nlBZtcLEkMSUYwGKQmDpt5uL1lDDoGSZj+UpHZiqT0M+MRCWLKI1BrCnPGmWGK",
+ "aQXJnAhZfMP8fHzLP2IhtqSrEVkyHRPMMJBfw0CTKOMkAg6SJiNCeUjgPhMKiBIpFJvmsCRzoDqXYID3",
+ "4ez6dHzLb/k1DsoVzPOEJIx/VtNbfkRuPsZVhUrIhGJayJUVOBpJxHScz9DnFsI/ohkrnwsb+qpcTolc",
+ "Bpbhyv7nuPMqsZ0p+LNEzPyUKg3SVzLwU8q4L8HSU77IgNOMjVc0Tb7yRl7CAnCVkfMlZxkNYiAn40nT",
+ "YpbL5Ziar2MhI99NVf7lxdt376/fHZ2MJ+NYp4mJziBT9WGO4GcBdFmdb4b46LOYNs6zAPeV2ws5qhqK",
+ "N/IWIJW1t+PxZHz8Ggm5DXlT73Q8GaOvzqiOjWtA12WiplC67SrOwpBQAwW0gVpNb1a1doK5NQ7F7HBU",
+ "aWisDtvHOFoul0cYhY5ymQBHMwj/862RtxKohorUGtnfOtUy2Re+sIW3UcfJZPJf3/y5zoMAlEL7LyGA",
+ "KHs1+bqNoAu+oAkLCeNZ7totLnR705uHZuS9qca+USVK3j3ejTyVpynFOmMzLm2ifGPS0juM7nkHsj9l",
+ "oVETJ3DPlEaXi0vNVuQibGHbDv4T3m25Add/NJBP+kF+cU5UjoxAaMe+ao/FsMWFJnOR87DXbP6B69kk",
+ "BO4DsK+fy3q6sd+ynMeRiQ4+JllvVusCIYIOe/ohTzTDpM7VvAua5KBM8jEDgtkHCyG0qUkg0pQSBRmV",
+ "VENIbP6vWmaHiSrGuZI4xi1JU9AglRFAQ2c10mVj2vWlA8EVC0FCaFKIOUu0SXjhPktMhxOhOrK1w685",
+ "yNW6dFAF+TWkip7ktFbG71Xao3KeZB+DOgIG560m+RbDecLKLYtS+1hUFU3Phn/ElTIZFPr7Urmb0P/R",
+ "NV82Yx9X2AnyY/JJmWnHI/z7xPx9alNcMJY53mAVhqktNoFj0AAs3MlsNQzx2i7dgYSevn6p9z/B3Atm",
+ "TaODItkprRvHD6YJ/mi5KxrsdWSdm/c2zWmAaktHZS3kVkunK/4x45MdGw6AWJGsl7Yd+2YiUSW0tcPW",
+ "QuJG3WAS87y6sdJUhHYG11G3K/kRdC656ZEwHiXg5tb19D3oK9BvVkZCG63/4hzLeZcjS7P2y8n795Dm",
+ "qRdK85qYKpuVN3doIk8w/7JsOe8qfVxV31PO/JPp+Dsh0x1g1Dztz81a4eFQ1XIg76ltUg1hpxHV3NHG",
+ "Dt7KpZT7ketIG7elfi9YQ1sUOP9UK+BsyoKqISHVdFtI8fMsETS8SN3Jfx/ocNB3zObEg52WlfALwuss",
+ "DE2fkSbkB9DUCaBLvbQcWRm4RdVDegci0KCPlJZA07qDK7czY5zKrhP4x0PW2tVbIoN96TOh1WJMEdPM",
+ "RqB1gdJ2dxlfANfuQHpLlE1phmBzZUYgQttyd2f+DFRX8L0oCTxR2GsEXdUOLQccrdUPyvbWRjUO1eRd",
+ "iMj6BrtfBt0Fk+36VFUgyrsdnW3lq4QGRYvUDG32j+oiN8PtdZHD9N8+lBccnrED17PoLklLscRBrbok",
+ "Mjw3GhajSiw5dXOna6xum0lxD4T8B/NPq25pHGgKSSz1QkhEyxVx1kIuzpWNaCa/J7f5ZHIakOPJZDIm",
+ "Z3ylY8YjQmdiAeYlEZJwwd1snJok7rRM28MokFLItmewCX+B0wEhDhFvRdJKLOxWe9IqJ5OXLI+GpLz2",
+ "jlIj6W2UQyTLZRBTVWy8mbgWOOgpj/bR9F/J16hS8x/U8Jh8MAeurk1YV2/ZbFXjLs9vtji88OpR7hzM",
+ "6fFLKvcQDuM5HNuL1WObwWkLqWHQRBeVq03hzVx0CNDf8WRlrFlwMA2aGEgiogjQT5p7yG2U2fNDd0Hm",
+ "EMHOXpd+3ljXveYuiPikugFhxRHWL203wF324g8qoefYTX9SVkLRnR/n7oaUA5/57xp7fmBGYf1+ydSG",
+ "A3y7miJJ5e6785ERWwC38ZoUFwT7oKgKShcmvO8PzCdd6D9kFnQ4nfedJFZQuydIBqu1D0WJiBivVEl1",
+ "9V/iV+eINp8xxBavBEOYSe/swt1lc3kpcKdGDNIorkCuSaAbDRKgkmi41z0Ey5uTuzRidsVW+yrjRiC1",
+ "6vZBnmLkWvCGw5+O3t1nTII6OptrG47qS5hDXsbJp49vyTIGTrT4DJyAneV1JhQbLqc/jryfjn7E75cs",
+ "ZR24DWiSYMEoSWwuKSaJWEJYxD3n0LqTmM4i10hlY+AvoOSXyFjnATV7uRSRshBlvLgtslIa0s3GIezN",
+ "kT7rELku43R3ONrZsA2jItckyKUErhvpAlGglEVCH9sPhVA2lkxPSlFsKj/UMxinsFuBU3ER/Unw9lbq",
+ "AORsTxzNBegtRU13sB51A+d7MKh5s3rvLtrvJ0BXRNgTZKR4XDs2JgeU7O8j7u5VSjwTLr4Hbe11tlpH",
+ "xi6EdN5Ne5Jx2rb+EOOs4+qwdvlHL2M6rs25cFT/meyzBRJHsKeMMG1guShwYW8w+zRj/uLUQ425CU3C",
+ "7xYg1w2zXNufI1zZ3v0OvzrY/DuD6s+K2uczZuuI1vIKtKnXd+TA8Y/sF03n7RwVamo1FwolKLesE3vt",
+ "Zyt3j/8OAAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ for rawPath, rawFunc := range externalRef0.PathToRawSpec(path.Join(path.Dir(pathToFile), "../packageB/spec.yaml")) {
+ if _, ok := res[rawPath]; ok {
+ // it is not possible to compare functions in golang, so always overwrite the old value
+ }
+ res[rawPath] = rawFunc
+ }
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/externalref/petstore/spec.yaml b/internal/test/externalref/petstore/spec.yaml
new file mode 100644
index 0000000000..2d1dcd41d5
--- /dev/null
+++ b/internal/test/externalref/petstore/spec.yaml
@@ -0,0 +1 @@
+{"openapi":"3.0.2","info":{"title":"Swagger Petstore - OpenAPI 3.0","description":"This is a sample Pet Store Server based on the OpenAPI 3.0 specification. You can find out more about\nSwagger at [http://swagger.io](http://swagger.io). In the third iteration of the pet store, we've switched to the design first approach!\nYou can now help us improve the API whether it's by making changes to the definition itself or to the code.\nThat way, with time, we can improve the API in general, and expose some of the new features in OAS3.\n\nSome useful links:\n- [The Pet Store repository](https://github.com/swagger-api/swagger-petstore)\n- [The source API definition for the Pet Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/resources/openapi.yaml)","termsOfService":"http://swagger.io/terms/","contact":{"email":"apiteam@swagger.io"},"license":{"name":"Apache 2.0","url":"http://www.apache.org/licenses/LICENSE-2.0.html"},"version":"1.0.17"},"externalDocs":{"description":"Find out more about Swagger","url":"http://swagger.io"},"servers":[{"url":"/api/v3"}],"tags":[{"name":"pet","description":"Everything about your Pets","externalDocs":{"description":"Find out more","url":"http://swagger.io"}},{"name":"store","description":"Access to Petstore orders","externalDocs":{"description":"Find out more about our store","url":"http://swagger.io"}},{"name":"user","description":"Operations about user"}],"paths":{"/pet":{"put":{"tags":["pet"],"summary":"Update an existing pet","description":"Update an existing pet by Id","operationId":"updatePet","requestBody":{"description":"Update an existent pet in the store","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Pet"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Pet"}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Pet"}}},"required":true},"responses":{"200":{"description":"Successful operation","content":{"application/xml":{"schema":{"$ref":"#/components/schemas/Pet"}},"application/json":{"schema":{"$ref":"#/components/schemas/Pet"}}}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"},"405":{"description":"Validation exception"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]},"post":{"tags":["pet"],"summary":"Add a new pet to the store","description":"Add a new pet to the store","operationId":"addPet","requestBody":{"description":"Create a new pet in the store","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Pet"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Pet"}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Pet"}}},"required":true},"responses":{"200":{"description":"Successful operation","content":{"application/xml":{"schema":{"$ref":"#/components/schemas/Pet"}},"application/json":{"schema":{"$ref":"#/components/schemas/Pet"}}}},"405":{"description":"Invalid input"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/findByStatus":{"get":{"tags":["pet"],"summary":"Finds Pets by status","description":"Multiple status values can be provided with comma separated strings","operationId":"findPetsByStatus","parameters":[{"name":"status","in":"query","description":"Status values that need to be considered for filter","required":false,"explode":true,"schema":{"type":"string","default":"available","enum":["available","pending","sold"]}}],"responses":{"200":{"description":"successful operation","content":{"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Pet"}}},"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Pet"}}}}},"400":{"description":"Invalid status value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/findByTags":{"get":{"tags":["pet"],"summary":"Finds Pets by tags","description":"Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.","operationId":"findPetsByTags","parameters":[{"name":"tags","in":"query","description":"Tags to filter by","required":false,"explode":true,"schema":{"type":"array","items":{"type":"string"}}}],"responses":{"200":{"description":"successful operation","content":{"application/xml":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Pet"}}},"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Pet"}}}}},"400":{"description":"Invalid tag value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/{petId}":{"get":{"tags":["pet"],"summary":"Find pet by ID","description":"Returns a single pet","operationId":"getPetById","parameters":[{"name":"petId","in":"path","description":"ID of pet to return","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"successful operation","content":{"application/xml":{"schema":{"$ref":"#/components/schemas/Pet"}},"application/json":{"schema":{"$ref":"#/components/schemas/Pet"}}}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Pet not found"}},"security":[{"api_key":[]},{"petstore_auth":["write:pets","read:pets"]}]},"post":{"tags":["pet"],"summary":"Updates a pet in the store with form data","description":"","operationId":"updatePetWithForm","parameters":[{"name":"petId","in":"path","description":"ID of pet that needs to be updated","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"name","in":"query","description":"Name of pet that needs to be updated","schema":{"type":"string"}},{"name":"status","in":"query","description":"Status of pet that needs to be updated","schema":{"type":"string"}}],"responses":{"405":{"description":"Invalid input"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]},"delete":{"tags":["pet"],"summary":"Deletes a pet","description":"","operationId":"deletePet","parameters":[{"name":"api_key","in":"header","description":"","required":false,"schema":{"type":"string"}},{"name":"petId","in":"path","description":"Pet id to delete","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"400":{"description":"Invalid pet value"}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/pet/{petId}/uploadImage":{"post":{"tags":["pet"],"summary":"uploads an image","description":"","operationId":"uploadFile","parameters":[{"name":"petId","in":"path","description":"ID of pet to update","required":true,"schema":{"type":"integer","format":"int64"}},{"name":"additionalMetadata","in":"query","description":"Additional Metadata","required":false,"schema":{"type":"string"}}],"requestBody":{"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"responses":{"200":{"description":"successful operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiResponse"}}}}},"security":[{"petstore_auth":["write:pets","read:pets"]}]}},"/store/inventory":{"get":{"tags":["store"],"summary":"Returns pet inventories by status","description":"Returns a map of status codes to quantities","operationId":"getInventory","responses":{"200":{"description":"successful operation","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"integer","format":"int32"}}}}}},"security":[{"api_key":[]}]}},"/store/order":{"post":{"tags":["store"],"summary":"Place an order for a pet","description":"Place a new order in the store","operationId":"placeOrder","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Order"}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/Order"}}}},"responses":{"200":{"description":"successful operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}}},"405":{"description":"Invalid input"}}}},"/store/order/{orderId}":{"get":{"tags":["store"],"summary":"Find purchase order by ID","description":"For valid response try integer IDs with value <= 5 or > 10. Other values will generate exceptions.","operationId":"getOrderById","parameters":[{"name":"orderId","in":"path","description":"ID of order that needs to be fetched","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"200":{"description":"successful operation","content":{"application/xml":{"schema":{"$ref":"#/components/schemas/Order"}},"application/json":{"schema":{"$ref":"#/components/schemas/Order"}}}},"400":{"description":"Invalid ID supplied"},"404":{"description":"Order not found"}}},"delete":{"tags":["store"],"summary":"Delete purchase order by ID","description":"For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors","operationId":"deleteOrder","parameters":[{"name":"orderId","in":"path","description":"ID of the order that needs to be deleted","required":true,"schema":{"type":"integer","format":"int64"}}],"responses":{"400":{"description":"Invalid ID supplied"},"404":{"description":"Order not found"}}}},"/user":{"post":{"tags":["user"],"summary":"Create user","description":"This can only be done by the logged in user.","operationId":"createUser","requestBody":{"description":"Created user object","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}},"application/xml":{"schema":{"$ref":"#/components/schemas/User"}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/User"}}}},"responses":{"default":{"description":"successful operation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}},"application/xml":{"schema":{"$ref":"#/components/schemas/User"}}}}}}},"/user/createWithList":{"post":{"tags":["user"],"summary":"Creates list of users with given input array","description":"Creates list of users with given input array","operationId":"createUsersWithListInput","requestBody":{"content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/User"}}}}},"responses":{"200":{"description":"Successful operation","content":{"application/xml":{"schema":{"$ref":"#/components/schemas/User"}},"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"default":{"description":"successful operation"}}}},"/user/login":{"get":{"tags":["user"],"summary":"Logs user into the system","description":"","operationId":"loginUser","parameters":[{"name":"username","in":"query","description":"The user name for login","required":false,"schema":{"type":"string"}},{"name":"password","in":"query","description":"The password for login in clear text","required":false,"schema":{"type":"string"}}],"responses":{"200":{"description":"successful operation","headers":{"X-Rate-Limit":{"description":"calls per hour allowed by the user","schema":{"type":"integer","format":"int32"}},"X-Expires-After":{"description":"date in UTC when token expires","schema":{"type":"string","format":"date-time"}}},"content":{"application/xml":{"schema":{"type":"string"}},"application/json":{"schema":{"type":"string"}}}},"400":{"description":"Invalid username/password supplied"}}}},"/user/logout":{"get":{"tags":["user"],"summary":"Logs out current logged in user session","description":"","operationId":"logoutUser","parameters":[],"responses":{"default":{"description":"successful operation"}}}},"/user/{username}":{"get":{"tags":["user"],"summary":"Get user by user name","description":"","operationId":"getUserByName","parameters":[{"name":"username","in":"path","description":"The name that needs to be fetched. Use user1 for testing. ","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"successful operation","content":{"application/xml":{"schema":{"$ref":"#/components/schemas/User"}},"application/json":{"schema":{"$ref":"#/components/schemas/User"}}}},"400":{"description":"Invalid username supplied"},"404":{"description":"User not found"}}},"put":{"tags":["user"],"summary":"Update user","description":"This can only be done by the logged in user.","operationId":"updateUser","parameters":[{"name":"username","in":"path","description":"name that need to be deleted","required":true,"schema":{"type":"string"}}],"requestBody":{"description":"Update an existent user in the store","content":{"application/json":{"schema":{"$ref":"#/components/schemas/User"}},"application/xml":{"schema":{"$ref":"#/components/schemas/User"}},"application/x-www-form-urlencoded":{"schema":{"$ref":"#/components/schemas/User"}}}},"responses":{"default":{"description":"successful operation"}}},"delete":{"tags":["user"],"summary":"Delete user","description":"This can only be done by the logged in user.","operationId":"deleteUser","parameters":[{"name":"username","in":"path","description":"The name that needs to be deleted","required":true,"schema":{"type":"string"}}],"responses":{"400":{"description":"Invalid username supplied"},"404":{"description":"User not found"}}}}},"components":{"schemas":{"Order":{"type":"object","properties":{"id":{"type":"integer","format":"int64","example":10},"petId":{"type":"integer","format":"int64","example":198772},"quantity":{"type":"integer","format":"int32","example":7},"shipDate":{"type":"string","format":"date-time"},"status":{"type":"string","description":"Order Status","example":"approved","enum":["placed","approved","delivered"]},"complete":{"type":"boolean"}},"xml":{"name":"order"}},"Customer":{"type":"object","properties":{"id":{"type":"integer","format":"int64","example":100000},"username":{"type":"string","example":"fehguy"},"address":{"type":"array","xml":{"name":"addresses","wrapped":true},"items":{"$ref":"#/components/schemas/Address"}}},"xml":{"name":"customer"}},"Address":{"type":"object","properties":{"street":{"type":"string","example":"437 Lytton"},"city":{"type":"string","example":"Palo Alto"},"state":{"type":"string","example":"CA"},"zip":{"type":"string","example":"94301"}},"xml":{"name":"address"}},"Category":{"type":"object","properties":{"id":{"type":"integer","format":"int64","example":1},"name":{"type":"string","example":"Dogs"}},"xml":{"name":"category"}},"User":{"type":"object","properties":{"id":{"type":"integer","format":"int64","example":10},"username":{"type":"string","example":"theUser"},"firstName":{"type":"string","example":"John"},"lastName":{"type":"string","example":"James"},"email":{"type":"string","example":"john@email.com"},"password":{"type":"string","example":"12345"},"phone":{"type":"string","example":"12345"},"userStatus":{"type":"integer","description":"User Status","format":"int32","example":1}},"xml":{"name":"user"}},"Tag":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}},"xml":{"name":"tag"}},"Pet":{"required":["name","photoUrls"],"type":"object","properties":{"id":{"type":"integer","format":"int64","example":10},"name":{"type":"string","example":"doggie"},"category":{"$ref":"#/components/schemas/Category"},"photoUrls":{"type":"array","xml":{"wrapped":true},"items":{"type":"string","xml":{"name":"photoUrl"}}},"tags":{"type":"array","xml":{"wrapped":true},"items":{"$ref":"#/components/schemas/Tag"}},"status":{"type":"string","description":"pet status in the store","enum":["available","pending","sold"]}},"xml":{"name":"pet"}},"ApiResponse":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"type":{"type":"string"},"message":{"type":"string"}},"xml":{"name":"##default"}}},"requestBodies":{"Pet":{"description":"Pet object that needs to be added to the store","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Pet"}},"application/xml":{"schema":{"$ref":"#/components/schemas/Pet"}}}},"UserArray":{"description":"List of user object","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/User"}}}}}},"securitySchemes":{"petstore_auth":{"type":"oauth2","flows":{"implicit":{"authorizationUrl":"https://petstore3.swagger.io/oauth/authorize","scopes":{"write:pets":"modify pets in your account","read:pets":"read your pets"}}}},"api_key":{"type":"apiKey","name":"api_key","in":"header"}}}}
\ No newline at end of file
diff --git a/internal/test/externalref/spec.yaml b/internal/test/externalref/spec.yaml
index ba0ae6555f..a0540389f9 100644
--- a/internal/test/externalref/spec.yaml
+++ b/internal/test/externalref/spec.yaml
@@ -11,3 +11,5 @@ components:
$ref: ./packageB/spec.yaml#/components/schemas/ObjectB
object_c:
$ref: ./object_c.json
+ pet:
+ $ref: https://raw.githubusercontent.com/swagger-api/swagger-petstore/refs/heads/master/src/main/resources/openapi.yaml#/components/schemas/Pet
diff --git a/internal/test/filter/doc.go b/internal/test/filter/doc.go
new file mode 100644
index 0000000000..a9051b1015
--- /dev/null
+++ b/internal/test/filter/doc.go
@@ -0,0 +1,4 @@
+package client
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --package=filtertags --generate=server -o tags/server.gen.go -include-tags included-tag1,included-tag2 server.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --package=filteroperations --generate=server -o operations/server.gen.go -include-operation-ids included-operation1,included-operation2 server.yaml
diff --git a/internal/test/filter/operations/server.gen.go b/internal/test/filter/operations/server.gen.go
new file mode 100644
index 0000000000..157483ed85
--- /dev/null
+++ b/internal/test/filter/operations/server.gen.go
@@ -0,0 +1,93 @@
+// Package filteroperations provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package filteroperations
+
+import (
+ "github.com/labstack/echo/v4"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /included1)
+ IncludedOperation1(ctx echo.Context) error
+
+ // (GET /included2)
+ IncludedOperation2(ctx echo.Context) error
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+// IncludedOperation1 converts echo context to params.
+func (w *ServerInterfaceWrapper) IncludedOperation1(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.IncludedOperation1(ctx)
+ return err
+}
+
+// IncludedOperation2 converts echo context to params.
+func (w *ServerInterfaceWrapper) IncludedOperation2(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.IncludedOperation2(ctx)
+ return err
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+}
+
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
+}
+
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.GET(options.BaseURL+"/included1", wrapper.IncludedOperation1, options.OperationMiddlewares["included-operation1"]...)
+ router.GET(options.BaseURL+"/included2", wrapper.IncludedOperation2, options.OperationMiddlewares["included-operation2"]...)
+
+}
diff --git a/internal/test/filter/operations/server_test.go b/internal/test/filter/operations/server_test.go
new file mode 100644
index 0000000000..2dc33642b3
--- /dev/null
+++ b/internal/test/filter/operations/server_test.go
@@ -0,0 +1,26 @@
+package filteroperations
+
+import (
+ "testing"
+
+ "github.com/labstack/echo/v4"
+ "github.com/stretchr/testify/assert"
+)
+
+type server struct{}
+
+func (s server) IncludedOperation1(ctx echo.Context) error {
+ return nil
+}
+
+func (s server) IncludedOperation2(ctx echo.Context) error {
+ return nil
+}
+
+func TestServer(t *testing.T) {
+ assert := assert.New(t)
+
+ var s ServerInterface = server{}
+ assert.NoError(s.IncludedOperation1(nil))
+ assert.NoError(s.IncludedOperation2(nil))
+}
diff --git a/internal/test/filter/server.yaml b/internal/test/filter/server.yaml
new file mode 100644
index 0000000000..63e0a536ad
--- /dev/null
+++ b/internal/test/filter/server.yaml
@@ -0,0 +1,48 @@
+openapi: "3.0.1"
+info:
+ version: 1.0.0
+ title: Test Server
+ license:
+ name: MIT
+ description: |
+ This tests whether filtering works correctly
+paths:
+ /included1:
+ get:
+ operationId: included-operation1
+ tags:
+ - included-tag1
+ responses:
+ 200:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SchemaObject'
+ /filtered:
+ get:
+ operationId: filtered-operation
+ tags:
+ - filtered-tag
+ responses:
+ 200:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SchemaObject'
+ /included2:
+ get:
+ operationId: included-operation2
+ tags:
+ - included-tag2
+ responses:
+ 200:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/SchemaObject'
+
+components:
+ schemas:
+ SchemaObject:
+ properties:
+ firstName:
+ type: string
+ required:
+ - firstName
diff --git a/internal/test/filter/tags/server.gen.go b/internal/test/filter/tags/server.gen.go
new file mode 100644
index 0000000000..59f4dd8b03
--- /dev/null
+++ b/internal/test/filter/tags/server.gen.go
@@ -0,0 +1,93 @@
+// Package filtertags provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package filtertags
+
+import (
+ "github.com/labstack/echo/v4"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /included1)
+ IncludedOperation1(ctx echo.Context) error
+
+ // (GET /included2)
+ IncludedOperation2(ctx echo.Context) error
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+// IncludedOperation1 converts echo context to params.
+func (w *ServerInterfaceWrapper) IncludedOperation1(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.IncludedOperation1(ctx)
+ return err
+}
+
+// IncludedOperation2 converts echo context to params.
+func (w *ServerInterfaceWrapper) IncludedOperation2(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.IncludedOperation2(ctx)
+ return err
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+}
+
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
+}
+
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.GET(options.BaseURL+"/included1", wrapper.IncludedOperation1, options.OperationMiddlewares["included-operation1"]...)
+ router.GET(options.BaseURL+"/included2", wrapper.IncludedOperation2, options.OperationMiddlewares["included-operation2"]...)
+
+}
diff --git a/internal/test/filter/tags/server_test.go b/internal/test/filter/tags/server_test.go
new file mode 100644
index 0000000000..1f466269cf
--- /dev/null
+++ b/internal/test/filter/tags/server_test.go
@@ -0,0 +1,26 @@
+package filtertags
+
+import (
+ "testing"
+
+ "github.com/labstack/echo/v4"
+ "github.com/stretchr/testify/assert"
+)
+
+type server struct{}
+
+func (s server) IncludedOperation1(ctx echo.Context) error {
+ return nil
+}
+
+func (s server) IncludedOperation2(ctx echo.Context) error {
+ return nil
+}
+
+func TestServer(t *testing.T) {
+ assert := assert.New(t)
+
+ var s ServerInterface = server{}
+ assert.NoError(s.IncludedOperation1(nil))
+ assert.NoError(s.IncludedOperation2(nil))
+}
diff --git a/internal/test/go.mod b/internal/test/go.mod
index 5dfb3d7798..8d111ae94d 100644
--- a/internal/test/go.mod
+++ b/internal/test/go.mod
@@ -1,102 +1,113 @@
-module github.com/deepmap/oapi-codegen/internal/test
+module github.com/oapi-codegen/oapi-codegen/v2/internal/test
-go 1.20
+go 1.25.9
-replace github.com/deepmap/oapi-codegen => ../../
+replace github.com/oapi-codegen/oapi-codegen/v2 => ../../
require (
- github.com/deepmap/oapi-codegen v0.0.0-00010101000000-000000000000
- github.com/getkin/kin-openapi v0.118.0
- github.com/gin-gonic/gin v1.9.1
- github.com/go-chi/chi/v5 v5.0.10
- github.com/gofiber/fiber/v2 v2.49.1
- github.com/gorilla/mux v1.8.0
- github.com/kataras/iris/v12 v12.2.6-0.20230908161203-24ba4e8933b9
- github.com/labstack/echo/v4 v4.11.1
- github.com/oapi-codegen/runtime v1.0.0
- github.com/stretchr/testify v1.8.4
- gopkg.in/yaml.v2 v2.4.0
+ github.com/getkin/kin-openapi v0.140.0
+ github.com/gin-gonic/gin v1.12.0
+ github.com/go-chi/chi/v5 v5.2.5
+ github.com/gofiber/fiber/v2 v2.52.13
+ github.com/google/uuid v1.6.0
+ github.com/gorilla/mux v1.8.1
+ github.com/kataras/iris/v12 v12.2.11
+ github.com/labstack/echo/v4 v4.15.1
+ github.com/labstack/echo/v5 v5.1.0
+ github.com/oapi-codegen/nullable v1.1.0
+ github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000
+ github.com/oapi-codegen/runtime v1.4.1
+ github.com/oapi-codegen/testutil v1.1.0
+ github.com/stretchr/testify v1.11.1
+ go.yaml.in/yaml/v3 v3.0.4
+ golang.org/x/time v0.15.0
)
require (
- github.com/BurntSushi/toml v1.3.2 // indirect
- github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 // indirect
- github.com/CloudyKit/jet/v6 v6.2.0 // indirect
+ github.com/BurntSushi/toml v1.6.0 // indirect
+ github.com/CloudyKit/fastprinter v0.0.0-20251202014920-1725d2651bd4 // indirect
+ github.com/CloudyKit/jet/v6 v6.3.2 // indirect
github.com/Joker/jade v1.1.3 // indirect
- github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 // indirect
- github.com/andybalholm/brotli v1.0.5 // indirect
+ github.com/Shopify/goreferrer v0.0.0-20250617153402-88c1d9a79b05 // indirect
+ github.com/andybalholm/brotli v1.2.1 // indirect
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
github.com/aymerick/douceur v0.2.0 // indirect
- github.com/bytedance/sonic v1.10.0-rc3 // indirect
- github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
- github.com/chenzhuoyu/iasm v0.9.0 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
+ github.com/bytedance/gopkg v0.1.4 // indirect
+ github.com/bytedance/sonic v1.15.1 // indirect
+ github.com/bytedance/sonic/loader v0.5.1 // indirect
+ github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
+ github.com/cloudwego/base64x v0.1.7 // indirect
+ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
+ github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/flosch/pongo2/v4 v4.0.2 // indirect
- github.com/gabriel-vasile/mimetype v1.4.2 // indirect
- github.com/gin-contrib/sse v0.1.0 // indirect
- github.com/go-openapi/jsonpointer v0.20.0 // indirect
- github.com/go-openapi/swag v0.22.4 // indirect
+ github.com/gabriel-vasile/mimetype v1.4.13 // indirect
+ github.com/gin-contrib/sse v1.1.1 // indirect
+ github.com/go-openapi/jsonpointer v0.23.1 // indirect
+ github.com/go-openapi/swag/jsonname v0.26.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
- github.com/go-playground/validator/v10 v10.14.1 // indirect
- github.com/goccy/go-json v0.10.2 // indirect
- github.com/golang-jwt/jwt v3.2.2+incompatible // indirect
- github.com/golang/snappy v0.0.4 // indirect
- github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 // indirect
- github.com/google/uuid v1.3.1 // indirect
- github.com/gorilla/css v1.0.0 // indirect
- github.com/invopop/yaml v0.2.0 // indirect
+ github.com/go-playground/validator/v10 v10.30.2 // indirect
+ github.com/goccy/go-json v0.10.6 // indirect
+ github.com/goccy/go-yaml v1.19.2 // indirect
+ github.com/golang/snappy v1.0.0 // indirect
+ github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df // indirect
+ github.com/gorilla/css v1.0.1 // indirect
github.com/iris-contrib/schema v0.0.6 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
- github.com/kataras/blocks v0.0.7 // indirect
- github.com/kataras/golog v0.1.9 // indirect
- github.com/kataras/pio v0.0.12 // indirect
+ github.com/kataras/blocks v0.0.12 // indirect
+ github.com/kataras/golog v0.1.11 // indirect
+ github.com/kataras/pio v0.0.13 // indirect
github.com/kataras/sitemap v0.0.6 // indirect
github.com/kataras/tunnel v0.0.4 // indirect
- github.com/klauspost/compress v1.16.7 // indirect
- github.com/klauspost/cpuid/v2 v2.2.5 // indirect
- github.com/labstack/gommon v0.4.0 // indirect
- github.com/leodido/go-urn v1.2.4 // indirect
+ github.com/klauspost/compress v1.18.6 // indirect
+ github.com/klauspost/cpuid/v2 v2.3.0 // indirect
+ github.com/labstack/gommon v0.5.0 // indirect
+ github.com/leodido/go-urn v1.4.0 // indirect
github.com/mailgun/raymond/v2 v2.0.48 // indirect
- github.com/mailru/easyjson v0.7.7 // indirect
- github.com/mattn/go-colorable v0.1.13 // indirect
- github.com/mattn/go-isatty v0.0.19 // indirect
- github.com/mattn/go-runewidth v0.0.15 // indirect
- github.com/microcosm-cc/bluemonday v1.0.25 // indirect
+ github.com/mailru/easyjson v0.9.2 // indirect
+ github.com/mattn/go-colorable v0.1.14 // indirect
+ github.com/mattn/go-isatty v0.0.22 // indirect
+ github.com/mattn/go-runewidth v0.0.23 // indirect
+ github.com/microcosm-cc/bluemonday v1.0.27 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
- github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
- github.com/pelletier/go-toml/v2 v2.0.9 // indirect
- github.com/perimeterx/marshmallow v1.1.5 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/rivo/uniseg v0.4.4 // indirect
- github.com/rogpeppe/go-internal v1.11.0 // indirect
+ github.com/oasdiff/yaml v0.1.0 // indirect
+ github.com/oasdiff/yaml3 v0.0.13 // indirect
+ github.com/pelletier/go-toml/v2 v2.3.0 // indirect
+ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
+ github.com/quic-go/qpack v0.6.0 // indirect
+ github.com/quic-go/quic-go v0.59.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
+ github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 // indirect
github.com/schollz/closestmatch v2.1.0+incompatible // indirect
- github.com/sirupsen/logrus v1.8.1 // indirect
- github.com/stretchr/objx v0.5.0 // indirect
- github.com/tdewolff/minify/v2 v2.12.9 // indirect
- github.com/tdewolff/parse/v2 v2.6.8 // indirect
+ github.com/sirupsen/logrus v1.9.4 // indirect
+ github.com/speakeasy-api/jsonpath v0.6.3 // indirect
+ github.com/speakeasy-api/openapi v1.23.0 // indirect
+ github.com/stretchr/objx v0.5.2 // indirect
+ github.com/tdewolff/minify/v2 v2.24.13 // indirect
+ github.com/tdewolff/parse/v2 v2.8.12 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
- github.com/ugorji/go/codec v1.2.11 // indirect
+ github.com/ugorji/go/codec v1.3.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
- github.com/valyala/fasthttp v1.49.0 // indirect
+ github.com/valyala/fasthttp v1.70.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
- github.com/valyala/tcplisten v1.0.0 // indirect
- github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
+ github.com/vmihailenco/msgpack/v5 v5.4.1 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
+ github.com/vmware-labs/yaml-jsonpath v0.3.2 // indirect
github.com/yosssi/ace v0.0.5 // indirect
- golang.org/x/arch v0.4.0 // indirect
- golang.org/x/crypto v0.13.0 // indirect
- golang.org/x/mod v0.12.0 // indirect
- golang.org/x/net v0.15.0 // indirect
- golang.org/x/sys v0.12.0 // indirect
- golang.org/x/text v0.13.0 // indirect
- golang.org/x/time v0.3.0 // indirect
- golang.org/x/tools v0.12.0 // indirect
- google.golang.org/protobuf v1.31.0 // indirect
- gopkg.in/ini.v1 v1.67.0 // indirect
+ go.mongodb.org/mongo-driver/v2 v2.6.0 // indirect
+ golang.org/x/arch v0.26.0 // indirect
+ golang.org/x/crypto v0.51.0 // indirect
+ golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f // indirect
+ golang.org/x/mod v0.36.0 // indirect
+ golang.org/x/net v0.54.0 // indirect
+ golang.org/x/sync v0.20.0 // indirect
+ golang.org/x/sys v0.44.0 // indirect
+ golang.org/x/text v0.37.0 // indirect
+ golang.org/x/tools v0.45.0 // indirect
+ google.golang.org/protobuf v1.36.11 // indirect
+ gopkg.in/ini.v1 v1.67.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
diff --git a/internal/test/go.sum b/internal/test/go.sum
index dd64351512..e6cb669a55 100644
--- a/internal/test/go.sum
+++ b/internal/test/go.sum
@@ -1,95 +1,128 @@
-github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
-github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
-github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53 h1:sR+/8Yb4slttB4vD+b9btVEnWgL3Q00OBTzVT8B9C0c=
+github.com/BurntSushi/toml v1.6.0 h1:dRaEfpa2VI55EwlIW72hMRHdWouJeRF7TPYhI+AUQjk=
+github.com/BurntSushi/toml v1.6.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/CloudyKit/fastprinter v0.0.0-20200109182630-33d98a066a53/go.mod h1:+3IMCy2vIlbG1XG/0ggNQv0SvxCAIpPM5b1nCz56Xno=
-github.com/CloudyKit/jet/v6 v6.2.0 h1:EpcZ6SR9n28BUGtNJSvlBqf90IpjeFr36Tizxhn/oME=
-github.com/CloudyKit/jet/v6 v6.2.0/go.mod h1:d3ypHeIRNo2+XyqnGA8s+aphtcVpjP5hPwP/Lzo7Ro4=
+github.com/CloudyKit/fastprinter v0.0.0-20251202014920-1725d2651bd4 h1:DQ1+lDdBve+u+aovjh4wV6sYnvZKH0Hx8GaQOi4vYl8=
+github.com/CloudyKit/fastprinter v0.0.0-20251202014920-1725d2651bd4/go.mod h1:eauGmjfZG874MOAEPVeqg21mZCbTOLW+tFe8F7NpfnY=
+github.com/CloudyKit/jet/v6 v6.3.2 h1:BPaX0lnXTZ9TniICiiK/0iJqzeGJ2ibvB4DjAqLMBSM=
+github.com/CloudyKit/jet/v6 v6.3.2/go.mod h1:lf8ksdNsxZt7/yH/3n4vJQWA9RUq4wpaHtArHhGVMOw=
github.com/Joker/hpp v1.0.0 h1:65+iuJYdRXv/XyN62C1uEmmOx3432rNG/rKlX6V7Kkc=
github.com/Joker/hpp v1.0.0/go.mod h1:8x5n+M1Hp5hC0g8okX3sR3vFQwynaX/UgSOM9MeBKzY=
github.com/Joker/jade v1.1.3 h1:Qbeh12Vq6BxURXT1qZBRHsDxeURB8ztcL6f3EXSGeHk=
github.com/Joker/jade v1.1.3/go.mod h1:T+2WLyt7VH6Lp0TRxQrUYEs64nRc83wkMQrfeIQKduM=
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
-github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06 h1:KkH3I3sJuOLP3TjA/dfr4NAY8bghDwnXiU7cTKxQqo0=
-github.com/Shopify/goreferrer v0.0.0-20220729165902-8cddb4f5de06/go.mod h1:7erjKLwalezA0k99cWs5L11HWOAPNjdUZ6RxH1BXbbM=
+github.com/Shopify/goreferrer v0.0.0-20250617153402-88c1d9a79b05 h1:dG7/gLroJGht/jSQtHiLvT48Hxn+crbmvyItZC8cWOs=
+github.com/Shopify/goreferrer v0.0.0-20250617153402-88c1d9a79b05/go.mod h1:NYezi6wtnJtBm5btoprXc5SvAdqH0XTXWnUup0MptAI=
github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU=
-github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
-github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
+github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
+github.com/andybalholm/brotli v1.2.1 h1:R+f5xP285VArJDRgowrfb9DqL18yVK0gKAW/F+eTWro=
+github.com/andybalholm/brotli v1.2.1/go.mod h1:rzTDkvFWvIrjDXZHkuS16NPggd91W3kUSvPlQ1pLaKY=
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
-github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
-github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
-github.com/bytedance/sonic v1.10.0-rc3 h1:uNSnscRapXTwUgTyOF0GVljYD08p9X/Lbr9MweSV3V0=
-github.com/bytedance/sonic v1.10.0-rc3/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
-github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
-github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
-github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
-github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
-github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
-github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
+github.com/bytedance/gopkg v0.1.4 h1:oZnQwnX82KAIWb7033bEwtxvTqXcYMxDBaQxo5JJHWM=
+github.com/bytedance/gopkg v0.1.4/go.mod h1:v1zWfPm21Fb+OsyXN2VAHdL6TBb2L88anLQgdyje6R4=
+github.com/bytedance/sonic v1.15.1 h1:nJD5PmM0vY7J8CT6MxoqbVAAMhkSmV2HgRAUrrpLoOw=
+github.com/bytedance/sonic v1.15.1/go.mod h1:mT2NbXunuaEbnZ+mRIX/vYqKISmgEuHFDI4UzmKx2SA=
+github.com/bytedance/sonic/loader v0.5.1 h1:Ygpfa9zwRCCKSlrp5bBP/b/Xzc3VxsAW+5NIYXrOOpI=
+github.com/bytedance/sonic/loader v0.5.1/go.mod h1:AR4NYCk5DdzZizZ5djGqQ92eEhCCcdf5x77udYiSJRo=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
+github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
+github.com/cloudwego/base64x v0.1.7 h1:NppS+Fgzg5ovhn4NkUXaDT3x9jldgH5ToMCqzBSi2zI=
+github.com/cloudwego/base64x v0.1.7/go.mod h1:Cu1PV9zfrSf7ET2tIbWbbEy7jO7HHJ13q4X2SQ8aWYg=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
+github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
+github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
+github.com/dprotaso/go-yit v0.0.0-20191028211022-135eb7262960/go.mod h1:9HQzr9D/0PGwMEbC3d5AB7oi67+h4TsQqItC1GVYG58=
+github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936 h1:PRxIJD8XjimM5aTknUK9w6DHLDox2r2M3DI4i2pnd3w=
+github.com/dprotaso/go-yit v0.0.0-20220510233725-9ba8df137936/go.mod h1:ttYvX5qlB+mlV1okblJqcSMtR4c52UKxDiX9GRBS8+Q=
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
+github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo=
github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
github.com/flosch/pongo2/v4 v4.0.2 h1:gv+5Pe3vaSVmiJvh/BZa82b7/00YUGm0PIyVVLop0Hw=
github.com/flosch/pongo2/v4 v4.0.2/go.mod h1:B5ObFANs/36VwxxlgKpdchIJHMvHB562PW+BWPhwZD8=
-github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
-github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
-github.com/getkin/kin-openapi v0.118.0 h1:z43njxPmJ7TaPpMSCQb7PN0dEYno4tyBPQcrFdHoLuM=
-github.com/getkin/kin-openapi v0.118.0/go.mod h1:l5e9PaFUo9fyLJCPGQeXI2ML8c3P8BHOEV2VaAVf/pc=
-github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
-github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
-github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
-github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
-github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
-github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
-github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
-github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ=
-github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA=
-github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
-github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
+github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
+github.com/gabriel-vasile/mimetype v1.4.13 h1:46nXokslUBsAJE/wMsp5gtO500a4F3Nkz9Ufpk2AcUM=
+github.com/gabriel-vasile/mimetype v1.4.13/go.mod h1:d+9Oxyo1wTzWdyVUPMmXFvp4F9tea18J8ufA774AB3s=
+github.com/getkin/kin-openapi v0.140.0 h1:JFn675aXRFjyiZKa/BFWploGldQlI0gobp4J5k0EZ2g=
+github.com/getkin/kin-openapi v0.140.0/go.mod h1:lISrB64F0CPcuDJ3LdtPTMJBY8VENjR9wJBdrcT6J3g=
+github.com/gin-contrib/sse v1.1.1 h1:uGYpNwTacv5R68bSGMapo62iLTRa9l5zxGCps4hK6ko=
+github.com/gin-contrib/sse v1.1.1/go.mod h1:QXzuVkA0YO7o/gun03UI1Q+FTI8ZV/n5t03kIQAI89s=
+github.com/gin-gonic/gin v1.12.0 h1:b3YAbrZtnf8N//yjKeU2+MQsh2mY5htkZidOM7O0wG8=
+github.com/gin-gonic/gin v1.12.0/go.mod h1:VxccKfsSllpKshkBWgVgRniFFAzFb9csfngsqANjnLc=
+github.com/go-chi/chi/v5 v5.2.5 h1:Eg4myHZBjyvJmAFjFvWgrqDTXFyOzjj7YIm3L3mu6Ug=
+github.com/go-chi/chi/v5 v5.2.5/go.mod h1:X7Gx4mteadT3eDOMTsXzmI4/rwUpOwBHLpAfupzFJP0=
+github.com/go-openapi/jsonpointer v0.23.1 h1:1HBACs7XIwR2RcmItfdSFlALhGbe6S92p0ry4d1GWg4=
+github.com/go-openapi/jsonpointer v0.23.1/go.mod h1:iWRmZTrGn7XwYhtPt/fvdSFj1OfNBngqRT2UG3BxSqY=
+github.com/go-openapi/swag/jsonname v0.26.0 h1:gV1NFX9M8avo0YSpmWogqfQISigCmpaiNci8cGECU5w=
+github.com/go-openapi/swag/jsonname v0.26.0/go.mod h1:urBBR8bZNoDYGr653ynhIx+gTeIz0ARZxHkAPktJK2M=
+github.com/go-openapi/testify/v2 v2.4.2 h1:tiByHpvE9uHrrKjOszax7ZvKB7QOgizBWGBLuq0ePx4=
+github.com/go-openapi/testify/v2 v2.4.2/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
+github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
-github.com/go-playground/validator/v10 v10.14.1 h1:9c50NUPC30zyuKprjL3vNZ0m5oG+jU0zvx4AqHGnv4k=
-github.com/go-playground/validator/v10 v10.14.1/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
-github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
-github.com/go-test/deep v1.0.8/go.mod h1:5C2ZWiW0ErCdrYzpqxLbTX7MG14M9iiw8DgHncVwcsE=
+github.com/go-playground/validator/v10 v10.30.2 h1:JiFIMtSSHb2/XBUbWM4i/MpeQm9ZK2xqPNk8vgvu5JQ=
+github.com/go-playground/validator/v10 v10.30.2/go.mod h1:mAf2pIOVXjTEBrwUMGKkCWKKPs9NheYGabeB04txQSc=
+github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
-github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
-github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
-github.com/gofiber/fiber/v2 v2.49.1 h1:0W2DRWevSirc8pJl4o8r8QejDR8TV6ZUCawHxwbIdOk=
-github.com/gofiber/fiber/v2 v2.49.1/go.mod h1:nPUeEBUeeYGgwbDm59Gp7vS8MDyScL6ezr/Np9A13WU=
-github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
-github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
+github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
+github.com/goccy/go-json v0.10.6 h1:p8HrPJzOakx/mn/bQtjgNjdTcN+/S6FcG2CTtQOrHVU=
+github.com/goccy/go-json v0.10.6/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
+github.com/goccy/go-yaml v1.19.2 h1:PmFC1S6h8ljIz6gMRBopkjP1TVT7xuwrButHID66PoM=
+github.com/goccy/go-yaml v1.19.2/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
+github.com/gofiber/fiber/v2 v2.52.13 h1:TOKP64iqC9b5P49VrBW5tHhUOvDyrtJ0xePEfzJbCbk=
+github.com/gofiber/fiber/v2 v2.52.13/go.mod h1:YEcBbO/FB+5M1IZNBP9FO3J9281zgPAreiI1oqg8nDw=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
-github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
-github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12 h1:uK3X/2mt4tbSGoHvbLBHUny7CKiuwUip3MArtukol4E=
-github.com/gomarkdown/markdown v0.0.0-20230716120725-531d2d74bc12/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
-github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
+github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
+github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs=
+github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
+github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df h1:Mwihr/o+v4L5h56rwHLOE20+hh7Okhwno5BHz3zDuao=
+github.com/gomarkdown/markdown v0.0.0-20260417124207-7d523f7318df/go.mod h1:JDGcbDT52eL4fju3sZ4TeHGsQwhG9nbDV21aMyhwPoA=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
+github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
+github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
-github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
-github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
-github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
-github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
-github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
+github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
+github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8=
+github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
+github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imkira/go-interpol v1.1.0 h1:KIiKr0VSG2CUW1hl1jpiyuzuJeKUUpC8iM1AIE7N1Vk=
-github.com/invopop/yaml v0.1.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
-github.com/invopop/yaml v0.2.0 h1:7zky/qH+O0DwAyoobXUqvVBwgBFRxKoQ/3FjcVpjTMY=
-github.com/invopop/yaml v0.2.0/go.mod h1:2XuRLgs/ouIrW3XNzuNj7J3Nvu/Dig5MXvbCEdiBN3Q=
+github.com/imkira/go-interpol v1.1.0/go.mod h1:z0h2/2T3XF8kyEPpRgJ3kmNv+C43p+I/CoI+jC3w2iA=
github.com/iris-contrib/httpexpect/v2 v2.15.2 h1:T9THsdP1woyAqKHwjkEsbCnMefsAFvk8iJJKokcJ3Go=
+github.com/iris-contrib/httpexpect/v2 v2.15.2/go.mod h1:JLDgIqnFy5loDSUv1OA2j0mb6p/rDhiCqigP22Uq9xE=
github.com/iris-contrib/schema v0.0.6 h1:CPSBLyx2e91H2yJzPuhGuifVRnZBBJ3pCOMbOvPZaTw=
github.com/iris-contrib/schema v0.0.6/go.mod h1:iYszG0IOsuIsfzjymw1kMzTL8YQcCWlm65f3wX8J5iA=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
@@ -97,200 +130,272 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
-github.com/kataras/blocks v0.0.7 h1:cF3RDY/vxnSRezc7vLFlQFTYXG/yAr1o7WImJuZbzC4=
-github.com/kataras/blocks v0.0.7/go.mod h1:UJIU97CluDo0f+zEjbnbkeMRlvYORtmc1304EeyXf4I=
-github.com/kataras/golog v0.1.9 h1:vLvSDpP7kihFGKFAvBSofYo7qZNULYSHOH2D7rPTKJk=
-github.com/kataras/golog v0.1.9/go.mod h1:jlpk/bOaYCyqDqH18pgDHdaJab72yBE6i0O3s30hpWY=
-github.com/kataras/iris/v12 v12.2.6-0.20230908161203-24ba4e8933b9 h1:Vx8kDVhO2qepK8w44lBtp+RzN3ld743i+LYPzODJSpQ=
-github.com/kataras/iris/v12 v12.2.6-0.20230908161203-24ba4e8933b9/go.mod h1:ldkoR3iXABBeqlTibQ3MYaviA1oSlPvim6f55biwBh4=
-github.com/kataras/pio v0.0.12 h1:o52SfVYauS3J5X08fNjlGS5arXHjW/ItLkyLcKjoH6w=
-github.com/kataras/pio v0.0.12/go.mod h1:ODK/8XBhhQ5WqrAhKy+9lTPS7sBf6O3KcLhc9klfRcY=
+github.com/kataras/blocks v0.0.12 h1:2OnEYFcLtYPjyEMhyDk1pdHm+b75hay5uobuPTacnIc=
+github.com/kataras/blocks v0.0.12/go.mod h1:CtCOQ+YDdd0NJTMW019YPV9D+q6dWO2b9d2cSRgifpk=
+github.com/kataras/golog v0.1.11 h1:dGkcCVsIpqiAMWTlebn/ZULHxFvfG4K43LF1cNWSh20=
+github.com/kataras/golog v0.1.11/go.mod h1:mAkt1vbPowFUuUGvexyQ5NFW6djEgGyxQBIARJ0AH4A=
+github.com/kataras/iris/v12 v12.2.11 h1:sGgo43rMPfzDft8rjVhPs6L3qDJy3TbBrMD/zGL1pzk=
+github.com/kataras/iris/v12 v12.2.11/go.mod h1:uMAeX8OqG9vqdhyrIPv8Lajo/wXTtAF43wchP9WHt2w=
+github.com/kataras/pio v0.0.13 h1:x0rXVX0fviDTXOOLOmr4MUxOabu1InVSTu5itF8CXCM=
+github.com/kataras/pio v0.0.13/go.mod h1:k3HNuSw+eJ8Pm2lA4lRhg3DiCjVgHlP8hmXApSej3oM=
github.com/kataras/sitemap v0.0.6 h1:w71CRMMKYMJh6LR2wTgnk5hSgjVNB9KL60n5e2KHvLY=
github.com/kataras/sitemap v0.0.6/go.mod h1:dW4dOCNs896OR1HmG+dMLdT7JjDk7mYBzoIRwuj5jA4=
github.com/kataras/tunnel v0.0.4 h1:sCAqWuJV7nPzGrlb0os3j49lk2JhILT0rID38NHNLpA=
github.com/kataras/tunnel v0.0.4/go.mod h1:9FkU4LaeifdMWqZu7o20ojmW4B7hdhv2CMLwfnHGpYw=
-github.com/klauspost/compress v1.16.7 h1:2mk3MPGNzKyxErAw8YaohYh69+pa4sIQSC0fPGCFR9I=
-github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
-github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
-github.com/klauspost/cpuid/v2 v2.2.5 h1:0E5MSMDEoAulmXNFquVs//DdoomxaoTY1kUhbc/qbZg=
-github.com/klauspost/cpuid/v2 v2.2.5/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
-github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
+github.com/klauspost/compress v1.18.6 h1:2jupLlAwFm95+YDR+NwD2MEfFO9d4z4Prjl1XXDjuao=
+github.com/klauspost/compress v1.18.6/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
+github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y=
+github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
+github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/labstack/echo/v4 v4.11.1 h1:dEpLU2FLg4UVmvCGPuk/APjlH6GDpbEPti61srUUUs4=
-github.com/labstack/echo/v4 v4.11.1/go.mod h1:YuYRTSM3CHs2ybfrL8Px48bO6BAnYIN4l8wSTMP6BDQ=
-github.com/labstack/gommon v0.4.0 h1:y7cvthEAEbU0yHOf4axH8ZG2NH8knB9iNSoTO8dyIk8=
-github.com/labstack/gommon v0.4.0/go.mod h1:uW6kP17uPlLJsD3ijUYn3/M5bAxtlZhMI6m3MFxTMTM=
-github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
-github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
+github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
+github.com/labstack/echo/v4 v4.15.1 h1:S9keusg26gZpjMmPqB5hOEvNKnmd1lNmcHrbbH2lnFs=
+github.com/labstack/echo/v4 v4.15.1/go.mod h1:xmw1clThob0BSVRX1CRQkGQ/vjwcpOMjQZSZa9fKA/c=
+github.com/labstack/echo/v5 v5.1.0 h1:MvIRydoN+p9cx/zq8Lff6YXqUW2ZaEsOMISzEGSMrBI=
+github.com/labstack/echo/v5 v5.1.0/go.mod h1:SyvlSdObGjRXeQfCCXW/sybkZdOOQZBmpKF0bvALaeo=
+github.com/labstack/gommon v0.5.0 h1:6VSQ2NOzsnEJ5W6+84E0RbcaDDmgB6NIAzWCczTEe6c=
+github.com/labstack/gommon v0.5.0/go.mod h1:Rzlg7HHy1maLfzBYGg9NZcVuz1sA68HHhLjhcEllYE0=
+github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
+github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw=
github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18=
-github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
-github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
-github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
-github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
-github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
-github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
-github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
-github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
-github.com/microcosm-cc/bluemonday v1.0.25 h1:4NEwSfiJ+Wva0VxN5B8OwMicaJvD8r9tlJWm9rtloEg=
-github.com/microcosm-cc/bluemonday v1.0.25/go.mod h1:ZIOjCQp1OrzBBPIJmfX4qDYFuhU02nx4bn030ixfHLE=
+github.com/mailru/easyjson v0.9.2 h1:dX8U45hQsZpxd80nLvDGihsQ/OxlvTkVUXH2r/8cb2M=
+github.com/mailru/easyjson v0.9.2/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU=
+github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
+github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
+github.com/mattn/go-isatty v0.0.22 h1:j8l17JJ9i6VGPUFUYoTUKPSgKe/83EYU2zBC7YNKMw4=
+github.com/mattn/go-isatty v0.0.22/go.mod h1:ZXfXG4SQHsB/w3ZeOYbR0PrPwLy+n6xiMrJlRFqopa4=
+github.com/mattn/go-runewidth v0.0.23 h1:7ykA0T0jkPpzSvMS5i9uoNn2Xy3R383f9HDx3RybWcw=
+github.com/mattn/go-runewidth v0.0.23/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
+github.com/microcosm-cc/bluemonday v1.0.27 h1:MpEUotklkwCSLeH+Qdx1VJgNqLlpY2KXwXFM08ygZfk=
+github.com/microcosm-cc/bluemonday v1.0.27/go.mod h1:jFi9vgW+H7c3V0lb6nR74Ib/DIB5OBs92Dimizgw2cA=
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
+github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
-github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw=
-github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
-github.com/oapi-codegen/runtime v1.0.0 h1:P4rqFX5fMFWqRzY9M/3YF9+aPSPPB06IzP2P7oOxrWo=
-github.com/oapi-codegen/runtime v1.0.0/go.mod h1:LmCUMQuPB4M/nLXilQXhHw+BLZdDb18B34OO356yJ/A=
-github.com/pelletier/go-toml/v2 v2.0.9 h1:uH2qQXheeefCCkuBBSLi7jCiSmj3VRh2+Goq2N7Xxu0=
-github.com/pelletier/go-toml/v2 v2.0.9/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
-github.com/perimeterx/marshmallow v1.1.4/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
-github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s=
-github.com/perimeterx/marshmallow v1.1.5/go.mod h1:dsXbUu8CRzfYP5a87xpp0xq9S3u0Vchtcl8we9tYaXw=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
+github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
+github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
+github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
+github.com/oapi-codegen/nullable v1.1.0 h1:eAh8JVc5430VtYVnq00Hrbpag9PFRGWLjxR1/3KntMs=
+github.com/oapi-codegen/nullable v1.1.0/go.mod h1:KUZ3vUzkmEKY90ksAmit2+5juDIhIZhfDl+0PwOQlFY=
+github.com/oapi-codegen/runtime v1.4.1 h1:9nwLoI+KrWxzbBcp0jO/R8uXqbik/HUyCvPeU68Y/qo=
+github.com/oapi-codegen/runtime v1.4.1/go.mod h1:GwV7hC2hviaMzj+ITfHVRESK5J2W/GefVwIND/bMGvU=
+github.com/oapi-codegen/testutil v1.1.0 h1:EufqpNg43acR3qzr3ObhXmWg3Sl2kwtRnUN5GYY4d5g=
+github.com/oapi-codegen/testutil v1.1.0/go.mod h1:ttCaYbHvJtHuiyeBF0tPIX+4uhEPTeizXKx28okijLw=
+github.com/oasdiff/yaml v0.1.0 h1:0bqZjfKc/8S9urj4JuwepX41WX9EoA6ifhU3SV06cXg=
+github.com/oasdiff/yaml v0.1.0/go.mod h1:kOlRmMdL2X3vucLCEQO5u61SU22RysnfXvcttrZA1O0=
+github.com/oasdiff/yaml3 v0.0.13 h1:06svmvOHOVBqF81+sY2EUScvUI/iS/vl2VIeUUxZQwg=
+github.com/oasdiff/yaml3 v0.0.13/go.mod h1:y5+oSEHCPT/DGrS++Wc/479ERge0zTFxaF8PbGKcg2o=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.2/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
+github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc=
+github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0=
+github.com/onsi/ginkgo/v2 v2.1.3/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
+github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
+github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY=
+github.com/onsi/gomega v1.19.0 h1:4ieX6qQjPP/BfC3mpsAtIGGlxTWPeA3Inl/7DtXw1tw=
+github.com/onsi/gomega v1.19.0/go.mod h1:LY+I3pBVzYsTBU1AnDwOSxaYi9WoWiqgwooUqq9yPro=
+github.com/pelletier/go-toml/v2 v2.3.0 h1:k59bC/lIZREW0/iVaQR8nDHxVq8OVlIzYCOJf421CaM=
+github.com/pelletier/go-toml/v2 v2.3.0/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
-github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
-github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
-github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
-github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
+github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/quic-go/qpack v0.6.0 h1:g7W+BMYynC1LbYLSqRt8PBg5Tgwxn214ZZR34VIOjz8=
+github.com/quic-go/qpack v0.6.0/go.mod h1:lUpLKChi8njB4ty2bFLX2x4gzDqXwUpaO1DP9qMDZII=
+github.com/quic-go/quic-go v0.59.0 h1:OLJkp1Mlm/aS7dpKgTc6cnpynnD2Xg7C1pwL6vy/SAw=
+github.com/quic-go/quic-go v0.59.0/go.mod h1:upnsH4Ju1YkqpLXC305eW3yDZ4NfnNbmQRCMWS58IKU=
+github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
+github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sanity-io/litter v1.5.5 h1:iE+sBxPBzoK6uaEP5Lt3fHNgpKcHXc/A2HGETy0uJQo=
+github.com/sanity-io/litter v1.5.5/go.mod h1:9gzJgR2i4ZpjZHsKvUXIRQVk7P+yM3e+jAF7bU2UI5U=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.2 h1:KRzFb2m7YtdldCEkzs6KqmJw4nqEVZGK7IN2kJkjTuQ=
+github.com/santhosh-tekuri/jsonschema/v6 v6.0.2/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/schollz/closestmatch v2.1.0+incompatible h1:Uel2GXEpJqOWBrlyI+oY9LTiyyjYS17cCYRqP13/SHk=
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
-github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
-github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
+github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
+github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
+github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
+github.com/speakeasy-api/jsonpath v0.6.3 h1:c+QPwzAOdrWvzycuc9HFsIZcxKIaWcNpC+xhOW9rJxU=
+github.com/speakeasy-api/jsonpath v0.6.3/go.mod h1:2cXloNuQ+RSXi5HTRaeBh7JEmjRXTiaKpFTdZiL7URI=
+github.com/speakeasy-api/openapi v1.23.0 h1:BlnHqUR/8uIs4tp3d2B4QDN03gw1/QY2R2MHg6fLhRU=
+github.com/speakeasy-api/openapi v1.23.0/go.mod h1:Ih+ZzaTCCPyB2ykiDXaxhqk6jsY84ke3n5p6fobMDXk=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
-github.com/stretchr/objx v0.5.0 h1:1zr/of2m5FGMsad5YfcqgdqdWrIhu+EBEJRhR1U7z/c=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
+github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
+github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
-github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
-github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/tdewolff/minify/v2 v2.12.9 h1:dvn5MtmuQ/DFMwqf5j8QhEVpPX6fi3WGImhv8RUB4zA=
-github.com/tdewolff/minify/v2 v2.12.9/go.mod h1:qOqdlDfL+7v0/fyymB+OP497nIxJYSvX4MQWA8OoiXU=
-github.com/tdewolff/parse/v2 v2.6.8 h1:mhNZXYCx//xG7Yq2e/kVLNZw4YfYmeHbhx+Zc0OvFMA=
-github.com/tdewolff/parse/v2 v2.6.8/go.mod h1:XHDhaU6IBgsryfdnpzUXBlT6leW/l25yrFBTEb4eIyM=
-github.com/tdewolff/test v1.0.9 h1:SswqJCmeN4B+9gEAi/5uqT0qpi1y2/2O47V/1hhGZT0=
-github.com/tdewolff/test v1.0.9/go.mod h1:6DAvZliBAAnD7rhVgwaM7DE5/d9NMOAJ09SqYqeK4QE=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
+github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
+github.com/tdewolff/minify/v2 v2.24.13 h1:xrcF7gKDnUszseEY9WX9mUlZII2v2Go/QAcAwRASw58=
+github.com/tdewolff/minify/v2 v2.24.13/go.mod h1:emvwoYeIl8bfAKqRU5ww95LX9Gpggpqv/naal9a8Yq0=
+github.com/tdewolff/parse/v2 v2.8.12 h1:5BBjfaCv482v3nltlS0u6wH1xJaxjR6ofDrWttNvROg=
+github.com/tdewolff/parse/v2 v2.8.12/go.mod h1:Hwlni2tiVNKyzR1o6nUs4FOF07URA+JLBLd6dlIXYqo=
+github.com/tdewolff/test v1.0.11/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
+github.com/tdewolff/test v1.0.12 h1:7F21DqIajswxuche0geHdrUZRCWE4oko4b7bcmkkrxk=
+github.com/tdewolff/test v1.0.12/go.mod h1:XPuWBzvdUzhCuxWO1ojpXsyzsA5bFoS3tO/Q3kFuTG8=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
-github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
-github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
-github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
-github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
+github.com/ugorji/go/codec v1.3.1 h1:waO7eEiFDwidsBN6agj1vJQ4AG7lh2yqXyOXqhgQuyY=
+github.com/ugorji/go/codec v1.3.1/go.mod h1:pRBVtBSKl77K30Bv8R2P+cLSGaTtex6fsA2Wjqmfxj4=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
-github.com/valyala/fasthttp v1.49.0 h1:9FdvCpmxB74LH4dPb7IJ1cOSsluR07XG3I1txXWwJpE=
-github.com/valyala/fasthttp v1.49.0/go.mod h1:k2zXd82h/7UZc3VOdJ2WaUqt1uZ/XpXAfE9i+HBC3lA=
-github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
+github.com/valyala/fasthttp v1.70.0 h1:LAhMGcWk13QZWm85+eg8ZBNbrq5mnkWFGbHMUJHIdXA=
+github.com/valyala/fasthttp v1.70.0/go.mod h1:oDZEHHkJ/Buyklg6uURmYs19442zFSnCIfX3j1FY3pE=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
-github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
-github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
-github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
-github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
+github.com/vmihailenco/msgpack/v5 v5.4.1 h1:cQriyiUvjTwOHg8QZaPihLWeRAAVoCpE00IUPn0Bjt8=
+github.com/vmihailenco/msgpack/v5 v5.4.1/go.mod h1:GaZTsDaehaPpQVyxrf5mtQlH+pc21PIudVV/E3rRQok=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
+github.com/vmware-labs/yaml-jsonpath v0.3.2 h1:/5QKeCBGdsInyDCyVNLbXyilb61MXGi9NP674f9Hobk=
+github.com/vmware-labs/yaml-jsonpath v0.3.2/go.mod h1:U6whw1z03QyqgWdgXxvVnQ90zN1BWz5V+51Ewf8k+rQ=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
+github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
+github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
+github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
+github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
+github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
+github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
github.com/yosssi/ace v0.0.5 h1:tUkIP/BLdKqrlrPwcmH0shwEEhTRHoGnc1wFIWmaBUA=
github.com/yosssi/ace v0.0.5/go.mod h1:ALfIzm2vT7t5ZE7uoIZqF3TQ7SAOyupFZnkrF5id+K0=
github.com/yudai/gojsondiff v1.0.0 h1:27cbfqXLVEJ1o8I6v3y9lg8Ydm53EKqHXAOMxEGlCOA=
+github.com/yudai/gojsondiff v1.0.0/go.mod h1:AY32+k2cwILAkW1fbgxQ5mUmMiZFgLIV+FBNExI05xg=
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 h1:BHyfKlQyqbsFN5p3IfnEUduWvb9is428/nNb5L3U01M=
+github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82/go.mod h1:lgjkn3NuSvDfVJdfcVVdX+jpBxNmX4rDAzaS45IcYoM=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
-golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
-golang.org/x/arch v0.4.0 h1:A8WCeEWhLwPBKNbFi5Wv5UTCBx5zzubnXDlMOFAzFMc=
-golang.org/x/arch v0.4.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+go.mongodb.org/mongo-driver/v2 v2.6.0 h1:b9sJOYrkmt4l8bY43ZenFBcPlhYIjaOfYHLtbB/5qi8=
+go.mongodb.org/mongo-driver/v2 v2.6.0/go.mod h1:yOI9kBsufol30iFsl1slpdq1I0eHPzybRWdyYUs8K/0=
+go.uber.org/mock v0.6.0 h1:hyF9dfmbgIX5EfOdasqLsWD6xqpNZlXblLB/Dbnwv3Y=
+go.uber.org/mock v0.6.0/go.mod h1:KiVJ4BqZJaMj4svdfmHM0AUx4NJYO8ZNpPnZn1Z+BBU=
+go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
+go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
+golang.org/x/arch v0.26.0 h1:jZ6dpec5haP/fUv1kLCbuJy6dnRrfX6iVK08lZBFpk4=
+golang.org/x/arch v0.26.0/go.mod h1:0X+GdSIP+kL5wPmpK7sdkEVTt2XoYP0cSjQSbZBwOi8=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
-golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
-golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 h1:VLliZ0d+/avPrXXH+OakdXhpJuEoBZuwh1m2j7U6Iug=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
+golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
+golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f h1:W3F4c+6OLc6H2lb//N1q4WpJkhzJCK5J6kUi1NTVXfM=
+golang.org/x/exp v0.0.0-20260410095643-746e56fc9e2f/go.mod h1:J1xhfL/vlindoeF/aINzNzt2Bket5bjo9sdOYzOsU80=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
-golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
-golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4=
+golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190327091125-710a502c58a2/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
+golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8=
-golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
+golang.org/x/net v0.54.0 h1:2zJIZAxAHV/OHCDTCOHAYehQzLfSXuf/5SoL/Dv6w/w=
+golang.org/x/net v0.54.0/go.mod h1:Sj4oj8jK6XmHpBZU/zWHw3BV3abl4Kvi+Ut7cQcY+cQ=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
+golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
-golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
+golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
-golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
-golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
-golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
+golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=
+golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U=
+golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
-golang.org/x/tools v0.12.0 h1:YW6HUoUmYBpwSgyaGaZq1fHjrBjX1rlpZ54T6mu2kss=
-golang.org/x/tools v0.12.0/go.mod h1:Sc0INKfu04TlqNoRA1hgpFZbhYXHPr4V5DzpSBTPqQM=
+golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8=
+golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
-google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
+google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
+google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
+google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
-gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
-gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
+gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/ini.v1 v1.67.1 h1:tVBILHy0R6e4wkYOn3XmiITt/hEVH4TFMYvAX2Ytz6k=
+gopkg.in/ini.v1 v1.67.1/go.mod h1:x/cyOwCgZqOkJoDIJ3c1KNHMo10+nLGAhh+kn3Zizss=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
+gopkg.in/yaml.v3 v3.0.0-20191026110619-0b21df46bc1d/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
moul.io/http2curl/v2 v2.3.0 h1:9r3JfDzWPcbIklMOs2TnIFzDYvfAZvjeavG6EzP7jYs=
-nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
-rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
+moul.io/http2curl/v2 v2.3.0/go.mod h1:RW4hyBjTWSYDOxapodpNEtX0g5Eb16sxklBqmd2RHcE=
diff --git a/internal/test/issues/issue-1039/client-config.yaml b/internal/test/issues/issue-1039/client-config.yaml
new file mode 100644
index 0000000000..a117c7c745
--- /dev/null
+++ b/internal/test/issues/issue-1039/client-config.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue1039
+generate:
+ client: true
+output: client.gen.go
diff --git a/internal/test/issues/issue-1039/client.gen.go b/internal/test/issues/issue-1039/client.gen.go
new file mode 100644
index 0000000000..9e9696094e
--- /dev/null
+++ b/internal/test/issues/issue-1039/client.gen.go
@@ -0,0 +1,274 @@
+// Package issue1039 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1039
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // ExamplePatchWithBody request with any body
+ ExamplePatchWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ ExamplePatch(ctx context.Context, body ExamplePatchJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) ExamplePatchWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewExamplePatchRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) ExamplePatch(ctx context.Context, body ExamplePatchJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewExamplePatchRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewExamplePatchRequest calls the generic ExamplePatch builder with application/json body
+func NewExamplePatchRequest(server string, body ExamplePatchJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewExamplePatchRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewExamplePatchRequestWithBody generates requests for ExamplePatch with any type of body
+func NewExamplePatchRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/example")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPatch, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // ExamplePatchWithBodyWithResponse request with any body
+ ExamplePatchWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ExamplePatchResponse, error)
+
+ ExamplePatchWithResponse(ctx context.Context, body ExamplePatchJSONRequestBody, reqEditors ...RequestEditorFn) (*ExamplePatchResponse, error)
+}
+
+type ExamplePatchResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r ExamplePatchResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r ExamplePatchResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r ExamplePatchResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r ExamplePatchResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// ExamplePatchWithBodyWithResponse request with arbitrary body returning *ExamplePatchResponse
+func (c *ClientWithResponses) ExamplePatchWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ExamplePatchResponse, error) {
+ rsp, err := c.ExamplePatchWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseExamplePatchResponse(rsp)
+}
+
+func (c *ClientWithResponses) ExamplePatchWithResponse(ctx context.Context, body ExamplePatchJSONRequestBody, reqEditors ...RequestEditorFn) (*ExamplePatchResponse, error) {
+ rsp, err := c.ExamplePatch(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseExamplePatchResponse(rsp)
+}
+
+// ParseExamplePatchResponse parses an HTTP response from a ExamplePatchWithResponse call
+func ParseExamplePatchResponse(rsp *http.Response) (*ExamplePatchResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &ExamplePatchResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
diff --git a/internal/test/issues/issue-1039/defaultbehaviour/defaultbehaviour_test.go b/internal/test/issues/issue-1039/defaultbehaviour/defaultbehaviour_test.go
new file mode 100644
index 0000000000..d49813ccf2
--- /dev/null
+++ b/internal/test/issues/issue-1039/defaultbehaviour/defaultbehaviour_test.go
@@ -0,0 +1,54 @@
+package defaultbehaviour
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func ptr[T any](v T) *T {
+ return &v
+}
+
+func TestNullableDisabled(t *testing.T) {
+ // include all fields in patch request
+ patchReq := PatchRequest{
+ ComplexRequiredNullable: &ComplexRequiredNullable{
+ Name: ptr("test-name"),
+ },
+ SimpleOptionalNonNullable: ptr(SimpleOptionalNonNullable("bar")),
+ ComplexOptionalNullable: &ComplexOptionalNullable{
+ AliasName: ptr("foo-alias"),
+ Name: ptr("foo"),
+ },
+ SimpleOptionalNullable: ptr(SimpleOptionalNullable(10)),
+ SimpleRequiredNullable: ptr(SimpleRequiredNullable(5)),
+ }
+
+ expected := []byte(`{"complex_optional_nullable":{"alias_name":"foo-alias","name":"foo"},"complex_required_nullable":{"name":"test-name"},"simple_optional_non_nullable":"bar","simple_optional_nullable":10,"simple_required_nullable":5}`)
+
+ actual, err := json.Marshal(patchReq)
+ require.NoError(t, err)
+ require.Equal(t, string(expected), string(actual))
+
+ // omit some fields
+ patchReq = PatchRequest{
+ ComplexRequiredNullable: &ComplexRequiredNullable{
+ Name: ptr("test-name"),
+ },
+ // SimpleOptionalNonNullable is omitted
+ ComplexOptionalNullable: &ComplexOptionalNullable{
+ AliasName: ptr("test-alias-name"),
+ Name: ptr("test-name"),
+ },
+ SimpleOptionalNullable: ptr(SimpleOptionalNullable(10)),
+ // SimpleRequiredNullable is omitted
+ }
+
+ expected = []byte(`{"complex_optional_nullable":{"alias_name":"test-alias-name","name":"test-name"},"complex_required_nullable":{"name":"test-name"},"simple_optional_nullable":10,"simple_required_nullable":null}`)
+
+ actual, err = json.Marshal(patchReq)
+ require.NoError(t, err)
+ require.Equal(t, string(expected), string(actual))
+}
diff --git a/internal/test/issues/issue-1039/defaultbehaviour/types.gen.go b/internal/test/issues/issue-1039/defaultbehaviour/types.gen.go
new file mode 100644
index 0000000000..5ed98d88f1
--- /dev/null
+++ b/internal/test/issues/issue-1039/defaultbehaviour/types.gen.go
@@ -0,0 +1,49 @@
+// Package defaultbehaviour provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package defaultbehaviour
+
+// PatchRequest A request to patch an existing user object.
+type PatchRequest struct {
+ // ComplexOptionalNullable Complex, optional and nullable
+ ComplexOptionalNullable *ComplexOptionalNullable `json:"complex_optional_nullable,omitempty"`
+
+ // ComplexRequiredNullable Complex required and nullable
+ ComplexRequiredNullable *ComplexRequiredNullable `json:"complex_required_nullable"`
+
+ // SimpleOptionalNonNullable Simple optional and non nullable
+ SimpleOptionalNonNullable *SimpleOptionalNonNullable `json:"simple_optional_non_nullable,omitempty"`
+
+ // SimpleOptionalNullable Simple optional and nullable
+ SimpleOptionalNullable *SimpleOptionalNullable `json:"simple_optional_nullable,omitempty"`
+
+ // SimpleRequiredNullable Simple required and nullable
+ SimpleRequiredNullable *SimpleRequiredNullable `json:"simple_required_nullable"`
+}
+
+// ComplexOptionalNullable Complex, optional and nullable
+type ComplexOptionalNullable struct {
+ // AliasName Optional and nullable
+ AliasName *string `json:"alias_name,omitempty"`
+
+ // Name Optional and non nullable
+ Name *string `json:"name,omitempty"`
+}
+
+// ComplexRequiredNullable Complex required and nullable
+type ComplexRequiredNullable struct {
+ // Name Optional and non nullable
+ Name *string `json:"name,omitempty"`
+}
+
+// SimpleOptionalNonNullable Simple optional and non nullable
+type SimpleOptionalNonNullable = string
+
+// SimpleOptionalNullable Simple optional and nullable
+type SimpleOptionalNullable = int
+
+// SimpleRequiredNullable Simple required and nullable
+type SimpleRequiredNullable = int
+
+// ExamplePatchJSONRequestBody defines body for ExamplePatch for application/json ContentType.
+type ExamplePatchJSONRequestBody = PatchRequest
diff --git a/internal/test/issues/issue-1039/doc.go b/internal/test/issues/issue-1039/doc.go
new file mode 100644
index 0000000000..2997380aaf
--- /dev/null
+++ b/internal/test/issues/issue-1039/doc.go
@@ -0,0 +1,6 @@
+package issue1039
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types-config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=type-config-defaultbehaviour.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=client-config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server-config.yaml spec.yaml
diff --git a/internal/test/issues/issue-1039/issue_test.go b/internal/test/issues/issue-1039/issue_test.go
new file mode 100644
index 0000000000..1cd390c315
--- /dev/null
+++ b/internal/test/issues/issue-1039/issue_test.go
@@ -0,0 +1,197 @@
+package issue1039
+
+import (
+ _ "embed"
+ "encoding/json"
+ "testing"
+
+ "github.com/oapi-codegen/nullable"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func ptr[T any](v T) *T {
+ return &v
+}
+
+func TestNullableTypesMarshal(t *testing.T) {
+ // include all fields in patch request
+ patchReq := PatchRequest{
+ ComplexRequiredNullable: nullable.NewNullableWithValue(ComplexRequiredNullable{
+ Name: ptr("test-name"),
+ }),
+ SimpleOptionalNonNullable: ptr(SimpleOptionalNonNullable("bar")),
+ ComplexOptionalNullable: nullable.NewNullableWithValue(ComplexOptionalNullable{
+ AliasName: nullable.NewNullableWithValue("foo-alias"),
+ Name: ptr("foo"),
+ }),
+ SimpleOptionalNullable: nullable.NewNullableWithValue(10),
+ SimpleRequiredNullable: nullable.NewNullableWithValue(5),
+ }
+
+ expected := []byte(`{"complex_optional_nullable":{"alias_name":"foo-alias","name":"foo"},"complex_required_nullable":{"name":"test-name"},"simple_optional_non_nullable":"bar","simple_optional_nullable":10,"simple_required_nullable":5}`)
+
+ actual, err := json.Marshal(patchReq)
+ require.NoError(t, err)
+ require.Equal(t, string(expected), string(actual))
+
+ // omit some fields
+ patchReq = PatchRequest{
+ ComplexRequiredNullable: nullable.NewNullableWithValue(ComplexRequiredNullable{
+ Name: ptr("test-name"),
+ }),
+ // SimpleOptionalNonNullable is omitted
+ ComplexOptionalNullable: nullable.NewNullableWithValue(ComplexOptionalNullable{
+ AliasName: nullable.NewNullableWithValue("test-alias-name"),
+ Name: ptr("test-name"),
+ }),
+ SimpleOptionalNullable: nullable.NewNullableWithValue(10),
+ // SimpleRequiredNullable is omitted
+ }
+
+ expected = []byte(`{"complex_optional_nullable":{"alias_name":"test-alias-name","name":"test-name"},"complex_required_nullable":{"name":"test-name"},"simple_optional_nullable":10,"simple_required_nullable":0}`)
+
+ actual, err = json.Marshal(patchReq)
+ require.NoError(t, err)
+ require.Equal(t, string(expected), string(actual))
+}
+
+func TestNullableTypesUnmarshal(t *testing.T) {
+ type testCase struct {
+ name string
+ json []byte
+ assert func(t *testing.T, obj PatchRequest)
+ }
+ tests := []testCase{
+ {
+ name: "when empty json is provided",
+ json: []byte(`{}`),
+ assert: func(t *testing.T, obj PatchRequest) {
+ t.Helper()
+
+ // check for nullable fields
+ assert.Falsef(t, obj.SimpleRequiredNullable.IsSpecified(), "SimpleRequiredNullable field should not be set")
+ assert.Falsef(t, obj.SimpleRequiredNullable.IsNull(), "SimpleRequiredNullable field should not be null")
+
+ assert.Falsef(t, obj.SimpleOptionalNullable.IsSpecified(), "SimpleOptionalNullable field should not be set")
+ assert.Falsef(t, obj.SimpleOptionalNullable.IsNull(), "SimpleOptionalNullable field should not be null")
+
+ assert.Falsef(t, obj.ComplexOptionalNullable.IsSpecified(), "ComplexOptionalNullable field should not be set")
+ assert.Falsef(t, obj.ComplexOptionalNullable.IsNull(), "ComplexOptionalNullable field should not be null")
+
+ assert.Falsef(t, obj.ComplexRequiredNullable.IsSpecified(), "ComplexRequiredNullable field should not be set")
+ assert.Falsef(t, obj.ComplexRequiredNullable.IsNull(), "ComplexRequiredNullable field should not be null")
+
+ // check for non-nullable field
+ assert.Nilf(t, obj.SimpleOptionalNonNullable, "SimpleOptionalNonNullable field should be nil")
+ },
+ },
+
+ {
+ name: "when only empty complex_optional_nullable is provided",
+ json: []byte(`{"complex_optional_nullable":{}}`),
+ assert: func(t *testing.T, obj PatchRequest) {
+ t.Helper()
+ // check for nullable field
+ assert.Truef(t, obj.ComplexOptionalNullable.IsSpecified(), "ComplexOptionalNullable field should be set")
+ assert.Falsef(t, obj.ComplexOptionalNullable.IsNull(), "ComplexOptionalNullable field should not be null")
+
+ // other simple nullable fields should not be set and should not be null
+ assert.Falsef(t, obj.SimpleRequiredNullable.IsSpecified(), "SimpleRequiredNullable field should not be set")
+ assert.Falsef(t, obj.SimpleRequiredNullable.IsNull(), "SimpleRequiredNullable field should not be null")
+
+ assert.Falsef(t, obj.SimpleOptionalNullable.IsSpecified(), "SimpleOptionalNullable field should not be set")
+ assert.Falsef(t, obj.SimpleOptionalNullable.IsNull(), "SimpleOptionalNullable field should not be null")
+
+ // other complex nullable fields should not be set and should not be null
+ assert.Falsef(t, obj.ComplexRequiredNullable.IsSpecified(), "ComplexRequiredNullable field should not be set")
+ assert.Falsef(t, obj.ComplexRequiredNullable.IsNull(), "ComplexRequiredNullable field should not be null")
+
+ // other non-nullable field should have its zero value
+ assert.Nilf(t, obj.SimpleOptionalNonNullable, "SimpleOptionalNonNullable field should be nil")
+
+ },
+ },
+
+ {
+ name: "when only complex_optional_nullable with its `name` child field is provided",
+ json: []byte(`{"complex_optional_nullable":{"name":"test-name"}}`),
+ assert: func(t *testing.T, obj PatchRequest) {
+ t.Helper()
+
+ assert.Truef(t, obj.ComplexOptionalNullable.IsSpecified(), "ComplexOptionalNullable field should be set")
+ assert.Falsef(t, obj.ComplexOptionalNullable.IsNull(), "ComplexOptionalNullable field should not be null")
+
+ gotComplexObj, err := obj.ComplexOptionalNullable.Get()
+ require.NoError(t, err)
+ assert.Equalf(t, "test-name", string(*gotComplexObj.Name), "name should be test-name")
+
+ assert.Falsef(t, gotComplexObj.AliasName.IsSpecified(), "child field `alias name` should not be specified")
+ assert.Falsef(t, gotComplexObj.AliasName.IsNull(), "child field `alias name` should not be null")
+ },
+ },
+
+ {
+ name: "when only complex_optional_nullable child fields `name` and `alias name` are provided with non-zero and null values respectively",
+ json: []byte(`{"complex_optional_nullable":{"name":"test-name","alias_name":null}}`),
+ assert: func(t *testing.T, obj PatchRequest) {
+ t.Helper()
+
+ assert.Truef(t, obj.ComplexOptionalNullable.IsSpecified(), "ComplexOptionalNullable field should be set")
+ assert.Falsef(t, obj.ComplexOptionalNullable.IsNull(), "ComplexOptionalNullable field should not be null")
+
+ gotComplexObj, err := obj.ComplexOptionalNullable.Get()
+ require.NoError(t, err)
+ assert.Equalf(t, "test-name", string(*gotComplexObj.Name), "name should be test-name")
+
+ assert.Truef(t, gotComplexObj.AliasName.IsSpecified(), "child field `alias name` should be set")
+ assert.Truef(t, gotComplexObj.AliasName.IsNull(), "child field `alias name` should be null")
+ },
+ },
+
+ {
+ name: "when simple_required_nullable is null ",
+ json: []byte(`{"simple_required_nullable":null}`),
+ assert: func(t *testing.T, obj PatchRequest) {
+ t.Helper()
+
+ assert.Truef(t, obj.SimpleRequiredNullable.IsSpecified(), "SimpleRequiredNullable field should be set")
+ assert.Truef(t, obj.SimpleRequiredNullable.IsNull(), "SimpleRequiredNullable field should be null")
+ },
+ },
+
+ {
+ name: "when simple_required_nullable is null and organization has non zero value",
+ json: []byte(`{"complex_optional_nullable":{"name":"foo","alias_name":"bar"},"simple_required_nullable":null}`),
+ assert: func(t *testing.T, obj PatchRequest) {
+ t.Helper()
+
+ assert.Truef(t, obj.SimpleRequiredNullable.IsSpecified(), "SimpleRequiredNullable field should be set")
+ assert.Truef(t, obj.SimpleRequiredNullable.IsNull(), "SimpleRequiredNullable field should be null")
+
+ assert.Truef(t, obj.ComplexOptionalNullable.IsSpecified(), "ComplexOptionalNullable field should be set")
+ assert.Falsef(t, obj.ComplexOptionalNullable.IsNull(), "ComplexOptionalNullable field should not be null")
+
+ gotComplexObj, err := obj.ComplexOptionalNullable.Get()
+ require.NoError(t, err)
+ assert.Equalf(t, "foo", string(*gotComplexObj.Name), "child field `name` should be foo")
+
+ assert.Truef(t, gotComplexObj.AliasName.IsSpecified(), "child field `alias name` should be set")
+ assert.Falsef(t, gotComplexObj.AliasName.IsNull(), "child field `alias name` should not be null")
+
+ gotAliasName, err := gotComplexObj.AliasName.Get()
+ require.NoError(t, err)
+ assert.Equalf(t, "bar", gotAliasName, "child field `alias name` should be bar")
+ },
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ var obj PatchRequest
+ err := json.Unmarshal(tt.json, &obj)
+ require.NoError(t, err)
+
+ tt.assert(t, obj)
+ })
+ }
+}
diff --git a/internal/test/issues/issue-1039/server-config.yaml b/internal/test/issues/issue-1039/server-config.yaml
new file mode 100644
index 0000000000..e1e7879932
--- /dev/null
+++ b/internal/test/issues/issue-1039/server-config.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue1039
+generate:
+ chi-server: true
+output: server.gen.go
diff --git a/internal/test/issues/issue-1039/server.gen.go b/internal/test/issues/issue-1039/server.gen.go
new file mode 100644
index 0000000000..a39f95dae7
--- /dev/null
+++ b/internal/test/issues/issue-1039/server.gen.go
@@ -0,0 +1,170 @@
+// Package issue1039 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1039
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/go-chi/chi/v5"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (PATCH /example)
+ ExamplePatch(w http.ResponseWriter, r *http.Request)
+}
+
+// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
+
+type Unimplemented struct{}
+
+// (PATCH /example)
+func (_ Unimplemented) ExamplePatch(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// ExamplePatch operation middleware
+func (siw *ServerInterfaceWrapper) ExamplePatch(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.ExamplePatch(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{})
+}
+
+type ChiServerOptions struct {
+ BaseURL string
+ BaseRouter chi.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = chi.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.Group(func(r chi.Router) {
+ r.Patch(options.BaseURL+"/example", wrapper.ExamplePatch)
+ })
+
+ return r
+}
diff --git a/internal/test/issues/issue-1039/spec.yaml b/internal/test/issues/issue-1039/spec.yaml
new file mode 100644
index 0000000000..821b71066e
--- /dev/null
+++ b/internal/test/issues/issue-1039/spec.yaml
@@ -0,0 +1,84 @@
+openapi: 3.0.1
+info:
+ version: '0.0.1'
+ title: example
+ description: |
+ Make sure that nullable types are generated properly
+paths:
+ /example:
+ patch:
+ operationId: examplePatch
+ requestBody:
+ description: The patch body
+ required: true
+ content:
+ application/json:
+ example:
+ name: Example Patch
+ schema:
+ $ref: "#/components/schemas/PatchRequest"
+ responses:
+ '200':
+ description: "OK"
+
+components:
+ schemas:
+ PatchRequest:
+ type: object
+ description: A request to patch an existing user object.
+ required:
+ - simple_required_nullable
+ - complex_required_nullable
+ properties:
+ simple_required_nullable:
+ # required and nullable
+ $ref: "#/components/schemas/simple_required_nullable"
+ simple_optional_nullable:
+ # optional and nullable
+ $ref: "#/components/schemas/simple_optional_nullable"
+ simple_optional_non_nullable:
+ # optional and non-nullable
+ $ref: "#/components/schemas/simple_optional_non_nullable"
+ complex_required_nullable:
+ # required and nullable
+ $ref: "#/components/schemas/complex_required_nullable"
+ complex_optional_nullable:
+ # optional and nullable
+ $ref: "#/components/schemas/complex_optional_nullable"
+ additionalProperties: false
+
+ simple_required_nullable:
+ type: integer
+ nullable: true
+ description: Simple required and nullable
+
+ simple_optional_nullable:
+ type: integer
+ nullable: true
+ description: Simple optional and nullable
+
+ simple_optional_non_nullable:
+ type: string
+ description: Simple optional and non nullable
+
+ complex_required_nullable:
+ type: object
+ nullable: true
+ description: Complex required and nullable
+ properties:
+ name:
+ description: Optional and non nullable
+ type: string
+
+ complex_optional_nullable:
+ type: object
+ description: Complex, optional and nullable
+ properties:
+ alias_name:
+ description: Optional and nullable
+ type: string
+ nullable: true
+ name:
+ description: Optional and non nullable
+ type: string
+ nullable: true
diff --git a/internal/test/issues/issue-1039/type-config-defaultbehaviour.yaml b/internal/test/issues/issue-1039/type-config-defaultbehaviour.yaml
new file mode 100644
index 0000000000..2b07679083
--- /dev/null
+++ b/internal/test/issues/issue-1039/type-config-defaultbehaviour.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: defaultbehaviour
+generate:
+ models: true
+output: defaultbehaviour/types.gen.go
diff --git a/internal/test/issues/issue-1039/types-config.yaml b/internal/test/issues/issue-1039/types-config.yaml
new file mode 100644
index 0000000000..9f97d8bc62
--- /dev/null
+++ b/internal/test/issues/issue-1039/types-config.yaml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue1039
+generate:
+ models: true
+output-options:
+ nullable-type: true
+output: types.gen.go
diff --git a/internal/test/issues/issue-1039/types.gen.go b/internal/test/issues/issue-1039/types.gen.go
new file mode 100644
index 0000000000..9c11915344
--- /dev/null
+++ b/internal/test/issues/issue-1039/types.gen.go
@@ -0,0 +1,53 @@
+// Package issue1039 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1039
+
+import (
+ "github.com/oapi-codegen/nullable"
+)
+
+// PatchRequest A request to patch an existing user object.
+type PatchRequest struct {
+ // ComplexOptionalNullable Complex, optional and nullable
+ ComplexOptionalNullable nullable.Nullable[ComplexOptionalNullable] `json:"complex_optional_nullable,omitempty"`
+
+ // ComplexRequiredNullable Complex required and nullable
+ ComplexRequiredNullable nullable.Nullable[ComplexRequiredNullable] `json:"complex_required_nullable"`
+
+ // SimpleOptionalNonNullable Simple optional and non nullable
+ SimpleOptionalNonNullable *SimpleOptionalNonNullable `json:"simple_optional_non_nullable,omitempty"`
+
+ // SimpleOptionalNullable Simple optional and nullable
+ SimpleOptionalNullable nullable.Nullable[SimpleOptionalNullable] `json:"simple_optional_nullable,omitempty"`
+
+ // SimpleRequiredNullable Simple required and nullable
+ SimpleRequiredNullable nullable.Nullable[SimpleRequiredNullable] `json:"simple_required_nullable"`
+}
+
+// ComplexOptionalNullable Complex, optional and nullable
+type ComplexOptionalNullable struct {
+ // AliasName Optional and nullable
+ AliasName nullable.Nullable[string] `json:"alias_name,omitempty"`
+
+ // Name Optional and non nullable
+ Name *string `json:"name,omitempty"`
+}
+
+// ComplexRequiredNullable Complex required and nullable
+type ComplexRequiredNullable struct {
+ // Name Optional and non nullable
+ Name *string `json:"name,omitempty"`
+}
+
+// SimpleOptionalNonNullable Simple optional and non nullable
+type SimpleOptionalNonNullable = string
+
+// SimpleOptionalNullable Simple optional and nullable
+type SimpleOptionalNullable = int
+
+// SimpleRequiredNullable Simple required and nullable
+type SimpleRequiredNullable = int
+
+// ExamplePatchJSONRequestBody defines body for ExamplePatch for application/json ContentType.
+type ExamplePatchJSONRequestBody = PatchRequest
diff --git a/internal/test/issues/issue-1087/api.gen.go b/internal/test/issues/issue-1087/api.gen.go
index d39ab9117f..527ceb2e45 100644
--- a/internal/test/issues/issue-1087/api.gen.go
+++ b/internal/test/issues/issue-1087/api.gen.go
@@ -1,6 +1,6 @@
// Package issue1087 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package issue1087
import (
@@ -12,8 +12,8 @@ import (
"net/url"
"strings"
- externalRef0 "github.com/deepmap/oapi-codegen/internal/test/issues/issue-1087/deps"
"github.com/go-chi/chi/v5"
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1087/deps"
)
// Thing defines model for Thing.
@@ -33,6 +33,9 @@ type N404 = externalRef0.Error
// ThingResponse Object containing list of Things
type ThingResponse = ThingList
+// bearerAuthWebhookContextKey is the context key for bearerAuthWebhook security scheme
+type bearerAuthWebhookContextKey string
+
// RequestEditorFn is the function signature for the RequestEditor callback function
type RequestEditorFn func(ctx context.Context, req *http.Request) error
@@ -141,7 +144,7 @@ func NewGetThingsRequest(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -206,6 +209,36 @@ type GetThingsResponse struct {
JSON500 *externalRef0.DefaultError
}
+// GetJSON200 returns JSON200
+func (r GetThingsResponse) GetJSON200() *ThingResponse {
+ return r.JSON200
+}
+
+// GetJSON401 returns JSON401
+func (r GetThingsResponse) GetJSON401() *externalRef0.N401 {
+ return r.JSON401
+}
+
+// GetJSON403 returns JSON403
+func (r GetThingsResponse) GetJSON403() *externalRef0.N403 {
+ return r.JSON403
+}
+
+// GetJSON404 returns JSON404
+func (r GetThingsResponse) GetJSON404() *N404 {
+ return r.JSON404
+}
+
+// GetJSON500 returns JSON500
+func (r GetThingsResponse) GetJSON500() *externalRef0.DefaultError {
+ return r.JSON500
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetThingsResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetThingsResponse) Status() string {
if r.HTTPResponse != nil {
@@ -222,6 +255,14 @@ func (r GetThingsResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetThingsResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// GetThingsWithResponse request returning *GetThingsResponse
func (c *ClientWithResponses) GetThingsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetThingsResponse, error) {
rsp, err := c.GetThings(ctx, reqEditors...)
@@ -319,7 +360,6 @@ type MiddlewareFunc func(http.Handler) http.Handler
// GetThings operation middleware
func (siw *ServerInterfaceWrapper) GetThings(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.GetThings(w, r)
@@ -329,7 +369,7 @@ func (siw *ServerInterfaceWrapper) GetThings(w http.ResponseWriter, r *http.Requ
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
type UnescapedCookieParamError struct {
diff --git a/internal/test/issues/issue-1087/deps/config.yaml b/internal/test/issues/issue-1087/deps/config.yaml
index 01ee1951a0..95c23f63e0 100644
--- a/internal/test/issues/issue-1087/deps/config.yaml
+++ b/internal/test/issues/issue-1087/deps/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
package: deps
output:
deps.gen.go
@@ -5,4 +6,4 @@ output-options:
skip-prune: true
generate:
models: true
- embedded-spec: true
\ No newline at end of file
+ embedded-spec: true
diff --git a/internal/test/issues/issue-1087/deps/deps.gen.go b/internal/test/issues/issue-1087/deps/deps.gen.go
index c20ce82fad..3661be9d81 100644
--- a/internal/test/issues/issue-1087/deps/deps.gen.go
+++ b/internal/test/issues/issue-1087/deps/deps.gen.go
@@ -1,11 +1,11 @@
// Package deps provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package deps
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/url"
@@ -31,7 +31,22 @@ type BaseError struct {
}
// Error defines model for Error.
-type Error = BaseError
+type Error struct {
+ // Code The underlying http status code
+ Code int32 `json:"code"`
+
+ // Domain The domain where the error is originating from as defined by the service
+ Domain string `json:"domain"`
+
+ // Message A simple message in english describing the error and can be returned to the consumer
+ Message string `json:"message"`
+
+ // Metadata Any additional details to be conveyed as determined by the service. If present, will return map of key value pairs
+ Metadata *map[string]string `json:"metadata,omitempty"`
+
+ // Reason A reason code specific to the service and can be used to identify the exact issue. Should be unique within a domain
+ Reason string `json:"reason"`
+}
// N401 defines model for 401.
type N401 = Error
@@ -45,41 +60,42 @@ type N410 = Error
// DefaultError defines model for DefaultError.
type DefaultError = Error
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/7SV34/jNBDH/5WR4TFq0+siobwVDtAiAacDnk6rlRtPmjmcsc+edLes+r8jO2nTH6tb",
- "7qR9ahPPeL7zmR95UrXrvGNkiap6UgGjdxwxP9yUi/RTOxZkSX+195ZqLeR4/jE6Tu/wUXfe4mBpUFU3",
- "5aJQxnWaWFVq1UurCtVhjHqDqlK3vNWWDOheWmQZr1OFCqjzlQeL+9W5xb5QsW6x0ynUtwEbValv5pP+",
- "+XAa5z+F4ILa7wsl+Chzb7OSpxPvo2b164MARcBHTwGNKpTsfHofJRBv1D7dYjDWgXwWUam/OSl3gf5F",
- "M4NbNkkfRpBWC/jgtmTQQB3QJO3axnQ/O4GcVMriplx+Hdfl57iu6hpjhLfIlBM54hwO7seDV6F4GftF",
- "iD+7sCZjkK8IBvzUYxSoNSdoa4QJd4a3KL8K3qI8gXcG7hfHeMorP78KpjHSi3TeY+2CAXZgHW8wgN5q",
- "snpts6632OjeyhD4ZRRflsaVljEaYDKAw36AxgXQvBteRyAGaRFW724zivHWFPQHHfEo1QfnMQgN+2Wo",
- "zNNFwL9ahJ4NBrsj3kAr4iGKlj5CdigmoN+VZaEaFzotqlLEsnwz4SUW3GBIxA51fy7UcAYPLQbMOQyJ",
- "UgQXaEOsJalogutARzDYEKOB9S7bRgxbqs80qesCnzTbpYIVREp+MFokkMgbS7GFwXKdwk+6NJs0Gmku",
- "Akofkhhx2aB2HPsOw5ma1QZPRsmmKZVWMyy+f16naKMld4s2hpJKbd+dVe3K6SIj3sHkCgZFk41J4zpL",
- "3OIOzYBSMHTP0JzBbQM+YESWAh7I2jFV6LQH18A/uEvLtEfwmkI8zffYYrvfdZdknj6moqb1kjf9/pi+",
- "W3/EWnLfHk+rD2pstrF3phreXTkW6tjg2to/GlV9+PywTTOxvysuhuKwhq47ZTjJQwDRY00N1Yfaj+hO",
- "26OPQ2tQ/g41A2J81HX64MUeZ/Bn63prsi3Tpx7hgaQlBg3HpKdGep+j3/84ULlcYf8P3XHJXjNMVxA3",
- "LncYSQ75mzNoU3m3GOJA4c2snJWJuPPI2pOq1HJWzpaqUF5Lmwim9YMhueQ69MGqSs3V/m7/XwAAAP//",
- "TAbhS+0IAAA=",
+ "tJXfj+M0EMf/lZHhMWrT6yKhvBUO0CIBpwOeTquVG0+aOZyxz550t6z6vyM7adMfq1vupH1qE894vvOZ",
+ "H3lSteu8Y2SJqnpSAaN3HDE/3JSL9FM7FmRJf7X3lmot5Hj+MTpO7/BRd97iYGlQVTflolDGdZpYVWrV",
+ "S6sK1WGMeoOqUre81ZYM6F5aZBmvU4UKqPOVB4v71bnFvlCxbrHTKdS3ARtVqW/mk/75cBrnP4Xggtrv",
+ "CyX4KHNvs5KnE++jZvXrgwBFwEdPAY0qlOx8eh8lEG/UPt1iMNaBfBZRqb85KXeB/kUzg1s2SR9GkFYL",
+ "+OC2ZNBAHdAk7drGdD87gZxUyuKmXH4d1+XnuK7qGmOEt8iUEzniHA7ux4NXoXgZ+0WIP7uwJmOQrwgG",
+ "/NRjFKg1J2hrhAl3hrcovwreojyBdwbuF8d4yis/vwqmMdKLdN5j7YIBdmAdbzCA3mqyem2zrrfY6N7K",
+ "EPhlFF+WxpWWMRpgMoDDfoDGBdC8G15HIAZpEVbvbjOK8dYU9Acd8SjVB+cxCA37ZajM00XAv1qEng0G",
+ "uyPeQCviIYqWPkJ2KCag35VloRoXOi2qUsSyfDPhJRbcYEjEDnV/LtRwBg8tBsw5DIlSBBdoQ6wlqWiC",
+ "60BHMNgQo4H1LttGDFuqzzSp6wKfNNulghVESn4wWiSQyBtLsYXBcp3CT7o0mzQaaS4CSh+SGHHZoHYc",
+ "+w7DmZrVBk9GyaYplVYzLL5/XqdooyV3izaGkkpt351V7crpIiPeweQKBkWTjUnjOkvc4g7NgFIwdM/Q",
+ "nMFtAz5gRJYCHsjaMVXotAfXwD+4S8u0R/CaQjzN99hiu991l2SePqaipvWSN/3+mL5bf8Ract8eT6sP",
+ "amy2sXemGt5dORbq2ODa2j8aVX34/LBNM7G/Ky6G4rCGrjtlOMlDANFjTQ3Vh9qP6E7bo49Da1D+DjUD",
+ "YnzUdfrgxR5n8GfremuyLdOnHuGBpCUGDcekp0Z6n6Pf/zhQuVxh/w/dccleM0xXEDcudxhJDvmbM2hT",
+ "ebcY4kDhzayclYm488jak6rUclbOlqpQXkubCKb1gyG55Dr0wapKzdX+bv9fAAAA//8=",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -87,7 +103,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -105,12 +121,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -136,3 +152,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1087/deps/doc.go b/internal/test/issues/issue-1087/deps/doc.go
index 5f2295d74e..0684d56cae 100644
--- a/internal/test/issues/issue-1087/deps/doc.go
+++ b/internal/test/issues/issue-1087/deps/doc.go
@@ -1,3 +1,3 @@
package deps
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml my-deps.json
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml my-deps.json
diff --git a/internal/test/issues/issue-1087/doc.go b/internal/test/issues/issue-1087/doc.go
index 521fd0f115..2ad8db520c 100644
--- a/internal/test/issues/issue-1087/doc.go
+++ b/internal/test/issues/issue-1087/doc.go
@@ -1,3 +1,3 @@
package issue1087
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.config.yaml spec.yaml
diff --git a/internal/test/issues/issue-1087/server.config.yaml b/internal/test/issues/issue-1087/server.config.yaml
index 8275b35b4c..6d795c05d7 100644
--- a/internal/test/issues/issue-1087/server.config.yaml
+++ b/internal/test/issues/issue-1087/server.config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: issue1087
output:
api.gen.go
@@ -7,4 +8,4 @@ generate:
embedded-spec: false
client: true
import-mapping:
- ./deps/my-deps.json: github.com/deepmap/oapi-codegen/internal/test/issues/issue-1087/deps
+ ./deps/my-deps.json: github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1087/deps
diff --git a/internal/test/issues/issue-1093/api/child/child.gen.go b/internal/test/issues/issue-1093/api/child/child.gen.go
index a5fc3167e5..1275e1b202 100644
--- a/internal/test/issues/issue-1093/api/child/child.gen.go
+++ b/internal/test/issues/issue-1093/api/child/child.gen.go
@@ -1,11 +1,11 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -15,10 +15,9 @@ import (
"path"
"strings"
- externalRef0 "github.com/deepmap/oapi-codegen/internal/test/issues/issue-1093/api/parent"
"github.com/getkin/kin-openapi/openapi3"
"github.com/gin-gonic/gin"
- strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin"
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1093/api/parent"
)
// ServerInterface represents all server handlers.
@@ -90,10 +89,15 @@ type GetPetsResponseObject interface {
type GetPets200JSONResponse externalRef0.Pet
func (response GetPets200JSONResponse) VisitGetPetsResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
// StrictServerInterface represents all server handlers.
@@ -103,16 +107,61 @@ type StrictServerInterface interface {
GetPets(ctx context.Context, request GetPetsRequestObject) (GetPetsResponseObject, error)
}
-type StrictHandlerFunc = strictgin.StrictGinHandlerFunc
-type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc
+type StrictHandlerFunc func(ctx *gin.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictGinServerOptions struct {
+ // RequestErrorHandlerFunc is called when a request cannot be parsed or
+ // decoded. It is invoked for JSON bind failures, form parse/bind errors,
+ // multipart reader errors, media type parse errors, missing multipart
+ // boundaries, and request body read errors. The default returns 400.
+ RequestErrorHandlerFunc func(ctx *gin.Context, err error)
+ // HandlerErrorFunc is called when the application handler (or any
+ // middleware wrapping it) returns a non-nil error. The default returns 500.
+ HandlerErrorFunc func(ctx *gin.Context, err error)
+ // ResponseErrorHandlerFunc is called when the response object fails to
+ // serialize (Visit*Response returns an error) or when the handler returns
+ // an unexpected response type. The default returns 500.
+ ResponseErrorHandlerFunc func(ctx *gin.Context, err error)
+}
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
- return &strictHandler{ssi: ssi, middlewares: middlewares}
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictGinServerOptions{
+ RequestErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ },
+ HandlerErrorFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ ResponseErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictGinServerOptions) ServerInterface {
+ if options.RequestErrorHandlerFunc == nil {
+ options.RequestErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.HandlerErrorFunc == nil {
+ options.HandlerErrorFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.ResponseErrorHandlerFunc == nil {
+ options.ResponseErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
}
type strictHandler struct {
ssi StrictServerInterface
middlewares []StrictMiddlewareFunc
+ options StrictGinServerOptions
}
// GetPets operation middleware
@@ -129,43 +178,44 @@ func (sh *strictHandler) GetPets(ctx *gin.Context) {
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(GetPetsResponseObject); ok {
if err := validResponse.VisitGetPetsResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/2xRQW7jMAz8isDdoxF7tzd9oOgtKHpLc1BlOlZgSyxJFwgC/72g3CAI0BMpYcgZzlwh",
- "lplKxqwC/goSR5xDbfeoVogLIWvC+pnDjFb1QggeRDnlE6wNaDj98r82wPi5JMYe/GGbPjY3VPk4Y1RY",
- "DZbyUGxBjxI5kaaSwcPbmMTFMU29E8Lo0kyFVdxcepzEDVxmpyM6CoxZKwYa0KST7a+D0MAXsmz7/u06",
- "E1sIc6AEHp523a6DBijoWA9sCTcnTtv5j3peURfO4gj1Ti4XUbQ2aH0vguzGIC7EiCJOy3uGSsrB9rz0",
- "4OEZdW9MZpBQybL5+7/rrMSSFXMVEIimFOtgexZTcUvJur+MA3j4095jbH8ybC3A6u3jDcHJUoUNy+Ru",
- "5AY0qCCbW+APV1h4Ag/t5uJ6XL8DAAD//w/2Vy4sAgAA",
+ "bFHBbtswDP0VgdvRiL3tph8YdguG3tKgUGU6VmBLLEkXCAL/e0G5QRqgJ5H24+Pje1eIZaaSMauAv4LE",
+ "EedQSwqMWV/2qLXjQsiasP7LYUZ79UIIHkQ55ROsDWg4ffN9bYDxbUmMPfjDNn1sbqjyesaosBos5aEY",
+ "QY8SOZGmksHD05jExTFNvRPC6NJMhVXcXHqcxA1cZqcjuk1yxUADmnQy/joIDbwjy8b3a9eZ2EKYAyXw",
+ "8GfX7TpogIKO9cCWcDPktJ3/qOc/6sJZHKHel8tFFK0MWvtFkN0YxIUYUcRpec5Ql3Iwnn89ePiLurdN",
+ "ZpBQybL5+7vr7IklK+YqIBBNKdbB9iym4haWVT8ZB/Dwo72n2X5G2X7JsVr8eEpwslR9wzK5mwYDGlSQ",
+ "zTTwhyssPIGHdjNzPa4fAQAA//8=",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -173,7 +223,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -188,9 +238,7 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
res[pathToFile] = rawSpec
}
- pathPrefix := path.Dir(pathToFile)
-
- for rawPath, rawFunc := range externalRef0.PathToRawSpec(path.Join(pathPrefix, "parent.api.yaml")) {
+ for rawPath, rawFunc := range externalRef0.PathToRawSpec(path.Join(path.Dir(pathToFile), "parent.api.yaml")) {
if _, ok := res[rawPath]; ok {
// it is not possible to compare functions in golang, so always overwrite the old value
}
@@ -199,12 +247,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -230,3 +278,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1093/api/parent/parent.gen.go b/internal/test/issues/issue-1093/api/parent/parent.gen.go
index e1ebfa4d3f..d1696c0068 100644
--- a/internal/test/issues/issue-1093/api/parent/parent.gen.go
+++ b/internal/test/issues/issue-1093/api/parent/parent.gen.go
@@ -1,11 +1,11 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -17,7 +17,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/gin-gonic/gin"
- strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin"
)
// Pet defines model for Pet.
@@ -95,10 +94,15 @@ type GetPetsResponseObject interface {
type GetPets200JSONResponse Pet
func (response GetPets200JSONResponse) VisitGetPetsResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
// StrictServerInterface represents all server handlers.
@@ -108,16 +112,61 @@ type StrictServerInterface interface {
GetPets(ctx context.Context, request GetPetsRequestObject) (GetPetsResponseObject, error)
}
-type StrictHandlerFunc = strictgin.StrictGinHandlerFunc
-type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc
+type StrictHandlerFunc func(ctx *gin.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictGinServerOptions struct {
+ // RequestErrorHandlerFunc is called when a request cannot be parsed or
+ // decoded. It is invoked for JSON bind failures, form parse/bind errors,
+ // multipart reader errors, media type parse errors, missing multipart
+ // boundaries, and request body read errors. The default returns 400.
+ RequestErrorHandlerFunc func(ctx *gin.Context, err error)
+ // HandlerErrorFunc is called when the application handler (or any
+ // middleware wrapping it) returns a non-nil error. The default returns 500.
+ HandlerErrorFunc func(ctx *gin.Context, err error)
+ // ResponseErrorHandlerFunc is called when the response object fails to
+ // serialize (Visit*Response returns an error) or when the handler returns
+ // an unexpected response type. The default returns 500.
+ ResponseErrorHandlerFunc func(ctx *gin.Context, err error)
+}
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
- return &strictHandler{ssi: ssi, middlewares: middlewares}
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictGinServerOptions{
+ RequestErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ },
+ HandlerErrorFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ ResponseErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictGinServerOptions) ServerInterface {
+ if options.RequestErrorHandlerFunc == nil {
+ options.RequestErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.HandlerErrorFunc == nil {
+ options.HandlerErrorFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.ResponseErrorHandlerFunc == nil {
+ options.ResponseErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
}
type strictHandler struct {
ssi StrictServerInterface
middlewares []StrictMiddlewareFunc
+ options StrictGinServerOptions
}
// GetPets operation middleware
@@ -134,43 +183,44 @@ func (sh *strictHandler) GetPets(ctx *gin.Context) {
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(GetPetsResponseObject); ok {
if err := validResponse.VisitGetPetsResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/2xRwa7TMBD8FWvhGDUBbv4BxO0JcXv04Dqb2lViL7sbUBXl39E6rVAlTru2xjPjmQ1i",
- "XagWLCrgN5CYcAltfUO1QVwJWTO2yxIWtKl3QvAgyrlcYe9Aw/U/93sHjL/WzDiCfz9en7snql5uGBV2",
- "g+UyVSMYUSJn0lwLePiRsjgKjEWdEEaXgriljjiL+5NyTC4wurxQZcXRXe5OE7qY8jw2PHSgWWcTO1ig",
- "g9/IcrB/Og1mvRKWQBk8fDkNpwE6oKCpfbcnPHK5HmG8uvuOunIRR6hu4ro0cbmLoq1B23kV5GY7xIgi",
- "TuvPAk2Ug/F8G8HDV9Q3U7K4hGqRI+3Pw2Aj1qLm3W8QiOYc28P+Jubi2ZltHxkn8PCh/1dq/2i0tzpb",
- "0q9/CE7WZmxaZ/cUN6BBBdnSAv++wcozeOgfMe7n/W8AAAD///mNvoM7AgAA",
+ "bFHBrtMwEPwVa+EYNQFu/gHE7Qlxe/TgOpvaVWIvuxtQFeXf0TqtUCVOu7bGM+OZDWJdqBYsKuA3kJhw",
+ "CW19Q7VBXAlZM7bLEha0qXdC8CDKuVxh70DD9T/3eweMv9bMOIJ/P16fuyeqXm4YFXaD5TJVIxhRImfS",
+ "XAt4+JGyOAqMRZ0QRpeCuKWOOIv7k3JMLjC6vFBlxdFd7k4TupjyPDY8dKBZZxM7WKCD38hysH86DWa9",
+ "EpZAGTx8OQ2nATqgoKl9tyc8crkeYby6+466chFHqG7iujRxuYuirUHbeRXkZjvEiCJO688CTZSD8Xwb",
+ "wcNX1DdTsriEapEj7c/DYCPWoubdbxCI5hzbw/4m5uLZmW0fGSfw8KH/V2r/aLS3OlvSr38ITtZmbFpn",
+ "9xQ3oEEF2dIC/77ByjN46B8x7uf9bwAAAP//",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -178,7 +228,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -196,12 +246,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -227,3 +277,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1093/child.cfg.yaml b/internal/test/issues/issue-1093/child.cfg.yaml
index 1ebaf789ad..4efb750c1e 100644
--- a/internal/test/issues/issue-1093/child.cfg.yaml
+++ b/internal/test/issues/issue-1093/child.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
# child.yaml
package: api
generate:
@@ -6,5 +7,5 @@ generate:
strict-server: true
models: true
import-mapping:
- parent.api.yaml: github.com/deepmap/oapi-codegen/internal/test/issues/issue-1093/api/parent
-output: api/child/child.gen.go
\ No newline at end of file
+ parent.api.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1093/api/parent
+output: api/child/child.gen.go
diff --git a/internal/test/issues/issue-1093/doc.go b/internal/test/issues/issue-1093/doc.go
index b80f0e5ee9..6996cdd2d8 100644
--- a/internal/test/issues/issue-1093/doc.go
+++ b/internal/test/issues/issue-1093/doc.go
@@ -1,6 +1,6 @@
// This is an example of how to reference models of one api specification from another.
-// See https://github.com/deepmap/oapi-codegen/issues/1093
+// See https://github.com/oapi-codegen/oapi-codegen/issues/1093
package issue1093
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config parent.cfg.yaml parent.api.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config child.cfg.yaml child.api.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config parent.cfg.yaml parent.api.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config child.cfg.yaml child.api.yaml
diff --git a/internal/test/issues/issue-1093/issue_test.go b/internal/test/issues/issue-1093/issue_test.go
index 277e7462d0..990de85384 100644
--- a/internal/test/issues/issue-1093/issue_test.go
+++ b/internal/test/issues/issue-1093/issue_test.go
@@ -7,7 +7,7 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/stretchr/testify/require"
- "github.com/deepmap/oapi-codegen/pkg/codegen"
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/codegen"
)
//go:embed child.api.yaml
@@ -29,7 +29,7 @@ func TestIssue(t *testing.T) {
EmbeddedSpec: true,
},
ImportMapping: map[string]string{
- "parent.api.yaml": "github.com/deepmap/oapi-codegen/internal/test/issues/issue-1093/api/parent",
+ "parent.api.yaml": "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1093/api/parent",
},
}
diff --git a/internal/test/issues/issue-1093/parent.cfg.yaml b/internal/test/issues/issue-1093/parent.cfg.yaml
index 306f456cc6..ef00a99d61 100644
--- a/internal/test/issues/issue-1093/parent.cfg.yaml
+++ b/internal/test/issues/issue-1093/parent.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
gin-server: true
@@ -6,4 +7,4 @@ generate:
models: true
output: api/parent/parent.gen.go
output-options:
- skip-prune: true
\ No newline at end of file
+ skip-prune: true
diff --git a/internal/test/issues/issue-1127/api.gen.go b/internal/test/issues/issue-1127/api.gen.go
index cc8412e49e..d3fa8e4293 100644
--- a/internal/test/issues/issue-1127/api.gen.go
+++ b/internal/test/issues/issue-1127/api.gen.go
@@ -1,6 +1,6 @@
// Package issue1127 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package issue1127
// Whatever defines model for Whatever.
diff --git a/internal/test/issues/issue-1127/doc.go b/internal/test/issues/issue-1127/doc.go
index 78bc2ef06c..d591e52f84 100644
--- a/internal/test/issues/issue-1127/doc.go
+++ b/internal/test/issues/issue-1127/doc.go
@@ -1,3 +1,3 @@
package issue1127
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.config.yaml spec.yaml
diff --git a/internal/test/issues/issue-1127/server.config.yaml b/internal/test/issues/issue-1127/server.config.yaml
index 86e0e1e42d..fd6b9de19d 100644
--- a/internal/test/issues/issue-1127/server.config.yaml
+++ b/internal/test/issues/issue-1127/server.config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: issue1127
output:
api.gen.go
diff --git a/internal/test/issues/issue-1168/api.gen.go b/internal/test/issues/issue-1168/api.gen.go
index c520f21c80..d681fbd81c 100644
--- a/internal/test/issues/issue-1168/api.gen.go
+++ b/internal/test/issues/issue-1168/api.gen.go
@@ -1,6 +1,6 @@
// Package issue1168 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package issue1168
import (
diff --git a/internal/test/issues/issue-1168/doc.go b/internal/test/issues/issue-1168/doc.go
index 9916b7b85b..2541e721d1 100644
--- a/internal/test/issues/issue-1168/doc.go
+++ b/internal/test/issues/issue-1168/doc.go
@@ -1,3 +1,3 @@
package issue1168
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.config.yaml spec.yaml
diff --git a/internal/test/issues/issue-1168/server.config.yaml b/internal/test/issues/issue-1168/server.config.yaml
index 7d70ed842d..ff204a7c23 100644
--- a/internal/test/issues/issue-1168/server.config.yaml
+++ b/internal/test/issues/issue-1168/server.config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: issue1168
output:
api.gen.go
diff --git a/internal/test/issues/issue-1180/config.yaml b/internal/test/issues/issue-1180/config.yaml
index 307b8e33b3..f8f01372f9 100644
--- a/internal/test/issues/issue-1180/config.yaml
+++ b/internal/test/issues/issue-1180/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: issue1180
generate:
echo-server: true
diff --git a/internal/test/issues/issue-1180/doc.go b/internal/test/issues/issue-1180/doc.go
index b195cecde1..5fcca2b965 100644
--- a/internal/test/issues/issue-1180/doc.go
+++ b/internal/test/issues/issue-1180/doc.go
@@ -1,3 +1,3 @@
package issue1180
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml issue.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml issue.yaml
diff --git a/internal/test/issues/issue-1180/issue.gen.go b/internal/test/issues/issue-1180/issue.gen.go
index a9da529dea..11fe0948f7 100644
--- a/internal/test/issues/issue-1180/issue.gen.go
+++ b/internal/test/issues/issue-1180/issue.gen.go
@@ -1,11 +1,11 @@
// Package issue1180 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package issue1180
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"fmt"
@@ -115,7 +115,7 @@ func NewGetSimplePrimitiveRequest(server string, param string) (*http.Request, e
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("simple", false, "param", runtime.ParamLocationPath, param)
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: "int32"})
if err != nil {
return nil, err
}
@@ -135,7 +135,7 @@ func NewGetSimplePrimitiveRequest(server string, param string) (*http.Request, e
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -195,6 +195,11 @@ type GetSimplePrimitiveResponse struct {
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetSimplePrimitiveResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetSimplePrimitiveResponse) Status() string {
if r.HTTPResponse != nil {
@@ -211,6 +216,14 @@ func (r GetSimplePrimitiveResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetSimplePrimitiveResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// GetSimplePrimitiveWithResponse request returning *GetSimplePrimitiveResponse
func (c *ClientWithResponses) GetSimplePrimitiveWithResponse(ctx context.Context, param string, reqEditors ...RequestEditorFn) (*GetSimplePrimitiveResponse, error) {
rsp, err := c.GetSimplePrimitive(ctx, param, reqEditors...)
@@ -254,7 +267,7 @@ func (w *ServerInterfaceWrapper) GetSimplePrimitive(ctx echo.Context) error {
// ------------- Path parameter "param" -------------
var param string
- err = runtime.BindStyledParameterWithLocation("simple", false, "param", runtime.ParamLocationPath, ctx.Param("param"), ¶m)
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: "int32"})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
}
@@ -279,49 +292,70 @@ type EchoRouter interface {
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
}
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
- router.GET(baseURL+"/simplePrimitive/:param", wrapper.GetSimplePrimitive)
+ router.GET(options.BaseURL+"/simplePrimitive/:param", wrapper.GetSimplePrimitive, options.OperationMiddlewares["getSimplePrimitive"]...)
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/7RRPY/TQBD9K9aDcuX13XXbUaErkBC5DlEs9iQZ5P1gdhJxsvzf0a4TIBHtVfbMzrz3",
- "5r0FYwo5RYpa4BYIlZxioVbsOOSZvlxatTOmqBS1/ir9Uptnz7FWZTxS8K3/mgkORYXjAeu6GkxURuGs",
- "nCIcPnSl4XZXri59/0GjbrMc96nCzDzShTT6UBE/Pb9gNVDWuZYvVLTbkZxJYHAmKRv8Qz/0Qx1MmaLP",
- "DIenfugfYJC9HtthdlPwWTiw8pnskr34sNa3A7XzUibxVfHzBIePpLvblQYnPpCSFLivC6oRjQLmKrlN",
- "wEDo54mFJjiVE5l/3NonCV7hwFGfHmHu7TMo+tru3SRj/WZuQ3ochvp5L7SHwzv7N0/7Z87eJdmcfkv5",
- "HJUOJP/VX7lLy20jPskMh6NqdtZeQlMq2k9EOfjce65bvwMAAP//QUrtxqoCAAA=",
+ "tFE9j9NAEP0r1oNy5fXdddtRoSuQELkOUSz2JBnk/WB2EnGy/N/RrhMgEe1V9szOvPfmvQVjCjlFilrg",
+ "FgiVnGKhVuw45Jm+XFq1M6aoFLX+Kv1Sm2fPsVZlPFLwrf+aCQ5FheMB67oaTFRG4aycIhw+dKXhdleu",
+ "Ln3/QaNusxz3qcLMPNKFNPpQET89v2A1UNa5li9UtNuRnElgcCYpG/xDP/RDHUyZos8Mh6d+6B9gkL0e",
+ "22F2U/BZOLDymeySvfiw1rcDtfNSJvFV8fMEh4+ku9uVBic+kJIUuK8LqhGNAuYquU3AQOjniYUmOJUT",
+ "mX/c2icJXuHAUZ8eYe7tMyj62u7dJGP9Zm5DehyG+nkvtIfDO/s3T/tnzt4l2Zx+S/kclQ4k/9VfuUvL",
+ "bSM+yQyHo2p21l5CUyraT0Q5+Nx7rlu/AwAA//8=",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -329,7 +363,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -347,12 +381,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -378,3 +412,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1182/pkg1/config.yaml b/internal/test/issues/issue-1182/pkg1/config.yaml
index 3bdf594176..a300242fbc 100644
--- a/internal/test/issues/issue-1182/pkg1/config.yaml
+++ b/internal/test/issues/issue-1182/pkg1/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
package: pkg1
generate:
echo-server: true
@@ -7,4 +8,4 @@ generate:
strict-server: true
output: pkg1.gen.go
import-mapping:
- pkg2.yaml: github.com/deepmap/oapi-codegen/internal/test/issues/issue-1182/pkg2
+ pkg2.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1182/pkg2
diff --git a/internal/test/issues/issue-1182/pkg1/doc.go b/internal/test/issues/issue-1182/pkg1/doc.go
index 9b814a99d5..8b57f0836f 100644
--- a/internal/test/issues/issue-1182/pkg1/doc.go
+++ b/internal/test/issues/issue-1182/pkg1/doc.go
@@ -1,3 +1,3 @@
package pkg1
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml ../pkg1.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../pkg1.yaml
diff --git a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go
index ecb258db49..e02ca358c2 100644
--- a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go
+++ b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go
@@ -1,11 +1,11 @@
// Package pkg1 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package pkg1
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"fmt"
@@ -15,10 +15,9 @@ import (
"path"
"strings"
- externalRef0 "github.com/deepmap/oapi-codegen/internal/test/issues/issue-1182/pkg2"
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
- strictecho "github.com/oapi-codegen/runtime/strictmiddleware/echo"
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1182/pkg2"
)
// RequestEditorFn is the function signature for the RequestEditor callback function
@@ -129,7 +128,7 @@ func NewTestGetRequest(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -189,6 +188,11 @@ type TestGetResponse struct {
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r TestGetResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r TestGetResponse) Status() string {
if r.HTTPResponse != nil {
@@ -205,6 +209,14 @@ func (r TestGetResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r TestGetResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// TestGetWithResponse request returning *TestGetResponse
func (c *ClientWithResponses) TestGetWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*TestGetResponse, error) {
rsp, err := c.TestGet(ctx, reqEditors...)
@@ -266,20 +278,39 @@ type EchoRouter interface {
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
}
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
- router.GET(baseURL+"/test", wrapper.TestGet)
+ router.GET(options.BaseURL+"/test", wrapper.TestGet, options.OperationMiddlewares["TestGet"]...)
}
@@ -304,8 +335,8 @@ type StrictServerInterface interface {
TestGet(ctx context.Context, request TestGetRequestObject) (TestGetResponseObject, error)
}
-type StrictHandlerFunc = strictecho.StrictEchoHandlerFunc
-type StrictMiddlewareFunc = strictecho.StrictEchoMiddlewareFunc
+type StrictHandlerFunc func(ctx echo.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
return &strictHandler{ssi: ssi, middlewares: middlewares}
@@ -339,31 +370,33 @@ func (sh *strictHandler) TestGet(ctx echo.Context) error {
return nil
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/2yQwU7zMBCEX8Wa/z9GSQo33zihHriUShwQB5NMGkNjW+ttEary7shpKULitB55Z3e/",
- "OaGLU4qBQTPsCcKcYshcxOYinryOGw4Uho7lo2fuxCf1McDizny7THx9Y6fmY/TdaHw2UlzC3mg0g8TJ",
- "uBB1pJjkune3I+Z5ruDDEMvYve8Y8rIhuImweFhvMVdQr/sit8xqHilHCiocKfl8wapu67Y0xsTgkofF",
- "bd3WK1RITscFplFmLY8dlxITxRWCdX+ZfE9F9TuBm7Yt5b9wgMW/5ies5trX/B1TAcuHaXLyCVuWmnLA",
- "NaozeV5YMuzzCQfZw2JUTbZpLiDFUvdkmlyqncf8Mn8FAAD//91ZsTWyAQAA",
+ "fJAxT8MwEIX/ivVgjJK0bN6YUAeWUokBIWScl8a0sS37WoSq/HfktBSxMJ3Pd+/uvneCDWMMnl4y9AmJ",
+ "OQafOSdxt12+rS8/z06GNXsmestS7ZhtclFc8NC4Vz9SFd4/aEV9Ds4OymWViiqxUxJUn8KojA8yMKlo",
+ "7M5siWmaKjjfhzJ27yx9njd4MxIaj6sNpgriZF/SDbOoJ6YjEyocmfL5gkXd1m1pDJHeRAeNu7qtF6gQ",
+ "jQwzUSPMUh5bziFEJlMIVt1l8gMF1V8blm1bwm1iD42b5tex5trX/ONVocuHcTTpC7psVuWKq19n/DwD",
+ "ZeiXEw5pD41BJOqmudAUSd2RcTSxNg7T6/QdAAD//w==",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -371,7 +404,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -386,9 +419,7 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
res[pathToFile] = rawSpec
}
- pathPrefix := path.Dir(pathToFile)
-
- for rawPath, rawFunc := range externalRef0.PathToRawSpec(path.Join(pathPrefix, "pkg2.yaml")) {
+ for rawPath, rawFunc := range externalRef0.PathToRawSpec(path.Join(path.Dir(pathToFile), "pkg2.yaml")) {
if _, ok := res[rawPath]; ok {
// it is not possible to compare functions in golang, so always overwrite the old value
}
@@ -397,12 +428,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -428,3 +459,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1182/pkg2/config.yaml b/internal/test/issues/issue-1182/pkg2/config.yaml
index e4845843ad..e61fd48440 100644
--- a/internal/test/issues/issue-1182/pkg2/config.yaml
+++ b/internal/test/issues/issue-1182/pkg2/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
package: pkg2
generate:
echo-server: true
diff --git a/internal/test/issues/issue-1182/pkg2/doc.go b/internal/test/issues/issue-1182/pkg2/doc.go
index 5acb190c66..68cb0b78a1 100644
--- a/internal/test/issues/issue-1182/pkg2/doc.go
+++ b/internal/test/issues/issue-1182/pkg2/doc.go
@@ -1,3 +1,3 @@
package pkg2
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml ../pkg2.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../pkg2.yaml
diff --git a/internal/test/issues/issue-1182/pkg2/pkg2.gen.go b/internal/test/issues/issue-1182/pkg2/pkg2.gen.go
index f64a4d283a..21ba74e586 100644
--- a/internal/test/issues/issue-1182/pkg2/pkg2.gen.go
+++ b/internal/test/issues/issue-1182/pkg2/pkg2.gen.go
@@ -1,11 +1,11 @@
// Package pkg2 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package pkg2
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"fmt"
@@ -16,7 +16,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
- strictecho "github.com/oapi-codegen/runtime/strictmiddleware/echo"
)
// RequestEditorFn is the function signature for the RequestEditor callback function
@@ -163,14 +162,33 @@ type EchoRouter interface {
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
}
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
}
@@ -181,8 +199,8 @@ type ResponseWithReferenceResponse struct {
type StrictServerInterface interface {
}
-type StrictHandlerFunc = strictecho.StrictEchoHandlerFunc
-type StrictMiddlewareFunc = strictecho.StrictEchoMiddlewareFunc
+type StrictHandlerFunc func(ctx echo.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
return &strictHandler{ssi: ssi, middlewares: middlewares}
@@ -193,30 +211,32 @@ type strictHandler struct {
middlewares []StrictMiddlewareFunc
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/zSOMU/DMBSE/4p1c+S2YvPGyMBSKjEgBuNcsCGxLb/XMkT+7yihjJ/e++5uRShLLZlZ",
- "BW5Fo9SShTuc7/CaNJ45sTEHboeRElqqmkqGw6P5t0z5+GJQ8xNTiCaJaZvVOBotZmplMT4XjWym+vDt",
- "P4ne+4CUp7LFzikwy96Q/UI4PD9d0Ado0nnDC0XNC9uNDQNubPK34GSP9rg9lsrsa4LDgz3aEwZUr1Hg",
- "8nWeB8iuCtzbimub4RBVqzsc7p5S1I5kXXy1PqG/998AAAD//4Nm84whAQAA",
+ "NI4xT8MwFIT/inVz5LZi88bIwFIqMSAG41ywIbEtv9cyRP7vKKGMn9777m5FKEstmVkFbkWj1JKFO5zv",
+ "8Jo0njmxMQduh5ESWqqaSobDo/m3TPn4YlDzE1OIJolpm9U4Gi1mamUxPheNbKb68O0/id77gJSnssXO",
+ "KTDL3pD9Qjg8P13QB2jSecMLRc0L240NA25s8rfgZI/2uD2WyuxrgsODPdoTBlSvUeDydZ4HyK4K3NuK",
+ "a5vhEFWrOxzunlLUjmRdfLU+ob/33wAAAP//",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -224,7 +244,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -242,12 +262,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -273,3 +293,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1189/config.yaml b/internal/test/issues/issue-1189/config.yaml
index 921e76c162..ddc5076566 100644
--- a/internal/test/issues/issue-1189/config.yaml
+++ b/internal/test/issues/issue-1189/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: param
generate:
echo-server: true
diff --git a/internal/test/issues/issue-1189/doc.go b/internal/test/issues/issue-1189/doc.go
index b804515610..e64506f488 100644
--- a/internal/test/issues/issue-1189/doc.go
+++ b/internal/test/issues/issue-1189/doc.go
@@ -1,3 +1,3 @@
package param
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml issue1189.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml issue1189.yaml
diff --git a/internal/test/issues/issue-1189/issue1189.gen.go b/internal/test/issues/issue-1189/issue1189.gen.go
index c48fa86d40..0296cf0d90 100644
--- a/internal/test/issues/issue-1189/issue1189.gen.go
+++ b/internal/test/issues/issue-1189/issue1189.gen.go
@@ -1,11 +1,11 @@
// Package param provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package param
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -27,18 +27,54 @@ const (
TestFieldA1Foo TestFieldA1 = "foo"
)
+// Valid indicates whether the value is a known member of the TestFieldA1 enum.
+func (e TestFieldA1) Valid() bool {
+ switch e {
+ case TestFieldA1Bar:
+ return true
+ case TestFieldA1Foo:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for TestFieldB.
const (
TestFieldBBar TestFieldB = "bar"
TestFieldBFoo TestFieldB = "foo"
)
+// Valid indicates whether the value is a known member of the TestFieldB enum.
+func (e TestFieldB) Valid() bool {
+ switch e {
+ case TestFieldBBar:
+ return true
+ case TestFieldBFoo:
+ return true
+ default:
+ return false
+ }
+}
+
// Defines values for TestFieldC1.
const (
Bar TestFieldC1 = "bar"
Foo TestFieldC1 = "foo"
)
+// Valid indicates whether the value is a known member of the TestFieldC1 enum.
+func (e TestFieldC1) Valid() bool {
+ switch e {
+ case Bar:
+ return true
+ case Foo:
+ return true
+ default:
+ return false
+ }
+}
+
// Test defines model for test.
type Test struct {
FieldA *Test_FieldA `json:"fieldA,omitempty"`
@@ -92,7 +128,7 @@ func (t *Test_FieldA) MergeTestFieldA0(v TestFieldA0) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -118,7 +154,7 @@ func (t *Test_FieldA) MergeTestFieldA1(v TestFieldA1) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -154,7 +190,7 @@ func (t *Test_FieldC) MergeTestFieldC0(v TestFieldC0) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -180,7 +216,7 @@ func (t *Test_FieldC) MergeTestFieldC1(v TestFieldC1) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -303,7 +339,7 @@ func NewTestRequest(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -364,6 +400,16 @@ type TestResponse struct {
JSON200 *Test
}
+// GetJSON200 returns JSON200
+func (r TestResponse) GetJSON200() *Test {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r TestResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r TestResponse) Status() string {
if r.HTTPResponse != nil {
@@ -380,6 +426,14 @@ func (r TestResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r TestResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// TestWithResponse request returning *TestResponse
func (c *ClientWithResponses) TestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*TestResponse, error) {
rsp, err := c.Test(ctx, reqEditors...)
@@ -451,47 +505,68 @@ type EchoRouter interface {
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
}
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
- router.GET(baseURL+"/test", wrapper.Test)
+ router.GET(options.BaseURL+"/test", wrapper.Test, options.OperationMiddlewares["Test"]...)
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/6yRsU4zMRCE32X+v7RyJ+jcARUVDV2UwlzWiZFvd2Vviuh0747sI4pEC9vMyPZ+lmYW",
- "TDKrMLFV+AV1OtMcujWq1lSLKBVL1E9jonx8ai7w9S3C7xfYVQke1UriE1a3gPgyw+8RReDwEQoO7uez",
- "w+o22nOn5fw3tJdGE6Zf0to4JI4Cz5ecHUSJgyZ4PO7G3QgHDXbuoQy3rE7UpQUWLAm/HuHx3i4dClUV",
- "rluMD+PYZBI24r4TVHOa+tbwWYXvbTT3v1CEx7/hXtfw3dX2+XqbrwAAAP//gr+fh9IBAAA=",
+ "rJGxTjMxEITfZf6/tHIn6NwBFRUNXZTCXNaJkW93ZW+K6HTvjuwjikQL28zI9n6WZhZMMqswsVX4BXU6",
+ "0xy6NarWVIsoFUvUT2OifHxqLvD1LcLvF9hVCR7VSuITVreA+DLD7xFF4PARCg7u57PD6jbac6fl/De0",
+ "l0YTpl/S2jgkjgLPl5wdRImDJng87sbdCAcNdu6hDLesTtSlBRYsCb8e4fHeLh0KVRWuW4wP49hkEjbi",
+ "vhNUc5r61vBZhe9tNPe/UITHv+Fe1/Dd1fb5epuvAAAA//8=",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -499,7 +574,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -517,12 +592,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -548,3 +623,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1208-1209/config.yaml b/internal/test/issues/issue-1208-1209/config.yaml
index 9ce73ab039..52a520aa38 100644
--- a/internal/test/issues/issue-1208-1209/config.yaml
+++ b/internal/test/issues/issue-1208-1209/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: multijson
generate:
client: true
diff --git a/internal/test/issues/issue-1208-1209/doc.go b/internal/test/issues/issue-1208-1209/doc.go
index 13c8dd5e95..7384a2ab9f 100644
--- a/internal/test/issues/issue-1208-1209/doc.go
+++ b/internal/test/issues/issue-1208-1209/doc.go
@@ -1,3 +1,3 @@
package multijson
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml issue-multi-json.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml issue-multi-json.yaml
diff --git a/internal/test/issues/issue-1208-1209/issue-multi-json.gen.go b/internal/test/issues/issue-1208-1209/issue-multi-json.gen.go
index af31dc2c3e..cbd99a6ec8 100644
--- a/internal/test/issues/issue-1208-1209/issue-multi-json.gen.go
+++ b/internal/test/issues/issue-1208-1209/issue-multi-json.gen.go
@@ -1,11 +1,11 @@
// Package multijson provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package multijson
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -18,7 +18,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/gin-gonic/gin"
- strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin"
)
// Bar defines model for bar.
@@ -145,7 +144,7 @@ func NewTestRequest(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -209,6 +208,31 @@ type TestResponse struct {
ApplicationfooJSON201 *BazApplicationFooPlusJSON
}
+// GetApplicationbarJSON200 returns ApplicationbarJSON200
+func (r TestResponse) GetApplicationbarJSON200() *Bar {
+ return r.ApplicationbarJSON200
+}
+
+// GetApplicationfooJSON200 returns ApplicationfooJSON200
+func (r TestResponse) GetApplicationfooJSON200() *Foo {
+ return r.ApplicationfooJSON200
+}
+
+// GetApplicationbarJSON201 returns ApplicationbarJSON201
+func (r TestResponse) GetApplicationbarJSON201() *BazApplicationBarPlusJSON {
+ return r.ApplicationbarJSON201
+}
+
+// GetApplicationfooJSON201 returns ApplicationfooJSON201
+func (r TestResponse) GetApplicationfooJSON201() *BazApplicationFooPlusJSON {
+ return r.ApplicationfooJSON201
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r TestResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r TestResponse) Status() string {
if r.HTTPResponse != nil {
@@ -225,6 +249,14 @@ func (r TestResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r TestResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// TestWithResponse request returning *TestResponse
func (c *ClientWithResponses) TestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*TestResponse, error) {
rsp, err := c.Test(ctx, reqEditors...)
@@ -353,19 +385,29 @@ type TestResponseObject interface {
type Test200ApplicationBarPlusJSONResponse Bar
func (response Test200ApplicationBarPlusJSONResponse) VisitTestResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/bar+json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type Test200ApplicationFooPlusJSONResponse Foo
func (response Test200ApplicationFooPlusJSONResponse) VisitTestResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/foo+json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type Test201ApplicationBarPlusJSONResponse struct {
@@ -373,10 +415,15 @@ type Test201ApplicationBarPlusJSONResponse struct {
}
func (response Test201ApplicationBarPlusJSONResponse) VisitTestResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/bar+json")
w.WriteHeader(201)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type Test201ApplicationFooPlusJSONResponse struct {
@@ -384,10 +431,15 @@ type Test201ApplicationFooPlusJSONResponse struct {
}
func (response Test201ApplicationFooPlusJSONResponse) VisitTestResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/foo+json")
w.WriteHeader(201)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
// StrictServerInterface represents all server handlers.
@@ -397,16 +449,61 @@ type StrictServerInterface interface {
Test(ctx context.Context, request TestRequestObject) (TestResponseObject, error)
}
-type StrictHandlerFunc = strictgin.StrictGinHandlerFunc
-type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc
+type StrictHandlerFunc func(ctx *gin.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictGinServerOptions struct {
+ // RequestErrorHandlerFunc is called when a request cannot be parsed or
+ // decoded. It is invoked for JSON bind failures, form parse/bind errors,
+ // multipart reader errors, media type parse errors, missing multipart
+ // boundaries, and request body read errors. The default returns 400.
+ RequestErrorHandlerFunc func(ctx *gin.Context, err error)
+ // HandlerErrorFunc is called when the application handler (or any
+ // middleware wrapping it) returns a non-nil error. The default returns 500.
+ HandlerErrorFunc func(ctx *gin.Context, err error)
+ // ResponseErrorHandlerFunc is called when the response object fails to
+ // serialize (Visit*Response returns an error) or when the handler returns
+ // an unexpected response type. The default returns 500.
+ ResponseErrorHandlerFunc func(ctx *gin.Context, err error)
+}
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
- return &strictHandler{ssi: ssi, middlewares: middlewares}
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictGinServerOptions{
+ RequestErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ },
+ HandlerErrorFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ ResponseErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictGinServerOptions) ServerInterface {
+ if options.RequestErrorHandlerFunc == nil {
+ options.RequestErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.HandlerErrorFunc == nil {
+ options.HandlerErrorFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.ResponseErrorHandlerFunc == nil {
+ options.ResponseErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
}
type strictHandler struct {
ssi StrictServerInterface
middlewares []StrictMiddlewareFunc
+ options StrictGinServerOptions
}
// Test operation middleware
@@ -423,41 +520,42 @@ func (sh *strictHandler) Test(ctx *gin.Context) {
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(TestResponseObject); ok {
if err := validResponse.VisitTestResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/8ySQU4DMQxF7/JhR9Skwy43YM8F0qnTBk1tKwkLqObuyGkFqlQW7JiNPXHeT/5Xzpjl",
- "pMLEvSGeUampcKPxs0ufVmbhTtytTapLmVMvwn6X6tNbE7b1Nh/plKx7rJQR8eB/dP1l2ozAuroblSzy",
- "R5UsgtU+dwWud61WtIpS7eViIBda9pN1/UMJEa3XwgcM2HTuE9u7hDGFsyDy+7I4iBInLYh43oRNgIOm",
- "fhwqvlMbeR1oFDth2H3ZI+LVhu426imEfxy1wxS2v23+9uHtvYyg1q8AAAD//25zbQ5XAgAA",
+ "zJJBTgMxDEXv8mFH1KTDLjdgzwXSqdMGTW0rCQuo5u7IaQWqVBbsmI09cd5P/lfOmOWkwsS9IZ5Rqalw",
+ "o/GzS59WZuFO3K1NqkuZUy/Cfpfq01sTtvU2H+mUrHuslBHx4H90/WXajMC6uhuVLPJHlSyC1T53Ba53",
+ "rVa0ilLt5WIgF1r2k3X9QwkRrdfCBwzYdO4T27uEMYWzIPL7sjiIEictiHjehE2Ag6Z+HCq+Uxt5HWgU",
+ "O2HYfdkj4tWG7jbqKYR/HLXDFLa/bf724e29jKDWrwAAAP//",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -465,7 +563,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -483,12 +581,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -514,3 +612,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1208-1209/issue-multi-json_test.go b/internal/test/issues/issue-1208-1209/issue-multi-json_test.go
index f97041e1bc..2c379909e9 100644
--- a/internal/test/issues/issue-1208-1209/issue-multi-json_test.go
+++ b/internal/test/issues/issue-1208-1209/issue-multi-json_test.go
@@ -6,7 +6,7 @@ import (
"net/http"
"testing"
- multijson "github.com/deepmap/oapi-codegen/internal/test/issues/issue-1208-1209"
+ multijson "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1208-1209"
"github.com/stretchr/testify/assert"
)
diff --git a/internal/test/issues/issue-1212/pkg1/config.yaml b/internal/test/issues/issue-1212/pkg1/config.yaml
index d88ef6ad74..040b8223b7 100644
--- a/internal/test/issues/issue-1212/pkg1/config.yaml
+++ b/internal/test/issues/issue-1212/pkg1/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
package: pkg1
generate:
client: true
@@ -7,4 +8,4 @@ generate:
strict-server: true
output: pkg1.gen.go
import-mapping:
- pkg2.yaml: github.com/deepmap/oapi-codegen/internal/test/issues/issue-1212/pkg2
+ pkg2.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1212/pkg2
diff --git a/internal/test/issues/issue-1212/pkg1/doc.go b/internal/test/issues/issue-1212/pkg1/doc.go
index 9b814a99d5..8b57f0836f 100644
--- a/internal/test/issues/issue-1212/pkg1/doc.go
+++ b/internal/test/issues/issue-1212/pkg1/doc.go
@@ -1,3 +1,3 @@
package pkg1
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml ../pkg1.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../pkg1.yaml
diff --git a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go
index 4f5f74371b..23d6c7db96 100644
--- a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go
+++ b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go
@@ -1,25 +1,25 @@
// Package pkg1 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package pkg1
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"fmt"
"io"
+ "mime"
"mime/multipart"
"net/http"
"net/url"
"path"
"strings"
- externalRef0 "github.com/deepmap/oapi-codegen/internal/test/issues/issue-1212/pkg2"
"github.com/getkin/kin-openapi/openapi3"
"github.com/gin-gonic/gin"
- strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin"
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1212/pkg2"
)
// RequestEditorFn is the function signature for the RequestEditor callback function
@@ -130,7 +130,7 @@ func NewTestRequest(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -190,6 +190,11 @@ type TestResponse struct {
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r TestResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r TestResponse) Status() string {
if r.HTTPResponse != nil {
@@ -206,6 +211,14 @@ func (r TestResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r TestResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// TestWithResponse request returning *TestResponse
func (c *ClientWithResponses) TestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*TestResponse, error) {
rsp, err := c.Test(ctx, reqEditors...)
@@ -301,7 +314,8 @@ type Test200MultipartResponse externalRef0.TestMultipartResponse
func (response Test200MultipartResponse) VisitTestResponse(w http.ResponseWriter) error {
writer := multipart.NewWriter(w)
- w.Header().Set("Content-Type", writer.FormDataContentType())
+
+ w.Header().Set("Content-Type", mime.FormatMediaType("multipart/related", map[string]string{"boundary": writer.Boundary()}))
w.WriteHeader(200)
defer writer.Close()
@@ -315,16 +329,61 @@ type StrictServerInterface interface {
Test(ctx context.Context, request TestRequestObject) (TestResponseObject, error)
}
-type StrictHandlerFunc = strictgin.StrictGinHandlerFunc
-type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc
+type StrictHandlerFunc func(ctx *gin.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictGinServerOptions struct {
+ // RequestErrorHandlerFunc is called when a request cannot be parsed or
+ // decoded. It is invoked for JSON bind failures, form parse/bind errors,
+ // multipart reader errors, media type parse errors, missing multipart
+ // boundaries, and request body read errors. The default returns 400.
+ RequestErrorHandlerFunc func(ctx *gin.Context, err error)
+ // HandlerErrorFunc is called when the application handler (or any
+ // middleware wrapping it) returns a non-nil error. The default returns 500.
+ HandlerErrorFunc func(ctx *gin.Context, err error)
+ // ResponseErrorHandlerFunc is called when the response object fails to
+ // serialize (Visit*Response returns an error) or when the handler returns
+ // an unexpected response type. The default returns 500.
+ ResponseErrorHandlerFunc func(ctx *gin.Context, err error)
+}
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
- return &strictHandler{ssi: ssi, middlewares: middlewares}
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictGinServerOptions{
+ RequestErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ },
+ HandlerErrorFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ ResponseErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictGinServerOptions) ServerInterface {
+ if options.RequestErrorHandlerFunc == nil {
+ options.RequestErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.HandlerErrorFunc == nil {
+ options.HandlerErrorFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.ResponseErrorHandlerFunc == nil {
+ options.ResponseErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
}
type strictHandler struct {
ssi StrictServerInterface
middlewares []StrictMiddlewareFunc
+ options StrictGinServerOptions
}
// Test operation middleware
@@ -341,41 +400,42 @@ func (sh *strictHandler) Test(ctx *gin.Context) {
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(TestResponseObject); ok {
if err := validResponse.VisitTestResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/4SQv24DIQyH3+XXjihc042xQ6XufQFyZxIqzkbgDFWUd6+A/lGkq3KLfeDPH/YFs6xZ",
- "mFgr3AWFahau1H+UqrY4CytxT9dz0ph9UVsoeaWlHdb5RKtvWS6SqWgc/EcVfvGlpY+FAhwe7J/ODqza",
- "gy+4ml79KnKvOojgOj7zbe6ywxDdviBESsu+z/KZCQ5VS+QjOhyGbIN42iQaEzkIHJ9TMpBM7HOEw/Nu",
- "2k0wyF5PvYv9Wd2RemgGr1H4bYHDe7s0t7veT9N/k//Wja5j9q8AAAD//2k9V1a5AQAA",
+ "jJExT8MwEIX/y4MxqkPYPDIgsbMjN7mkBufOsq8DqvrfkW1oVKlIzZI72997p3cnjLJGYWLNsCckylE4",
+ "U23i1zJ8KGUtzSisxLVcj0F9dElNouCUpnKYxwOtrmJJIiX1TeQzC7+4VMrHRDMsHszmaRqWTfXau4Rz",
+ "V5FXkbuQWQTn9nW/M2yz75vv9UCzpzANpdLvSLDImjwvqAoXzdvY002sgJ5ngeVjCB0kErvoYfG863c9",
+ "OkSnh6pi/uJcqP6Kg1Mv/DbB4r1cdtdLGPr+vyAu78y2qRbFTwAAAP//",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -383,7 +443,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -398,9 +458,7 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
res[pathToFile] = rawSpec
}
- pathPrefix := path.Dir(pathToFile)
-
- for rawPath, rawFunc := range externalRef0.PathToRawSpec(path.Join(pathPrefix, "pkg2.yaml")) {
+ for rawPath, rawFunc := range externalRef0.PathToRawSpec(path.Join(path.Dir(pathToFile), "pkg2.yaml")) {
if _, ok := res[rawPath]; ok {
// it is not possible to compare functions in golang, so always overwrite the old value
}
@@ -409,12 +467,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -440,3 +498,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1212/pkg2/config.yaml b/internal/test/issues/issue-1212/pkg2/config.yaml
index 9ea6f2ce66..d3a63e5d40 100644
--- a/internal/test/issues/issue-1212/pkg2/config.yaml
+++ b/internal/test/issues/issue-1212/pkg2/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
package: pkg2
generate:
client: true
diff --git a/internal/test/issues/issue-1212/pkg2/doc.go b/internal/test/issues/issue-1212/pkg2/doc.go
index 5acb190c66..68cb0b78a1 100644
--- a/internal/test/issues/issue-1212/pkg2/doc.go
+++ b/internal/test/issues/issue-1212/pkg2/doc.go
@@ -1,3 +1,3 @@
package pkg2
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml ../pkg2.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../pkg2.yaml
diff --git a/internal/test/issues/issue-1212/pkg2/pkg2.gen.go b/internal/test/issues/issue-1212/pkg2/pkg2.gen.go
index ecd8309efd..778ed9cbfd 100644
--- a/internal/test/issues/issue-1212/pkg2/pkg2.gen.go
+++ b/internal/test/issues/issue-1212/pkg2/pkg2.gen.go
@@ -1,11 +1,11 @@
// Package pkg2 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package pkg2
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"fmt"
@@ -17,7 +17,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/gin-gonic/gin"
- strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin"
)
// Bar defines model for bar.
@@ -186,42 +185,88 @@ type TestMultipartResponse func(writer *multipart.Writer) error
type StrictServerInterface interface {
}
-type StrictHandlerFunc = strictgin.StrictGinHandlerFunc
-type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc
+type StrictHandlerFunc func(ctx *gin.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictGinServerOptions struct {
+ // RequestErrorHandlerFunc is called when a request cannot be parsed or
+ // decoded. It is invoked for JSON bind failures, form parse/bind errors,
+ // multipart reader errors, media type parse errors, missing multipart
+ // boundaries, and request body read errors. The default returns 400.
+ RequestErrorHandlerFunc func(ctx *gin.Context, err error)
+ // HandlerErrorFunc is called when the application handler (or any
+ // middleware wrapping it) returns a non-nil error. The default returns 500.
+ HandlerErrorFunc func(ctx *gin.Context, err error)
+ // ResponseErrorHandlerFunc is called when the response object fails to
+ // serialize (Visit*Response returns an error) or when the handler returns
+ // an unexpected response type. The default returns 500.
+ ResponseErrorHandlerFunc func(ctx *gin.Context, err error)
+}
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
- return &strictHandler{ssi: ssi, middlewares: middlewares}
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictGinServerOptions{
+ RequestErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ },
+ HandlerErrorFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ ResponseErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictGinServerOptions) ServerInterface {
+ if options.RequestErrorHandlerFunc == nil {
+ options.RequestErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.HandlerErrorFunc == nil {
+ options.HandlerErrorFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.ResponseErrorHandlerFunc == nil {
+ options.ResponseErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
}
type strictHandler struct {
ssi StrictServerInterface
middlewares []StrictMiddlewareFunc
+ options StrictGinServerOptions
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/4SPwU4EIQyG36V6JIurN44efA92trgYpm3a7sFM5t0NYGJMJlku/MD/5aMbLLwKE5Ib",
- "pA0UTZgMx8HRvO8LkyONuN6bV8nqUbFlx2u/tOWGa+5JlAXV6+S/jOk9a4/PigUSPMU/XZyYxUtW2MNo",
- "fzA/ahdm2OcKv+Yhu0zR/x+Uiu36Omb5FoQE5lrpEwZcpuyAOB8SnalUGBLdWwvAgpSlQoK308vpDAEk",
- "+83m8/4TAAD//08ZxXtaAQAA",
+ "hI/BTgQhDIbfpXoki6s3jh58D3a2uBimbdruwUzm3Q1gYkwmWS78wP/loxssvAoTkhukDRRNmAzHwdG8",
+ "7wuTI4243ptXyepRsWXHa7+05YZr7kmUBdXr5L+M6T1rj8+KBRI8xT9dnJjFS1bYw2h/MD9qF2bY5wq/",
+ "5iG7TNH/H5SK7fo6ZvkWhATmWukTBlym7IA4HxKdqVQYEt1bC8CClKVCgrfTy+kMAST7zebz/hMAAP//",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -229,7 +274,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -247,12 +292,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -278,3 +323,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1219/config.yaml b/internal/test/issues/issue-1219/config.yaml
index 0260889cdb..91e041af5f 100644
--- a/internal/test/issues/issue-1219/config.yaml
+++ b/internal/test/issues/issue-1219/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: issue1219
generate:
models: true
diff --git a/internal/test/issues/issue-1219/doc.go b/internal/test/issues/issue-1219/doc.go
index bc616c105b..7e1118e5c9 100644
--- a/internal/test/issues/issue-1219/doc.go
+++ b/internal/test/issues/issue-1219/doc.go
@@ -1,3 +1,3 @@
package issue1219
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml issue.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml issue.yaml
diff --git a/internal/test/issues/issue-1219/issue.gen.go b/internal/test/issues/issue-1219/issue.gen.go
index dd4d3dcf19..2beeedc59c 100644
--- a/internal/test/issues/issue-1219/issue.gen.go
+++ b/internal/test/issues/issue-1219/issue.gen.go
@@ -1,6 +1,6 @@
// Package issue1219 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package issue1219
import (
@@ -8,14 +8,14 @@ import (
"fmt"
)
-// DefaultAddtional1 defines model for DefaultAddtional1.
-type DefaultAddtional1 struct {
+// DefaultAdditional1 defines model for DefaultAdditional1.
+type DefaultAdditional1 struct {
Field1 *int `json:"field1,omitempty"`
Field2 *string `json:"field2,omitempty"`
}
-// DefaultAddtional2 defines model for DefaultAddtional2.
-type DefaultAddtional2 struct {
+// DefaultAdditional2 defines model for DefaultAdditional2.
+type DefaultAdditional2 struct {
FieldA *int `json:"fieldA,omitempty"`
FieldB *string `json:"fieldB,omitempty"`
}
@@ -147,42 +147,42 @@ type MergeWithoutWithout struct {
FieldB *string `json:"fieldB,omitempty"`
}
-// WithAnyAddtional1 defines model for WithAnyAddtional1.
-type WithAnyAddtional1 struct {
+// WithAnyAdditional1 defines model for WithAnyAdditional1.
+type WithAnyAdditional1 struct {
Field1 *int `json:"field1,omitempty"`
Field2 *string `json:"field2,omitempty"`
AdditionalProperties map[string]interface{} `json:"-"`
}
-// WithAnyAddtional2 defines model for WithAnyAddtional2.
-type WithAnyAddtional2 struct {
+// WithAnyAdditional2 defines model for WithAnyAdditional2.
+type WithAnyAdditional2 struct {
FieldA *int `json:"fieldA,omitempty"`
FieldB *string `json:"fieldB,omitempty"`
AdditionalProperties map[string]interface{} `json:"-"`
}
-// WithStringAddtional1 defines model for WithStringAddtional1.
-type WithStringAddtional1 struct {
+// WithStringAdditional1 defines model for WithStringAdditional1.
+type WithStringAdditional1 struct {
Field1 *int `json:"field1,omitempty"`
Field2 *string `json:"field2,omitempty"`
AdditionalProperties map[string]string `json:"-"`
}
-// WithStringAddtional2 defines model for WithStringAddtional2.
-type WithStringAddtional2 struct {
+// WithStringAdditional2 defines model for WithStringAdditional2.
+type WithStringAdditional2 struct {
FieldA *int `json:"fieldA,omitempty"`
FieldB *string `json:"fieldB,omitempty"`
AdditionalProperties map[string]string `json:"-"`
}
-// WithoutAddtional1 defines model for WithoutAddtional1.
-type WithoutAddtional1 struct {
+// WithoutAdditional1 defines model for WithoutAdditional1.
+type WithoutAdditional1 struct {
Field1 *int `json:"field1,omitempty"`
Field2 *string `json:"field2,omitempty"`
}
-// WithoutAddtional2 defines model for WithoutAddtional2.
-type WithoutAddtional2 struct {
+// WithoutAdditional2 defines model for WithoutAdditional2.
+type WithoutAdditional2 struct {
FieldA *int `json:"fieldA,omitempty"`
FieldB *string `json:"fieldB,omitempty"`
}
@@ -978,25 +978,25 @@ func (a MergeWithStringWithAny) MarshalJSON() ([]byte, error) {
return json.Marshal(object)
}
-// Getter for additional properties for WithAnyAddtional1. Returns the specified
+// Getter for additional properties for WithAnyAdditional1. Returns the specified
// element and whether it was found
-func (a WithAnyAddtional1) Get(fieldName string) (value interface{}, found bool) {
+func (a WithAnyAdditional1) Get(fieldName string) (value interface{}, found bool) {
if a.AdditionalProperties != nil {
value, found = a.AdditionalProperties[fieldName]
}
return
}
-// Setter for additional properties for WithAnyAddtional1
-func (a *WithAnyAddtional1) Set(fieldName string, value interface{}) {
+// Setter for additional properties for WithAnyAdditional1
+func (a *WithAnyAdditional1) Set(fieldName string, value interface{}) {
if a.AdditionalProperties == nil {
a.AdditionalProperties = make(map[string]interface{})
}
a.AdditionalProperties[fieldName] = value
}
-// Override default JSON handling for WithAnyAddtional1 to handle AdditionalProperties
-func (a *WithAnyAddtional1) UnmarshalJSON(b []byte) error {
+// Override default JSON handling for WithAnyAdditional1 to handle AdditionalProperties
+func (a *WithAnyAdditional1) UnmarshalJSON(b []byte) error {
object := make(map[string]json.RawMessage)
err := json.Unmarshal(b, &object)
if err != nil {
@@ -1033,8 +1033,8 @@ func (a *WithAnyAddtional1) UnmarshalJSON(b []byte) error {
return nil
}
-// Override default JSON handling for WithAnyAddtional1 to handle AdditionalProperties
-func (a WithAnyAddtional1) MarshalJSON() ([]byte, error) {
+// Override default JSON handling for WithAnyAdditional1 to handle AdditionalProperties
+func (a WithAnyAdditional1) MarshalJSON() ([]byte, error) {
var err error
object := make(map[string]json.RawMessage)
@@ -1061,25 +1061,25 @@ func (a WithAnyAddtional1) MarshalJSON() ([]byte, error) {
return json.Marshal(object)
}
-// Getter for additional properties for WithAnyAddtional2. Returns the specified
+// Getter for additional properties for WithAnyAdditional2. Returns the specified
// element and whether it was found
-func (a WithAnyAddtional2) Get(fieldName string) (value interface{}, found bool) {
+func (a WithAnyAdditional2) Get(fieldName string) (value interface{}, found bool) {
if a.AdditionalProperties != nil {
value, found = a.AdditionalProperties[fieldName]
}
return
}
-// Setter for additional properties for WithAnyAddtional2
-func (a *WithAnyAddtional2) Set(fieldName string, value interface{}) {
+// Setter for additional properties for WithAnyAdditional2
+func (a *WithAnyAdditional2) Set(fieldName string, value interface{}) {
if a.AdditionalProperties == nil {
a.AdditionalProperties = make(map[string]interface{})
}
a.AdditionalProperties[fieldName] = value
}
-// Override default JSON handling for WithAnyAddtional2 to handle AdditionalProperties
-func (a *WithAnyAddtional2) UnmarshalJSON(b []byte) error {
+// Override default JSON handling for WithAnyAdditional2 to handle AdditionalProperties
+func (a *WithAnyAdditional2) UnmarshalJSON(b []byte) error {
object := make(map[string]json.RawMessage)
err := json.Unmarshal(b, &object)
if err != nil {
@@ -1116,8 +1116,8 @@ func (a *WithAnyAddtional2) UnmarshalJSON(b []byte) error {
return nil
}
-// Override default JSON handling for WithAnyAddtional2 to handle AdditionalProperties
-func (a WithAnyAddtional2) MarshalJSON() ([]byte, error) {
+// Override default JSON handling for WithAnyAdditional2 to handle AdditionalProperties
+func (a WithAnyAdditional2) MarshalJSON() ([]byte, error) {
var err error
object := make(map[string]json.RawMessage)
@@ -1144,25 +1144,25 @@ func (a WithAnyAddtional2) MarshalJSON() ([]byte, error) {
return json.Marshal(object)
}
-// Getter for additional properties for WithStringAddtional1. Returns the specified
+// Getter for additional properties for WithStringAdditional1. Returns the specified
// element and whether it was found
-func (a WithStringAddtional1) Get(fieldName string) (value string, found bool) {
+func (a WithStringAdditional1) Get(fieldName string) (value string, found bool) {
if a.AdditionalProperties != nil {
value, found = a.AdditionalProperties[fieldName]
}
return
}
-// Setter for additional properties for WithStringAddtional1
-func (a *WithStringAddtional1) Set(fieldName string, value string) {
+// Setter for additional properties for WithStringAdditional1
+func (a *WithStringAdditional1) Set(fieldName string, value string) {
if a.AdditionalProperties == nil {
a.AdditionalProperties = make(map[string]string)
}
a.AdditionalProperties[fieldName] = value
}
-// Override default JSON handling for WithStringAddtional1 to handle AdditionalProperties
-func (a *WithStringAddtional1) UnmarshalJSON(b []byte) error {
+// Override default JSON handling for WithStringAdditional1 to handle AdditionalProperties
+func (a *WithStringAdditional1) UnmarshalJSON(b []byte) error {
object := make(map[string]json.RawMessage)
err := json.Unmarshal(b, &object)
if err != nil {
@@ -1199,8 +1199,8 @@ func (a *WithStringAddtional1) UnmarshalJSON(b []byte) error {
return nil
}
-// Override default JSON handling for WithStringAddtional1 to handle AdditionalProperties
-func (a WithStringAddtional1) MarshalJSON() ([]byte, error) {
+// Override default JSON handling for WithStringAdditional1 to handle AdditionalProperties
+func (a WithStringAdditional1) MarshalJSON() ([]byte, error) {
var err error
object := make(map[string]json.RawMessage)
@@ -1227,25 +1227,25 @@ func (a WithStringAddtional1) MarshalJSON() ([]byte, error) {
return json.Marshal(object)
}
-// Getter for additional properties for WithStringAddtional2. Returns the specified
+// Getter for additional properties for WithStringAdditional2. Returns the specified
// element and whether it was found
-func (a WithStringAddtional2) Get(fieldName string) (value string, found bool) {
+func (a WithStringAdditional2) Get(fieldName string) (value string, found bool) {
if a.AdditionalProperties != nil {
value, found = a.AdditionalProperties[fieldName]
}
return
}
-// Setter for additional properties for WithStringAddtional2
-func (a *WithStringAddtional2) Set(fieldName string, value string) {
+// Setter for additional properties for WithStringAdditional2
+func (a *WithStringAdditional2) Set(fieldName string, value string) {
if a.AdditionalProperties == nil {
a.AdditionalProperties = make(map[string]string)
}
a.AdditionalProperties[fieldName] = value
}
-// Override default JSON handling for WithStringAddtional2 to handle AdditionalProperties
-func (a *WithStringAddtional2) UnmarshalJSON(b []byte) error {
+// Override default JSON handling for WithStringAdditional2 to handle AdditionalProperties
+func (a *WithStringAdditional2) UnmarshalJSON(b []byte) error {
object := make(map[string]json.RawMessage)
err := json.Unmarshal(b, &object)
if err != nil {
@@ -1282,8 +1282,8 @@ func (a *WithStringAddtional2) UnmarshalJSON(b []byte) error {
return nil
}
-// Override default JSON handling for WithStringAddtional2 to handle AdditionalProperties
-func (a WithStringAddtional2) MarshalJSON() ([]byte, error) {
+// Override default JSON handling for WithStringAdditional2 to handle AdditionalProperties
+func (a WithStringAdditional2) MarshalJSON() ([]byte, error) {
var err error
object := make(map[string]json.RawMessage)
diff --git a/internal/test/issues/issue-1219/issue.yaml b/internal/test/issues/issue-1219/issue.yaml
index 6ded9d9275..0437423277 100644
--- a/internal/test/issues/issue-1219/issue.yaml
+++ b/internal/test/issues/issue-1219/issue.yaml
@@ -1,7 +1,7 @@
openapi: "3.0.1"
components:
schemas:
- WithAnyAddtional1:
+ WithAnyAdditional1:
type: object
properties:
field1:
@@ -9,7 +9,7 @@ components:
field2:
type: string
additionalProperties: true
- WithAnyAddtional2:
+ WithAnyAdditional2:
type: object
properties:
fieldA:
@@ -17,7 +17,7 @@ components:
fieldB:
type: string
additionalProperties: true
- WithStringAddtional1:
+ WithStringAdditional1:
type: object
properties:
field1:
@@ -26,7 +26,7 @@ components:
type: string
additionalProperties:
type: string
- WithStringAddtional2:
+ WithStringAdditional2:
type: object
properties:
fieldA:
@@ -35,7 +35,7 @@ components:
type: string
additionalProperties:
type: string
- WithoutAddtional1:
+ WithoutAdditional1:
type: object
properties:
field1:
@@ -43,7 +43,7 @@ components:
field2:
type: string
additionalProperties: false
- WithoutAddtional2:
+ WithoutAdditional2:
type: object
properties:
fieldA:
@@ -51,14 +51,14 @@ components:
fieldB:
type: string
additionalProperties: false
- DefaultAddtional1:
+ DefaultAdditional1:
type: object
properties:
field1:
type: integer
field2:
type: string
- DefaultAddtional2:
+ DefaultAdditional2:
type: object
properties:
fieldA:
@@ -68,70 +68,69 @@ components:
MergeWithoutWithout:
allOf:
- - $ref: '#/components/schemas/WithoutAddtional1'
- - $ref: '#/components/schemas/WithoutAddtional2'
+ - $ref: '#/components/schemas/WithoutAdditional1'
+ - $ref: '#/components/schemas/WithoutAdditional2'
MergeWithoutWithString:
allOf:
- - $ref: '#/components/schemas/WithoutAddtional1'
- - $ref: '#/components/schemas/WithStringAddtional2'
+ - $ref: '#/components/schemas/WithoutAdditional1'
+ - $ref: '#/components/schemas/WithStringAdditional2'
MergeWithoutWithAny:
allOf:
- - $ref: '#/components/schemas/WithoutAddtional1'
- - $ref: '#/components/schemas/WithAnyAddtional2'
+ - $ref: '#/components/schemas/WithoutAdditional1'
+ - $ref: '#/components/schemas/WithAnyAdditional2'
MergeWithoutDefault:
allOf:
- - $ref: '#/components/schemas/WithoutAddtional1'
- - $ref: '#/components/schemas/DefaultAddtional2'
+ - $ref: '#/components/schemas/WithoutAdditional1'
+ - $ref: '#/components/schemas/DefaultAdditional2'
MergeWithStringWithout:
allOf:
- - $ref: '#/components/schemas/WithStringAddtional1'
- - $ref: '#/components/schemas/WithoutAddtional2'
+ - $ref: '#/components/schemas/WithStringAdditional1'
+ - $ref: '#/components/schemas/WithoutAdditional2'
# Cannot merge this
# MergeWithStringWithString:
# allOf:
- # - $ref: '#/components/schemas/WithStringAddtional1'
- # - $ref: '#/components/schemas/WithStringAddtional2'
+ # - $ref: '#/components/schemas/WithStringAdditional1'
+ # - $ref: '#/components/schemas/WithStringAdditional2'
MergeWithStringWithAny:
allOf:
- - $ref: '#/components/schemas/WithStringAddtional1'
- - $ref: '#/components/schemas/WithAnyAddtional2'
+ - $ref: '#/components/schemas/WithStringAdditional1'
+ - $ref: '#/components/schemas/WithAnyAdditional2'
MergeWithStringDefault:
allOf:
- - $ref: '#/components/schemas/WithStringAddtional1'
- - $ref: '#/components/schemas/DefaultAddtional2'
+ - $ref: '#/components/schemas/WithStringAdditional1'
+ - $ref: '#/components/schemas/DefaultAdditional2'
MergeWithAnyWithout:
allOf:
- - $ref: '#/components/schemas/WithAnyAddtional1'
- - $ref: '#/components/schemas/WithoutAddtional2'
+ - $ref: '#/components/schemas/WithAnyAdditional1'
+ - $ref: '#/components/schemas/WithoutAdditional2'
MergeWithAnyWithString:
allOf:
- - $ref: '#/components/schemas/WithAnyAddtional1'
- - $ref: '#/components/schemas/WithStringAddtional2'
+ - $ref: '#/components/schemas/WithAnyAdditional1'
+ - $ref: '#/components/schemas/WithStringAdditional2'
MergeWithAnyWithAny:
allOf:
- - $ref: '#/components/schemas/WithAnyAddtional1'
- - $ref: '#/components/schemas/WithAnyAddtional2'
+ - $ref: '#/components/schemas/WithAnyAdditional1'
+ - $ref: '#/components/schemas/WithAnyAdditional2'
MergeWithAnyDefault:
allOf:
- - $ref: '#/components/schemas/WithAnyAddtional1'
- - $ref: '#/components/schemas/DefaultAddtional2'
+ - $ref: '#/components/schemas/WithAnyAdditional1'
+ - $ref: '#/components/schemas/DefaultAdditional2'
MergeDefaultWithout:
allOf:
- - $ref: '#/components/schemas/DefaultAddtional1'
- - $ref: '#/components/schemas/WithoutAddtional2'
+ - $ref: '#/components/schemas/DefaultAdditional1'
+ - $ref: '#/components/schemas/WithoutAdditional2'
MergeDefaultWithString:
allOf:
- - $ref: '#/components/schemas/DefaultAddtional1'
- - $ref: '#/components/schemas/WithStringAddtional2'
+ - $ref: '#/components/schemas/DefaultAdditional1'
+ - $ref: '#/components/schemas/WithStringAdditional2'
MergeDefaultWithAny:
allOf:
- - $ref: '#/components/schemas/DefaultAddtional1'
- - $ref: '#/components/schemas/WithAnyAddtional2'
+ - $ref: '#/components/schemas/DefaultAdditional1'
+ - $ref: '#/components/schemas/WithAnyAdditional2'
MergeDefaultDefault:
allOf:
- - $ref: '#/components/schemas/DefaultAddtional1'
- - $ref: '#/components/schemas/DefaultAddtional2'
-
+ - $ref: '#/components/schemas/DefaultAdditional1'
+ - $ref: '#/components/schemas/DefaultAdditional2'
diff --git a/internal/test/issues/issue-1219/issue_test.go b/internal/test/issues/issue-1219/issue_test.go
index 0c5472d6a2..aebd0d1afd 100644
--- a/internal/test/issues/issue-1219/issue_test.go
+++ b/internal/test/issues/issue-1219/issue_test.go
@@ -4,7 +4,7 @@ import (
"reflect"
"testing"
- issue1219 "github.com/deepmap/oapi-codegen/internal/test/issues/issue-1219"
+ issue1219 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1219"
"github.com/stretchr/testify/assert"
)
diff --git a/internal/test/issues/issue-1277/config.yaml b/internal/test/issues/issue-1277/config.yaml
new file mode 100644
index 0000000000..f4c4a686a2
--- /dev/null
+++ b/internal/test/issues/issue-1277/config.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue1277
+generate:
+ models: true
+ client: true
+ chi-server: true
+ strict-server: true
+output: content-array.gen.go
diff --git a/internal/test/issues/issue-1277/content-array.gen.go b/internal/test/issues/issue-1277/content-array.gen.go
new file mode 100644
index 0000000000..e2e7846119
--- /dev/null
+++ b/internal/test/issues/issue-1277/content-array.gen.go
@@ -0,0 +1,585 @@
+// Package issue1277 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1277
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/go-chi/chi/v5"
+)
+
+// Test200JSONResponseBody_Item defines parameters for Test.
+type Test200JSONResponseBody_Item struct {
+ Field1 *string `json:"field1,omitempty"`
+ Field2 *string `json:"field2,omitempty"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// Getter for additional properties for Test200JSONResponseBody_Item. Returns the specified
+// element and whether it was found
+func (a Test200JSONResponseBody_Item) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Test200JSONResponseBody_Item
+func (a *Test200JSONResponseBody_Item) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Test200JSONResponseBody_Item to handle AdditionalProperties
+func (a *Test200JSONResponseBody_Item) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["field1"]; found {
+ err = json.Unmarshal(raw, &a.Field1)
+ if err != nil {
+ return fmt.Errorf("error reading 'field1': %w", err)
+ }
+ delete(object, "field1")
+ }
+
+ if raw, found := object["field2"]; found {
+ err = json.Unmarshal(raw, &a.Field2)
+ if err != nil {
+ return fmt.Errorf("error reading 'field2': %w", err)
+ }
+ delete(object, "field2")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Test200JSONResponseBody_Item to handle AdditionalProperties
+func (a Test200JSONResponseBody_Item) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Field1 != nil {
+ object["field1"], err = json.Marshal(a.Field1)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'field1': %w", err)
+ }
+ }
+
+ if a.Field2 != nil {
+ object["field2"], err = json.Marshal(a.Field2)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'field2': %w", err)
+ }
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // Test request
+ Test(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) Test(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewTestRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewTestRequest generates requests for Test
+func NewTestRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/test")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // TestWithResponse request
+ TestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*TestResponse, error)
+}
+
+type TestResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *[]Test200JSONResponseBody_Item
+}
+
+// GetJSON200 returns JSON200
+func (r TestResponse) GetJSON200() *[]Test200JSONResponseBody_Item {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r TestResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r TestResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r TestResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r TestResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// TestWithResponse request returning *TestResponse
+func (c *ClientWithResponses) TestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*TestResponse, error) {
+ rsp, err := c.Test(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseTestResponse(rsp)
+}
+
+// ParseTestResponse parses an HTTP response from a TestWithResponse call
+func ParseTestResponse(rsp *http.Response) (*TestResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &TestResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest []Test200JSONResponseBody_Item
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /test)
+ Test(w http.ResponseWriter, r *http.Request)
+}
+
+// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
+
+type Unimplemented struct{}
+
+// (GET /test)
+func (_ Unimplemented) Test(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// Test operation middleware
+func (siw *ServerInterfaceWrapper) Test(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.Test(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{})
+}
+
+type ChiServerOptions struct {
+ BaseURL string
+ BaseRouter chi.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = chi.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/test", wrapper.Test)
+ })
+
+ return r
+}
+
+type TestRequestObject struct {
+}
+
+type TestResponseObject interface {
+ VisitTestResponse(w http.ResponseWriter) error
+}
+
+type Test200JSONResponse []Test200JSONResponseBody_Item
+
+func (response Test200JSONResponse) VisitTestResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /test)
+ Test(ctx context.Context, request TestRequestObject) (TestResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// Test operation middleware
+func (sh *strictHandler) Test(w http.ResponseWriter, r *http.Request) {
+ var request TestRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.Test(ctx, request.(TestRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "Test")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(TestResponseObject); ok {
+ if err := validResponse.VisitTestResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/internal/test/issues/issue-1277/generate.go b/internal/test/issues/issue-1277/generate.go
new file mode 100644
index 0000000000..7158b4df22
--- /dev/null
+++ b/internal/test/issues/issue-1277/generate.go
@@ -0,0 +1,3 @@
+package issue1277
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-1277/spec.yaml b/internal/test/issues/issue-1277/spec.yaml
new file mode 100644
index 0000000000..bd03fd2b97
--- /dev/null
+++ b/internal/test/issues/issue-1277/spec.yaml
@@ -0,0 +1,23 @@
+openapi: "3.0.1"
+info:
+ title: a
+ version: 1.0.0
+paths:
+ /test:
+ get:
+ operationId: test
+ responses:
+ "200":
+ description: desc
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties:
+ field1:
+ type: string
+ field2:
+ type: string
+ additionalProperties: true
diff --git a/internal/test/issues/issue-1298/config.yaml b/internal/test/issues/issue-1298/config.yaml
new file mode 100644
index 0000000000..76ef6715e7
--- /dev/null
+++ b/internal/test/issues/issue-1298/config.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue1298
+generate:
+ models: true
+ client: true
+ gin-server: true
+ strict-server: true
+output: issue1298.gen.go
diff --git a/internal/test/issues/issue-1298/doc.go b/internal/test/issues/issue-1298/doc.go
new file mode 100644
index 0000000000..b5e5ee95c9
--- /dev/null
+++ b/internal/test/issues/issue-1298/doc.go
@@ -0,0 +1,3 @@
+package issue1298
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml issue1298.yaml
diff --git a/internal/test/issues/issue-1298/issue1298.gen.go b/internal/test/issues/issue-1298/issue1298.gen.go
new file mode 100644
index 0000000000..a3229d9c86
--- /dev/null
+++ b/internal/test/issues/issue-1298/issue1298.gen.go
@@ -0,0 +1,459 @@
+// Package issue1298 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1298
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/gin-gonic/gin"
+)
+
+// Test defines model for Test.
+type Test struct {
+ Field1 string `json:"field1"`
+ Field2 string `json:"field2"`
+}
+
+// TestApplicationTestPlusJSONRequestBody defines body for Test for application/test+json ContentType.
+type TestApplicationTestPlusJSONRequestBody = Test
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // TestWithBody request with any body
+ TestWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ TestWithApplicationTestPlusJSONBody(ctx context.Context, body TestApplicationTestPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) TestWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewTestRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) TestWithApplicationTestPlusJSONBody(ctx context.Context, body TestApplicationTestPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewTestRequestWithApplicationTestPlusJSONBody(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewTestRequestWithApplicationTestPlusJSONBody calls the generic Test builder with application/test+json body
+func NewTestRequestWithApplicationTestPlusJSONBody(server string, body TestApplicationTestPlusJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewTestRequestWithBody(server, "application/test+json", bodyReader)
+}
+
+// NewTestRequestWithBody generates requests for Test with any type of body
+func NewTestRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/test")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // TestWithBodyWithResponse request with any body
+ TestWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*TestResponse, error)
+
+ TestWithApplicationTestPlusJSONBodyWithResponse(ctx context.Context, body TestApplicationTestPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*TestResponse, error)
+}
+
+type TestResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r TestResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r TestResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r TestResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r TestResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// TestWithBodyWithResponse request with arbitrary body returning *TestResponse
+func (c *ClientWithResponses) TestWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*TestResponse, error) {
+ rsp, err := c.TestWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseTestResponse(rsp)
+}
+
+func (c *ClientWithResponses) TestWithApplicationTestPlusJSONBodyWithResponse(ctx context.Context, body TestApplicationTestPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*TestResponse, error) {
+ rsp, err := c.TestWithApplicationTestPlusJSONBody(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseTestResponse(rsp)
+}
+
+// ParseTestResponse parses an HTTP response from a TestWithResponse call
+func ParseTestResponse(rsp *http.Response) (*TestResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &TestResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /test)
+ Test(c *gin.Context)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandler func(*gin.Context, error, int)
+}
+
+type MiddlewareFunc func(c *gin.Context)
+
+// Test operation middleware
+func (siw *ServerInterfaceWrapper) Test(c *gin.Context) {
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.Test(c)
+}
+
+// GinServerOptions provides options for the Gin server.
+type GinServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ ErrorHandler func(*gin.Context, error, int)
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router gin.IRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, GinServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) {
+ errorHandler := options.ErrorHandler
+ if errorHandler == nil {
+ errorHandler = func(c *gin.Context, err error, statusCode int) {
+ c.JSON(statusCode, gin.H{"msg": err.Error()})
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandler: errorHandler,
+ }
+
+ router.GET(options.BaseURL+"/test", wrapper.Test)
+}
+
+type TestRequestObject struct {
+ Body *TestApplicationTestPlusJSONRequestBody
+}
+
+type TestResponseObject interface {
+ VisitTestResponse(w http.ResponseWriter) error
+}
+
+type Test204Response struct {
+}
+
+func (response Test204Response) VisitTestResponse(w http.ResponseWriter) error {
+ w.WriteHeader(204)
+ return nil
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /test)
+ Test(ctx context.Context, request TestRequestObject) (TestResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx *gin.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictGinServerOptions struct {
+ // RequestErrorHandlerFunc is called when a request cannot be parsed or
+ // decoded. It is invoked for JSON bind failures, form parse/bind errors,
+ // multipart reader errors, media type parse errors, missing multipart
+ // boundaries, and request body read errors. The default returns 400.
+ RequestErrorHandlerFunc func(ctx *gin.Context, err error)
+ // HandlerErrorFunc is called when the application handler (or any
+ // middleware wrapping it) returns a non-nil error. The default returns 500.
+ HandlerErrorFunc func(ctx *gin.Context, err error)
+ // ResponseErrorHandlerFunc is called when the response object fails to
+ // serialize (Visit*Response returns an error) or when the handler returns
+ // an unexpected response type. The default returns 500.
+ ResponseErrorHandlerFunc func(ctx *gin.Context, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictGinServerOptions{
+ RequestErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ },
+ HandlerErrorFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ ResponseErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictGinServerOptions) ServerInterface {
+ if options.RequestErrorHandlerFunc == nil {
+ options.RequestErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.HandlerErrorFunc == nil {
+ options.HandlerErrorFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.ResponseErrorHandlerFunc == nil {
+ options.ResponseErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictGinServerOptions
+}
+
+// Test operation middleware
+func (sh *strictHandler) Test(ctx *gin.Context) {
+ var request TestRequestObject
+
+ var body TestApplicationTestPlusJSONRequestBody
+ if err := ctx.ShouldBindJSON(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
+ }
+ } else {
+ request.Body = &body
+ }
+
+ handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.Test(ctx, request.(TestRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "Test")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ sh.options.HandlerErrorFunc(ctx, err)
+ } else if validResponse, ok := response.(TestResponseObject); ok {
+ if err := validResponse.VisitTestResponse(ctx.Writer); err != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/internal/test/issues/issue-1298/issue1298.yaml b/internal/test/issues/issue-1298/issue1298.yaml
new file mode 100644
index 0000000000..889d0c2b17
--- /dev/null
+++ b/internal/test/issues/issue-1298/issue1298.yaml
@@ -0,0 +1,25 @@
+openapi: "3.0.1"
+components:
+ schemas:
+ Test:
+ type: object
+ properties:
+ field1:
+ type: string
+ field2:
+ type: string
+ required:
+ - field1
+ - field2
+paths:
+ /test:
+ get:
+ operationId: test
+ requestBody:
+ content:
+ application/test+json:
+ schema:
+ $ref: "#/components/schemas/Test"
+ responses:
+ 204:
+ description: good
diff --git a/internal/test/issues/issue-1298/issue1298_test.go b/internal/test/issues/issue-1298/issue1298_test.go
new file mode 100644
index 0000000000..0d627f10f5
--- /dev/null
+++ b/internal/test/issues/issue-1298/issue1298_test.go
@@ -0,0 +1,44 @@
+package issue1298_test
+
+import (
+ "context"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/gin-gonic/gin"
+ issue1298 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1298"
+ "github.com/stretchr/testify/assert"
+)
+
+type testStrictServerInterface struct {
+ t *testing.T
+}
+
+// (GET /test)
+func (s *testStrictServerInterface) Test(ctx context.Context, request issue1298.TestRequestObject) (issue1298.TestResponseObject, error) {
+ assert.Equal(s.t, "test1", request.Body.Field1)
+ assert.Equal(s.t, "test2", request.Body.Field2)
+ return issue1298.Test204Response{}, nil
+}
+
+func TestIssue1298(t *testing.T) {
+ g := gin.Default()
+ issue1298.RegisterHandlersWithOptions(g,
+ issue1298.NewStrictHandler(&testStrictServerInterface{t: t}, nil),
+ issue1298.GinServerOptions{})
+ ts := httptest.NewServer(g)
+ defer ts.Close()
+
+ c, err := issue1298.NewClientWithResponses(ts.URL)
+ assert.NoError(t, err)
+ res, err := c.TestWithApplicationTestPlusJSONBodyWithResponse(
+ context.TODO(),
+ issue1298.Test{
+ Field1: "test1",
+ Field2: "test2",
+ },
+ )
+ assert.NoError(t, err)
+ assert.Equal(t, http.StatusNoContent, res.StatusCode())
+}
diff --git a/internal/test/issues/issue-1373/config.yaml b/internal/test/issues/issue-1373/config.yaml
new file mode 100644
index 0000000000..2c5fe25659
--- /dev/null
+++ b/internal/test/issues/issue-1373/config.yaml
@@ -0,0 +1,4 @@
+package: issue1373
+generate:
+ models: true
+output: issue.gen.go
diff --git a/internal/test/issues/issue-1373/generate.go b/internal/test/issues/issue-1373/generate.go
new file mode 100644
index 0000000000..fd0d2c74b7
--- /dev/null
+++ b/internal/test/issues/issue-1373/generate.go
@@ -0,0 +1,3 @@
+package issue1373
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-1373/issue.gen.go b/internal/test/issues/issue-1373/issue.gen.go
new file mode 100644
index 0000000000..0cd4cd8d85
--- /dev/null
+++ b/internal/test/issues/issue-1373/issue.gen.go
@@ -0,0 +1,15 @@
+// Package issue1373 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1373
+
+// NonRecursiveObject defines model for NonRecursiveObject.
+type NonRecursiveObject struct {
+ FieldInNonRecursive *string `json:"FieldInNonRecursive,omitempty"`
+}
+
+// RecursiveObject defines model for RecursiveObject.
+type RecursiveObject struct {
+ FieldInNonRecursive *string `json:"FieldInNonRecursive,omitempty"`
+ FieldInRecursive *string `json:"FieldInRecursive:,omitempty"`
+}
diff --git a/internal/test/issues/issue-1373/spec.yaml b/internal/test/issues/issue-1373/spec.yaml
new file mode 100644
index 0000000000..66bab84707
--- /dev/null
+++ b/internal/test/issues/issue-1373/spec.yaml
@@ -0,0 +1,32 @@
+openapi: 3.0.2
+info:
+ version: '0.0.1'
+ title: example
+ description: |
+ Make sure that recursive $ref in allOf are handled properly
+paths:
+ /example:
+ get:
+ operationId: exampleGet
+ responses:
+ '200':
+ description: "OK"
+ content:
+ 'application/json':
+ schema:
+ $ref: '#/components/schemas/RecursiveObject'
+
+components:
+ schemas:
+ RecursiveObject:
+ allOf:
+ - $ref: "#/components/schemas/NonRecursiveObject"
+ - $ref: "#/components/schemas/RecursiveObject"
+ - properties:
+ FieldInRecursive::
+ type: string
+
+ NonRecursiveObject:
+ properties:
+ FieldInNonRecursive:
+ type: string
diff --git a/internal/test/issues/issue-1378/bionicle.yaml b/internal/test/issues/issue-1378/bionicle.yaml
new file mode 100644
index 0000000000..0013d121a5
--- /dev/null
+++ b/internal/test/issues/issue-1378/bionicle.yaml
@@ -0,0 +1,43 @@
+openapi: 3.0.1
+
+info:
+ title: Test
+ description: Test
+ version: 1.0.0
+
+paths:
+ /bionicle/{name}:
+ get:
+ parameters:
+ - $ref: "#/components/parameters/bionicleName"
+ responses:
+ '200':
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Bionicle'
+ '400':
+ content:
+ application/json:
+ schema:
+ oneOf:
+ - $ref: '#/components/schemas/Bionicle'
+
+components:
+ parameters:
+ bionicleName:
+ name: name
+ in: path
+ description: Name of the character
+ required: true
+ schema:
+ type: string
+
+ schemas:
+ Bionicle:
+ type: object
+ properties:
+ name:
+ type: string
+ required:
+ - name
diff --git a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go
new file mode 100644
index 0000000000..f1f561ce10
--- /dev/null
+++ b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go
@@ -0,0 +1,439 @@
+// Package bionicle provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package bionicle
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gorilla/mux"
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1378/common"
+ "github.com/oapi-codegen/runtime"
+)
+
+// Bionicle defines model for Bionicle.
+type Bionicle struct {
+ Name string `json:"name"`
+}
+
+// BionicleName defines model for bionicleName.
+type BionicleName = string
+
+// GetBionicleName400JSONResponseBody defines parameters for GetBionicleName.
+type GetBionicleName400JSONResponseBody struct {
+ union json.RawMessage
+}
+
+// AsBionicle returns the union data inside the GetBionicleName400JSONResponseBody as a Bionicle
+func (t GetBionicleName400JSONResponseBody) AsBionicle() (Bionicle, error) {
+ var body Bionicle
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromBionicle overwrites any union data inside the GetBionicleName400JSONResponseBody as the provided Bionicle
+func (t *GetBionicleName400JSONResponseBody) FromBionicle(v Bionicle) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeBionicle performs a merge with any union data inside the GetBionicleName400JSONResponseBody, using the provided Bionicle
+func (t *GetBionicleName400JSONResponseBody) MergeBionicle(v Bionicle) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t GetBionicleName400JSONResponseBody) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *GetBionicleName400JSONResponseBody) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /bionicle/{name})
+ GetBionicleName(w http.ResponseWriter, r *http.Request, name BionicleName)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetBionicleName operation middleware
+func (siw *ServerInterfaceWrapper) GetBionicleName(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "name" -------------
+ var name BionicleName
+
+ err = runtime.BindStyledParameterWithOptions("simple", "name", mux.Vars(r)["name"], &name, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "name", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetBionicleName(w, r, name)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+ BaseURL string
+ BaseRouter *mux.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = mux.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.HandleFunc(options.BaseURL+"/bionicle/{name}", wrapper.GetBionicleName).Methods(http.MethodGet)
+
+ return r
+}
+
+type GetBionicleNameRequestObject struct {
+ Name BionicleName `json:"name"`
+}
+
+type GetBionicleNameResponseObject interface {
+ VisitGetBionicleNameResponse(w http.ResponseWriter) error
+}
+
+type GetBionicleName200JSONResponse Bionicle
+
+func (response GetBionicleName200JSONResponse) VisitGetBionicleNameResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type GetBionicleName400JSONResponse = GetBionicleName400JSONResponseBody
+
+func (response GetBionicleName400JSONResponse) VisitGetBionicleNameResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.union); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /bionicle/{name})
+ GetBionicleName(ctx context.Context, request GetBionicleNameRequestObject) (GetBionicleNameResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// GetBionicleName operation middleware
+func (sh *strictHandler) GetBionicleName(w http.ResponseWriter, r *http.Request, name BionicleName) {
+ var request GetBionicleNameRequestObject
+
+ request.Name = name
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetBionicleName(ctx, request.(GetBionicleNameRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetBionicleName")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetBionicleNameResponseObject); ok {
+ if err := validResponse.VisitGetBionicleNameResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "lJExTzMxDIb/SuXvG6PLFZhu7IJYYGGrOqSpr5eqlwTHRUKn/HfkXI9eKQxksRw7efz6HcCGPgaPnhM0",
+ "A0RDpkdGKtnWBe/sEZ9Nj5LvMFlykV3w0IDcLkK74A4XtjNkLCOBAifFaLgDBb68HIMCwreTI9xBw3RC",
+ "Bcl22Bv5mT+i9CUm5/eQc56KZY7VeY4yIYWIxA5LxZ8n+/5+zlqPXRs1dYXtAS2PFOfbcCvtFRODAnYs",
+ "0Cl9R0pjfVnVVQ1ZQYjoTXTQwH1VV0tQRXgZTU/b04Pws9ztkSWIAiOopx008Ii8mi9aXbmwHuA/YQsN",
+ "/NMXr/SlRV+5lDciPcXg07ihu7qWYINn9IVuYjw6W/j6kETPMHPiJ9jZCv3lQy67e/jj18HjS/urolvI",
+ "Jk/nMwAA//8=",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ for rawPath, rawFunc := range externalRef0.PathToRawSpec(path.Join(path.Dir(pathToFile), "common.yaml")) {
+ if _, ok := res[rawPath]; ok {
+ // it is not possible to compare functions in golang, so always overwrite the old value
+ }
+ res[rawPath] = rawFunc
+ }
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1378/bionicle/config.yaml b/internal/test/issues/issue-1378/bionicle/config.yaml
new file mode 100644
index 0000000000..4f81605dc4
--- /dev/null
+++ b/internal/test/issues/issue-1378/bionicle/config.yaml
@@ -0,0 +1,10 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
+package: bionicle
+generate:
+ gorilla-server: true
+ embedded-spec: true
+ strict-server: true
+ models: true
+import-mapping:
+ common.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1378/common
+output: bionicle.gen.go
diff --git a/internal/test/issues/issue-1378/bionicle/generate.go b/internal/test/issues/issue-1378/bionicle/generate.go
new file mode 100644
index 0000000000..26b3661696
--- /dev/null
+++ b/internal/test/issues/issue-1378/bionicle/generate.go
@@ -0,0 +1,3 @@
+package bionicle
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../bionicle.yaml
diff --git a/internal/test/issues/issue-1378/common.yaml b/internal/test/issues/issue-1378/common.yaml
new file mode 100644
index 0000000000..8aac6cdf4c
--- /dev/null
+++ b/internal/test/issues/issue-1378/common.yaml
@@ -0,0 +1,16 @@
+openapi: 3.0.1
+
+info:
+ title: Test
+ description: Test
+ version: 1.0.0
+
+components:
+ schemas:
+ ErrTracingIdNotSent:
+ type: object
+ properties:
+ code:
+ type: string
+ required:
+ - code
diff --git a/internal/test/issues/issue-1378/common/common.gen.go b/internal/test/issues/issue-1378/common/common.gen.go
new file mode 100644
index 0000000000..91da73aeb9
--- /dev/null
+++ b/internal/test/issues/issue-1378/common/common.gen.go
@@ -0,0 +1,282 @@
+// Package common provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package common
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gorilla/mux"
+)
+
+// ErrTracingIdNotSent defines model for ErrTracingIdNotSent.
+type ErrTracingIdNotSent struct {
+ Code string `json:"code"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+ BaseURL string
+ BaseRouter *mux.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = mux.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ return r
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "RMw/TwMxDAXw7/Lm6HQVW3YGFha6IYaQmNboahvHRUJVvjtKT4jJf95P74aqF1MhiY58Q69nupT7+uh+",
+ "9FJZTk/tWeOFJObbXI08mO6oaqM548cIGT2c5YQxEpy+ruzUkF939Zb+lL5/Ug2MyVg+dBY06tXZglWQ",
+ "caQeSAiOjf7Pb/K+54dlXVaMBDWSYoyMh2VdDkiwEueOLNdtG78BAAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1378/common/config.yaml b/internal/test/issues/issue-1378/common/config.yaml
new file mode 100644
index 0000000000..2d2960cdcf
--- /dev/null
+++ b/internal/test/issues/issue-1378/common/config.yaml
@@ -0,0 +1,10 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
+package: common
+generate:
+ gorilla-server: true
+ embedded-spec: true
+ strict-server: true
+ models: true
+output-options:
+ skip-prune: true
+output: common.gen.go
diff --git a/internal/test/issues/issue-1378/common/generate.go b/internal/test/issues/issue-1378/common/generate.go
new file mode 100644
index 0000000000..dbb23b05d1
--- /dev/null
+++ b/internal/test/issues/issue-1378/common/generate.go
@@ -0,0 +1,3 @@
+package common
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../common.yaml
diff --git a/internal/test/issues/issue-1378/foo-service.yaml b/internal/test/issues/issue-1378/foo-service.yaml
new file mode 100644
index 0000000000..ebd8447440
--- /dev/null
+++ b/internal/test/issues/issue-1378/foo-service.yaml
@@ -0,0 +1,10 @@
+openapi: 3.0.1
+
+info:
+ title: Test
+ description: Test
+ version: 1.0.0
+
+paths:
+ /bionicle/{name}:
+ $ref: "bionicle.yaml#/paths/~1bionicle~1{name}"
diff --git a/internal/test/issues/issue-1378/fooservice/config.yaml b/internal/test/issues/issue-1378/fooservice/config.yaml
new file mode 100644
index 0000000000..4690bd037e
--- /dev/null
+++ b/internal/test/issues/issue-1378/fooservice/config.yaml
@@ -0,0 +1,11 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
+package: fooservice
+generate:
+ gorilla-server: true
+ embedded-spec: true
+ strict-server: true
+ models: true
+import-mapping:
+ common.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1378/common
+ bionicle.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1378/bionicle
+output: fooservice.gen.go
diff --git a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go
new file mode 100644
index 0000000000..8b38f2010a
--- /dev/null
+++ b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go
@@ -0,0 +1,405 @@
+// Package fooservice provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package fooservice
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gorilla/mux"
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1378/bionicle"
+ externalRef1 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1378/common"
+ "github.com/oapi-codegen/runtime"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /bionicle/{name})
+ GetBionicleName(w http.ResponseWriter, r *http.Request, name externalRef0.BionicleName)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetBionicleName operation middleware
+func (siw *ServerInterfaceWrapper) GetBionicleName(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "name" -------------
+ var name externalRef0.BionicleName
+
+ err = runtime.BindStyledParameterWithOptions("simple", "name", mux.Vars(r)["name"], &name, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "name", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetBionicleName(w, r, name)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+ BaseURL string
+ BaseRouter *mux.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = mux.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.HandleFunc(options.BaseURL+"/bionicle/{name}", wrapper.GetBionicleName).Methods(http.MethodGet)
+
+ return r
+}
+
+type GetBionicleNameRequestObject struct {
+ Name externalRef0.BionicleName `json:"name"`
+}
+
+type GetBionicleNameResponseObject interface {
+ VisitGetBionicleNameResponse(w http.ResponseWriter) error
+}
+
+type GetBionicleName200JSONResponse externalRef0.Bionicle
+
+func (response GetBionicleName200JSONResponse) VisitGetBionicleNameResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type GetBionicleName400JSONResponse externalRef0.GetBionicleName400JSONResponseBody
+
+func (t GetBionicleName400JSONResponse) MarshalJSON() ([]byte, error) {
+ return externalRef0.GetBionicleName400JSONResponseBody(t).MarshalJSON()
+}
+
+func (t *GetBionicleName400JSONResponse) UnmarshalJSON(b []byte) error {
+ return (*externalRef0.GetBionicleName400JSONResponseBody)(t).UnmarshalJSON(b)
+}
+
+func (response GetBionicleName400JSONResponse) VisitGetBionicleNameResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /bionicle/{name})
+ GetBionicleName(ctx context.Context, request GetBionicleNameRequestObject) (GetBionicleNameResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// GetBionicleName operation middleware
+func (sh *strictHandler) GetBionicleName(w http.ResponseWriter, r *http.Request, name externalRef0.BionicleName) {
+ var request GetBionicleNameRequestObject
+
+ request.Name = name
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetBionicleName(ctx, request.(GetBionicleNameRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetBionicleName")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetBionicleNameResponseObject); ok {
+ if err := validResponse.VisitGetBionicleNameResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "lFFBT/MwDP0rk7/vGDUdcOpxF8QFLtymCWWZu2Zak+B4SKjKf0dOV21jA4lenMSvfs/vDWBDH4NHzwma",
+ "AaIh0yMjldvaBe/sHt+mw7PpURobTJZcZBc8NCCvs9DOuMOZ7QwZy0igwEkzGu5AgS9/jkUB4fvBEW6g",
+ "YTqggmQ77I1M5s8ouMTk/BZyzlPzUtDieCiaKUQkdlgg/ijx+6Bz0uWIWqkJFdY7tDzSOd+G6x1fMTEo",
+ "YMdCOl0/kNLYn1d1VUNWECJ6Ex00cF/V1RxUcaBI05N8PQh/lrctshTZwAjV0wYaeERenDuuLnJZDvCf",
+ "sIUG/ulTevoE0bdzyyvxIMXg02jVXV1LscEz+iLDxLh3tgjRuySLDWfZ3GI9hqOvk8nFzYc/cgSPL+2P",
+ "O/7CtsrT9xUAAP//",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ for rawPath, rawFunc := range externalRef0.PathToRawSpec(path.Join(path.Dir(pathToFile), "bionicle.yaml")) {
+ if _, ok := res[rawPath]; ok {
+ // it is not possible to compare functions in golang, so always overwrite the old value
+ }
+ res[rawPath] = rawFunc
+ }
+ for rawPath, rawFunc := range externalRef1.PathToRawSpec(path.Join(path.Dir(pathToFile), "common.yaml")) {
+ if _, ok := res[rawPath]; ok {
+ // it is not possible to compare functions in golang, so always overwrite the old value
+ }
+ res[rawPath] = rawFunc
+ }
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1378/fooservice/fooservice_test.go b/internal/test/issues/issue-1378/fooservice/fooservice_test.go
new file mode 100644
index 0000000000..0d3319ea6b
--- /dev/null
+++ b/internal/test/issues/issue-1378/fooservice/fooservice_test.go
@@ -0,0 +1,27 @@
+package fooservice
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+
+ bionicle "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1378/bionicle"
+)
+
+// TestExternalRefUnionResponseSerialization locks in the fix for the
+// case where a strict-server response envelope wraps an external union
+// type. Because the strict envelope is a defined type (`type X
+// externalRef0.Y`), methods on Y don't transfer; without an explicit
+// MarshalJSON delegator the encode falls back to struct-field
+// serialization on the unexported `union` field and produces `{}`.
+func TestExternalRefUnionResponseSerialization(t *testing.T) {
+ var body bionicle.GetBionicleName400JSONResponseBody
+ require.NoError(t, body.FromBionicle(bionicle.Bionicle{Name: "tahu"}))
+
+ resp := GetBionicleName400JSONResponse(body)
+
+ got, err := json.Marshal(resp)
+ require.NoError(t, err)
+ require.JSONEq(t, `{"name":"tahu"}`, string(got))
+}
diff --git a/internal/test/issues/issue-1378/fooservice/generate.go b/internal/test/issues/issue-1378/fooservice/generate.go
new file mode 100644
index 0000000000..2419719dbf
--- /dev/null
+++ b/internal/test/issues/issue-1378/fooservice/generate.go
@@ -0,0 +1,3 @@
+package fooservice
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../foo-service.yaml
diff --git a/internal/test/issues/issue-1397/config.yaml b/internal/test/issues/issue-1397/config.yaml
new file mode 100644
index 0000000000..d4a1284eeb
--- /dev/null
+++ b/internal/test/issues/issue-1397/config.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue1397
+generate:
+ echo-server: true
+ client: true
+ models: true
+ embedded-spec: true
+output: issue1397.gen.go
diff --git a/internal/test/issues/issue-1397/doc.go b/internal/test/issues/issue-1397/doc.go
new file mode 100644
index 0000000000..e5964fe298
--- /dev/null
+++ b/internal/test/issues/issue-1397/doc.go
@@ -0,0 +1,3 @@
+package issue1397
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-1397/issue1397.gen.go b/internal/test/issues/issue-1397/issue1397.gen.go
new file mode 100644
index 0000000000..4ff816ae40
--- /dev/null
+++ b/internal/test/issues/issue-1397/issue1397.gen.go
@@ -0,0 +1,504 @@
+// Package issue1397 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1397
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/labstack/echo/v4"
+)
+
+// Defines values for TestField1.
+const (
+ Option1 TestField1 = "option1"
+ Option2 TestField1 = "option2"
+)
+
+// Valid indicates whether the value is a known member of the TestField1 enum.
+func (e TestField1) Valid() bool {
+ switch e {
+ case Option1:
+ return true
+ case Option2:
+ return true
+ default:
+ return false
+ }
+}
+
+// Test defines model for Test.
+type Test = MyTestRequest
+
+// TestField1 defines model for Test.Field1.
+type TestField1 string
+
+// MyTestRequestNestedField A nested object with allocated name
+type MyTestRequestNestedField struct {
+ Field1 bool `json:"field1"`
+ Field2 string `json:"field2"`
+}
+
+// MyTestRequest defines model for .
+type MyTestRequest struct {
+ // Field1 A array of enum values
+ Field1 *[]TestField1 `json:"field1,omitempty"`
+
+ // Field2 A nested object with allocated name
+ Field2 *MyTestRequestNestedField `json:"field2,omitempty"`
+
+ // Field3 A nested object without allocated name
+ Field3 *struct {
+ Field1 bool `json:"field1"`
+ Field2 string `json:"field2"`
+ } `json:"field3,omitempty"`
+}
+
+// TestApplicationTestPlusJSONRequestBody defines body for Test for application/test+json ContentType.
+type TestApplicationTestPlusJSONRequestBody = Test
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // TestWithBody request with any body
+ TestWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ TestWithApplicationTestPlusJSONBody(ctx context.Context, body TestApplicationTestPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) TestWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewTestRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) TestWithApplicationTestPlusJSONBody(ctx context.Context, body TestApplicationTestPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewTestRequestWithApplicationTestPlusJSONBody(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewTestRequestWithApplicationTestPlusJSONBody calls the generic Test builder with application/test+json body
+func NewTestRequestWithApplicationTestPlusJSONBody(server string, body TestApplicationTestPlusJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewTestRequestWithBody(server, "application/test+json", bodyReader)
+}
+
+// NewTestRequestWithBody generates requests for Test with any type of body
+func NewTestRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/test")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // TestWithBodyWithResponse request with any body
+ TestWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*TestResponse, error)
+
+ TestWithApplicationTestPlusJSONBodyWithResponse(ctx context.Context, body TestApplicationTestPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*TestResponse, error)
+}
+
+type TestResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r TestResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r TestResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r TestResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r TestResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// TestWithBodyWithResponse request with arbitrary body returning *TestResponse
+func (c *ClientWithResponses) TestWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*TestResponse, error) {
+ rsp, err := c.TestWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseTestResponse(rsp)
+}
+
+func (c *ClientWithResponses) TestWithApplicationTestPlusJSONBodyWithResponse(ctx context.Context, body TestApplicationTestPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*TestResponse, error) {
+ rsp, err := c.TestWithApplicationTestPlusJSONBody(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseTestResponse(rsp)
+}
+
+// ParseTestResponse parses an HTTP response from a TestWithResponse call
+func ParseTestResponse(rsp *http.Response) (*TestResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &TestResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /test)
+ Test(ctx echo.Context) error
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+// Test converts echo context to params.
+func (w *ServerInterfaceWrapper) Test(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.Test(ctx)
+ return err
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+}
+
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
+}
+
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.GET(options.BaseURL+"/test", wrapper.Test, options.OperationMiddlewares["test"]...)
+
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "zFM7b9swEP4rwrVbZcuPduHWDgU8tEPgLchASyeZBsWjyVNiwdB/D45SbOQFJFsmHY738XvoeIaSWk8O",
+ "HUdQZ4jlHludyi1Glq8P5DGwwdStDdpqKVWFsQzGsyEHCn5nOgTdZ1Rn6Lo2u9e2wwg5GMY2IaUN6hYo",
+ "QZaQT9UK7nLg3iMoiByMa2DIodWnzYj8dTlNDHKYRKzeEuEwMlYZ7Q5YcvZgeJ9pa6nU0nW6RcjfNTSx",
+ "7Igsavec54W+IYeAx84ErMTSdMcFcDU0CoEcTrOGZtKcJRUK/vUS8A0eO4z8P8n+K+gL7/pj/qjjL2FR",
+ "AJ8zDYNgjKsJlOuslYVAp70BBev5Yi5sXvM+eSh4WscG00f8aYllU4Ead3UUjJH/UNXLTEmO0aVx7b01",
+ "ZQKkm34coiT6tPBSfQ9Yg4JvxfVFFNNzKLaT3BRK9OTimOxq8fP1X2qIqjQ8DI8BAAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1397/spec.yaml b/internal/test/issues/issue-1397/spec.yaml
new file mode 100644
index 0000000000..93cc609edf
--- /dev/null
+++ b/internal/test/issues/issue-1397/spec.yaml
@@ -0,0 +1,52 @@
+openapi: "3.0.1"
+components:
+ schemas:
+ Test:
+ type: object
+ properties:
+ field1:
+ description: A array of enum values
+ items:
+ enum:
+ - option1
+ - option2
+ type: string
+ maxItems: 5
+ minItems: 0
+ type: array
+ field2:
+ description: A nested object with allocated name
+ properties:
+ field1:
+ type: boolean
+ field2:
+ type: string
+ required:
+ - field1
+ - field2
+ type: object
+ x-go-type-name: MyTestRequestNestedField
+ field3:
+ description: A nested object without allocated name
+ properties:
+ field1:
+ type: boolean
+ field2:
+ type: string
+ required:
+ - field1
+ - field2
+ type: object
+ x-go-type-name: MyTestRequest
+paths:
+ /test:
+ get:
+ operationId: test
+ requestBody:
+ content:
+ application/test+json:
+ schema:
+ $ref: "#/components/schemas/Test"
+ responses:
+ 204:
+ description: good
diff --git a/internal/test/issues/issue-1529/strict-echo/config.yaml b/internal/test/issues/issue-1529/strict-echo/config.yaml
new file mode 100644
index 0000000000..56abc0bee7
--- /dev/null
+++ b/internal/test/issues/issue-1529/strict-echo/config.yaml
@@ -0,0 +1,9 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
+package: issue1529
+generate:
+ client: true
+ models: true
+ embedded-spec: true
+ echo-server: true
+ strict-server: true
+output: issue1529.gen.go
diff --git a/internal/test/issues/issue-1529/strict-echo/doc.go b/internal/test/issues/issue-1529/strict-echo/doc.go
new file mode 100644
index 0000000000..4bf78249fa
--- /dev/null
+++ b/internal/test/issues/issue-1529/strict-echo/doc.go
@@ -0,0 +1,3 @@
+package issue1529
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go
new file mode 100644
index 0000000000..349d34a553
--- /dev/null
+++ b/internal/test/issues/issue-1529/strict-echo/issue1529.gen.go
@@ -0,0 +1,553 @@
+// Package issue1529 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1529
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/labstack/echo/v4"
+)
+
+// Test defines model for Test.
+type Test = map[string]interface{}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // Test request
+ Test(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) Test(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewTestRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewTestRequest generates requests for Test
+func NewTestRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/test")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // TestWithResponse request
+ TestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*TestResponse, error)
+}
+
+type TestResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Test
+ ApplicationjsonProfileBar200 *Test
+ ApplicationjsonProfileFoo200 *Test
+}
+
+// GetJSON200 returns JSON200
+func (r TestResponse) GetJSON200() *Test {
+ return r.JSON200
+}
+
+// GetApplicationjsonProfileBar200 returns ApplicationjsonProfileBar200
+func (r TestResponse) GetApplicationjsonProfileBar200() *Test {
+ return r.ApplicationjsonProfileBar200
+}
+
+// GetApplicationjsonProfileFoo200 returns ApplicationjsonProfileFoo200
+func (r TestResponse) GetApplicationjsonProfileFoo200() *Test {
+ return r.ApplicationjsonProfileFoo200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r TestResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r TestResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r TestResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r TestResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// TestWithResponse request returning *TestResponse
+func (c *ClientWithResponses) TestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*TestResponse, error) {
+ rsp, err := c.Test(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseTestResponse(rsp)
+}
+
+// ParseTestResponse parses an HTTP response from a TestWithResponse call
+func ParseTestResponse(rsp *http.Response) (*TestResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &TestResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 200:
+ var dest Test
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ case rsp.Header.Get("Content-Type") == "application/json; profile=\"Bar\"" && rsp.StatusCode == 200:
+ var dest Test
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.ApplicationjsonProfileBar200 = &dest
+
+ case rsp.Header.Get("Content-Type") == "application/json; profile=\"Foo\"" && rsp.StatusCode == 200:
+ var dest Test
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.ApplicationjsonProfileFoo200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /test)
+ Test(ctx echo.Context) error
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+// Test converts echo context to params.
+func (w *ServerInterfaceWrapper) Test(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.Test(ctx)
+ return err
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+}
+
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
+}
+
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.GET(options.BaseURL+"/test", wrapper.Test, options.OperationMiddlewares["test"]...)
+
+}
+
+type TestRequestObject struct {
+}
+
+type TestResponseObject interface {
+ VisitTestResponse(w http.ResponseWriter) error
+}
+
+type Test200JSONResponse Test
+
+func (response Test200JSONResponse) VisitTestResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type Test200ApplicationJSONProfileBarResponse Test
+
+func (response Test200ApplicationJSONProfileBarResponse) VisitTestResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json; profile=\"Bar\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type Test200ApplicationJSONProfileFooResponse Test
+
+func (response Test200ApplicationJSONProfileFooResponse) VisitTestResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json; profile=\"Foo\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /test)
+ Test(ctx context.Context, request TestRequestObject) (TestResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx echo.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+}
+
+// Test operation middleware
+func (sh *strictHandler) Test(ctx echo.Context) error {
+ var request TestRequestObject
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.Test(ctx.Request().Context(), request.(TestRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "Test")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(TestResponseObject); ok {
+ return validResponse.VisitTestResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "rM8xSwQxEAXgvyJPy3BZtYvYWAj2ltfEOOvlyM0MyVjIsv9dEhcWLMVp3jTvY2ZBkosKE1tDWNDSiS5x",
+ "rK/UrKd9KSFA3s6UDOu6OmSeBYE/S3EQJY6aEXB/mA63cNBopyF424gPGiFKNVoWfnlH+PEdKjUVbjQa",
+ "d9PUIwkb8ehE1ZLTaPlzE96P7NtNpRkB137/wm8v+OH3a38TD1daZc6FHo94ivWIfzafRf5gbvMdAAD/",
+ "/w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1529/strict-echo/spec.yaml b/internal/test/issues/issue-1529/strict-echo/spec.yaml
new file mode 100644
index 0000000000..ca7aae80a3
--- /dev/null
+++ b/internal/test/issues/issue-1529/strict-echo/spec.yaml
@@ -0,0 +1,21 @@
+openapi: "3.0.1"
+components:
+ schemas:
+ Test:
+ type: object
+paths:
+ /test:
+ get:
+ operationId: test
+ responses:
+ 200:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Test"
+ application/json; profile="Foo":
+ schema:
+ $ref: "#/components/schemas/Test"
+ application/json; profile="Bar":
+ schema:
+ $ref: "#/components/schemas/Test"
diff --git a/internal/test/issues/issue-1529/strict-fiber/config.yaml b/internal/test/issues/issue-1529/strict-fiber/config.yaml
new file mode 100644
index 0000000000..e03a3f678b
--- /dev/null
+++ b/internal/test/issues/issue-1529/strict-fiber/config.yaml
@@ -0,0 +1,9 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
+package: issue1529
+generate:
+ client: true
+ models: true
+ embedded-spec: true
+ fiber-server: true
+ strict-server: true
+output: issue1529.gen.go
diff --git a/internal/test/issues/issue-1529/strict-fiber/doc.go b/internal/test/issues/issue-1529/strict-fiber/doc.go
new file mode 100644
index 0000000000..4bf78249fa
--- /dev/null
+++ b/internal/test/issues/issue-1529/strict-fiber/doc.go
@@ -0,0 +1,3 @@
+package issue1529
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go
new file mode 100644
index 0000000000..81bb0fad22
--- /dev/null
+++ b/internal/test/issues/issue-1529/strict-fiber/issue1529.gen.go
@@ -0,0 +1,529 @@
+// Package issue1529 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1529
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gofiber/fiber/v2"
+)
+
+// Test defines model for Test.
+type Test = map[string]interface{}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // Test request
+ Test(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) Test(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewTestRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewTestRequest generates requests for Test
+func NewTestRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/test")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // TestWithResponse request
+ TestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*TestResponse, error)
+}
+
+type TestResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Test
+ ApplicationjsonProfileBar200 *Test
+ ApplicationjsonProfileFoo200 *Test
+}
+
+// GetJSON200 returns JSON200
+func (r TestResponse) GetJSON200() *Test {
+ return r.JSON200
+}
+
+// GetApplicationjsonProfileBar200 returns ApplicationjsonProfileBar200
+func (r TestResponse) GetApplicationjsonProfileBar200() *Test {
+ return r.ApplicationjsonProfileBar200
+}
+
+// GetApplicationjsonProfileFoo200 returns ApplicationjsonProfileFoo200
+func (r TestResponse) GetApplicationjsonProfileFoo200() *Test {
+ return r.ApplicationjsonProfileFoo200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r TestResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r TestResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r TestResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r TestResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// TestWithResponse request returning *TestResponse
+func (c *ClientWithResponses) TestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*TestResponse, error) {
+ rsp, err := c.Test(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseTestResponse(rsp)
+}
+
+// ParseTestResponse parses an HTTP response from a TestWithResponse call
+func ParseTestResponse(rsp *http.Response) (*TestResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &TestResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 200:
+ var dest Test
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ case rsp.Header.Get("Content-Type") == "application/json; profile=\"Bar\"" && rsp.StatusCode == 200:
+ var dest Test
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.ApplicationjsonProfileBar200 = &dest
+
+ case rsp.Header.Get("Content-Type") == "application/json; profile=\"Foo\"" && rsp.StatusCode == 200:
+ var dest Test
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.ApplicationjsonProfileFoo200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /test)
+ Test(c *fiber.Ctx) error
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []HandlerMiddlewareFunc
+}
+
+type MiddlewareFunc fiber.Handler
+type HandlerMiddlewareFunc func(c *fiber.Ctx, next fiber.Handler) error
+
+// Test operation middleware
+func (siw *ServerInterfaceWrapper) Test(c *fiber.Ctx) error {
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.Test(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// FiberServerOptions provides options for the Fiber server.
+type FiberServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ HandlerMiddlewares []HandlerMiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router fiber.Router, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, FiberServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.HandlerMiddlewares,
+ }
+
+ for _, m := range options.Middlewares {
+ router.Use(fiber.Handler(m))
+ }
+
+ router.Get(options.BaseURL+"/test", wrapper.Test)
+
+}
+
+type TestRequestObject struct {
+}
+
+type TestResponseObject interface {
+ VisitTestResponse(ctx *fiber.Ctx) error
+}
+
+type Test200JSONResponse Test
+
+func (response Test200JSONResponse) VisitTestResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "application/json")
+ ctx.Status(200)
+
+ return ctx.JSON(&response)
+}
+
+type Test200ApplicationJSONProfileBarResponse Test
+
+func (response Test200ApplicationJSONProfileBarResponse) VisitTestResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "application/json; profile=\"Bar\"")
+ ctx.Status(200)
+
+ return ctx.JSON(&response)
+}
+
+type Test200ApplicationJSONProfileFooResponse Test
+
+func (response Test200ApplicationJSONProfileFooResponse) VisitTestResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "application/json; profile=\"Foo\"")
+ ctx.Status(200)
+
+ return ctx.JSON(&response)
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /test)
+ Test(ctx context.Context, request TestRequestObject) (TestResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx *fiber.Ctx, args any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+}
+
+// Test operation middleware
+func (sh *strictHandler) Test(ctx *fiber.Ctx) error {
+ var request TestRequestObject
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.Test(ctx.UserContext(), request.(TestRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "Test")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(TestResponseObject); ok {
+ if err := validResponse.VisitTestResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "rM8xSwQxEAXgvyJPy3BZtYvYWAj2ltfEOOvlyM0MyVjIsv9dEhcWLMVp3jTvY2ZBkosKE1tDWNDSiS5x",
+ "rK/UrKd9KSFA3s6UDOu6OmSeBYE/S3EQJY6aEXB/mA63cNBopyF424gPGiFKNVoWfnlH+PEdKjUVbjQa",
+ "d9PUIwkb8ehE1ZLTaPlzE96P7NtNpRkB137/wm8v+OH3a38TD1daZc6FHo94ivWIfzafRf5gbvMdAAD/",
+ "/w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1529/strict-fiber/spec.yaml b/internal/test/issues/issue-1529/strict-fiber/spec.yaml
new file mode 100644
index 0000000000..ca7aae80a3
--- /dev/null
+++ b/internal/test/issues/issue-1529/strict-fiber/spec.yaml
@@ -0,0 +1,21 @@
+openapi: "3.0.1"
+components:
+ schemas:
+ Test:
+ type: object
+paths:
+ /test:
+ get:
+ operationId: test
+ responses:
+ 200:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Test"
+ application/json; profile="Foo":
+ schema:
+ $ref: "#/components/schemas/Test"
+ application/json; profile="Bar":
+ schema:
+ $ref: "#/components/schemas/Test"
diff --git a/internal/test/issues/issue-1529/strict-iris/config.yaml b/internal/test/issues/issue-1529/strict-iris/config.yaml
new file mode 100644
index 0000000000..835b035300
--- /dev/null
+++ b/internal/test/issues/issue-1529/strict-iris/config.yaml
@@ -0,0 +1,9 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
+package: issue1529
+generate:
+ client: true
+ models: true
+ embedded-spec: true
+ iris-server: true
+ strict-server: true
+output: issue1529.gen.go
diff --git a/internal/test/issues/issue-1529/strict-iris/doc.go b/internal/test/issues/issue-1529/strict-iris/doc.go
new file mode 100644
index 0000000000..4bf78249fa
--- /dev/null
+++ b/internal/test/issues/issue-1529/strict-iris/doc.go
@@ -0,0 +1,3 @@
+package issue1529
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go b/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go
new file mode 100644
index 0000000000..69478c9163
--- /dev/null
+++ b/internal/test/issues/issue-1529/strict-iris/issue1529.gen.go
@@ -0,0 +1,514 @@
+// Package issue1529 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1529
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/kataras/iris/v12"
+)
+
+// Test defines model for Test.
+type Test = map[string]interface{}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // Test request
+ Test(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) Test(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewTestRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewTestRequest generates requests for Test
+func NewTestRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/test")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // TestWithResponse request
+ TestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*TestResponse, error)
+}
+
+type TestResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Test
+ ApplicationjsonProfileBar200 *Test
+ ApplicationjsonProfileFoo200 *Test
+}
+
+// GetJSON200 returns JSON200
+func (r TestResponse) GetJSON200() *Test {
+ return r.JSON200
+}
+
+// GetApplicationjsonProfileBar200 returns ApplicationjsonProfileBar200
+func (r TestResponse) GetApplicationjsonProfileBar200() *Test {
+ return r.ApplicationjsonProfileBar200
+}
+
+// GetApplicationjsonProfileFoo200 returns ApplicationjsonProfileFoo200
+func (r TestResponse) GetApplicationjsonProfileFoo200() *Test {
+ return r.ApplicationjsonProfileFoo200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r TestResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r TestResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r TestResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r TestResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// TestWithResponse request returning *TestResponse
+func (c *ClientWithResponses) TestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*TestResponse, error) {
+ rsp, err := c.Test(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseTestResponse(rsp)
+}
+
+// ParseTestResponse parses an HTTP response from a TestWithResponse call
+func ParseTestResponse(rsp *http.Response) (*TestResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &TestResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 200:
+ var dest Test
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ case rsp.Header.Get("Content-Type") == "application/json; profile=\"Bar\"" && rsp.StatusCode == 200:
+ var dest Test
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.ApplicationjsonProfileBar200 = &dest
+
+ case rsp.Header.Get("Content-Type") == "application/json; profile=\"Foo\"" && rsp.StatusCode == 200:
+ var dest Test
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.ApplicationjsonProfileFoo200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /test)
+ Test(ctx iris.Context)
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+type MiddlewareFunc iris.Handler
+
+// Test converts iris context to params.
+func (w *ServerInterfaceWrapper) Test(ctx iris.Context) {
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.Test(ctx)
+}
+
+// IrisServerOption is the option for iris server
+type IrisServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router *iris.Application, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, IrisServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router *iris.Application, si ServerInterface, options IrisServerOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.Get(options.BaseURL+"/test", wrapper.Test)
+
+ router.Build()
+}
+
+type TestRequestObject struct {
+}
+
+type TestResponseObject interface {
+ VisitTestResponse(ctx iris.Context) error
+}
+
+type Test200JSONResponse Test
+
+func (response Test200JSONResponse) VisitTestResponse(ctx iris.Context) error {
+ ctx.ResponseWriter().Header().Set("Content-Type", "application/json")
+ ctx.StatusCode(200)
+
+ return ctx.JSON(&response)
+}
+
+type Test200ApplicationJSONProfileBarResponse Test
+
+func (response Test200ApplicationJSONProfileBarResponse) VisitTestResponse(ctx iris.Context) error {
+ ctx.ResponseWriter().Header().Set("Content-Type", "application/json; profile=\"Bar\"")
+ ctx.StatusCode(200)
+
+ return ctx.JSON(&response)
+}
+
+type Test200ApplicationJSONProfileFooResponse Test
+
+func (response Test200ApplicationJSONProfileFooResponse) VisitTestResponse(ctx iris.Context) error {
+ ctx.ResponseWriter().Header().Set("Content-Type", "application/json; profile=\"Foo\"")
+ ctx.StatusCode(200)
+
+ return ctx.JSON(&response)
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /test)
+ Test(ctx context.Context, request TestRequestObject) (TestResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx iris.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+}
+
+// Test operation middleware
+func (sh *strictHandler) Test(ctx iris.Context) {
+ var request TestRequestObject
+
+ handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.Test(ctx, request.(TestRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "Test")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ } else if validResponse, ok := response.(TestResponseObject); ok {
+ if err := validResponse.VisitTestResponse(ctx); err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else if response != nil {
+ ctx.Writef("Unexpected response type: %T", response)
+ return
+ }
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "rM8xSwQxEAXgvyJPy3BZtYvYWAj2ltfEOOvlyM0MyVjIsv9dEhcWLMVp3jTvY2ZBkosKE1tDWNDSiS5x",
+ "rK/UrKd9KSFA3s6UDOu6OmSeBYE/S3EQJY6aEXB/mA63cNBopyF424gPGiFKNVoWfnlH+PEdKjUVbjQa",
+ "d9PUIwkb8ehE1ZLTaPlzE96P7NtNpRkB137/wm8v+OH3a38TD1daZc6FHo94ivWIfzafRf5gbvMdAAD/",
+ "/w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-1529/strict-iris/spec.yaml b/internal/test/issues/issue-1529/strict-iris/spec.yaml
new file mode 100644
index 0000000000..ca7aae80a3
--- /dev/null
+++ b/internal/test/issues/issue-1529/strict-iris/spec.yaml
@@ -0,0 +1,21 @@
+openapi: "3.0.1"
+components:
+ schemas:
+ Test:
+ type: object
+paths:
+ /test:
+ get:
+ operationId: test
+ responses:
+ 200:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Test"
+ application/json; profile="Foo":
+ schema:
+ $ref: "#/components/schemas/Test"
+ application/json; profile="Bar":
+ schema:
+ $ref: "#/components/schemas/Test"
diff --git a/internal/test/issues/issue-1530/config.yaml b/internal/test/issues/issue-1530/config.yaml
new file mode 100644
index 0000000000..3cb9f3dd04
--- /dev/null
+++ b/internal/test/issues/issue-1530/config.yaml
@@ -0,0 +1,4 @@
+package: issue1530
+generate:
+ models: true
+output: issue1530.gen.go
\ No newline at end of file
diff --git a/internal/test/issues/issue-1530/doc.go b/internal/test/issues/issue-1530/doc.go
new file mode 100644
index 0000000000..c6a0133735
--- /dev/null
+++ b/internal/test/issues/issue-1530/doc.go
@@ -0,0 +1,3 @@
+package issue1530
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml issue1530.yaml
diff --git a/internal/test/issues/issue-1530/issue1530.gen.go b/internal/test/issues/issue-1530/issue1530.gen.go
new file mode 100644
index 0000000000..8a60251b2c
--- /dev/null
+++ b/internal/test/issues/issue-1530/issue1530.gen.go
@@ -0,0 +1,126 @@
+// Package issue1530 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1530
+
+import (
+ "encoding/json"
+ "errors"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// ConfigHttp defines model for ConfigHttp.
+type ConfigHttp struct {
+ ConfigType string `json:"config_type"`
+ Host string `json:"host"`
+ Password *string `json:"password,omitempty"`
+ Port int `json:"port"`
+ User *string `json:"user,omitempty"`
+}
+
+// ConfigSaveReq defines model for ConfigSaveReq.
+type ConfigSaveReq struct {
+ union json.RawMessage
+}
+
+// ConfigSsh defines model for ConfigSsh.
+type ConfigSsh struct {
+ ConfigType string `json:"config_type"`
+ Host *string `json:"host,omitempty"`
+ Port *int `json:"port,omitempty"`
+ PrivateKey *string `json:"private_key,omitempty"`
+ User *string `json:"user,omitempty"`
+}
+
+// PostConfigJSONRequestBody defines body for PostConfig for application/json ContentType.
+type PostConfigJSONRequestBody = ConfigSaveReq
+
+// AsConfigHttp returns the union data inside the ConfigSaveReq as a ConfigHttp
+func (t ConfigSaveReq) AsConfigHttp() (ConfigHttp, error) {
+ var body ConfigHttp
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromConfigHttp overwrites any union data inside the ConfigSaveReq as the provided ConfigHttp
+func (t *ConfigSaveReq) FromConfigHttp(v ConfigHttp) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeConfigHttp performs a merge with any union data inside the ConfigSaveReq, using the provided ConfigHttp
+func (t *ConfigSaveReq) MergeConfigHttp(v ConfigHttp) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsConfigSsh returns the union data inside the ConfigSaveReq as a ConfigSsh
+func (t ConfigSaveReq) AsConfigSsh() (ConfigSsh, error) {
+ var body ConfigSsh
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromConfigSsh overwrites any union data inside the ConfigSaveReq as the provided ConfigSsh
+func (t *ConfigSaveReq) FromConfigSsh(v ConfigSsh) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeConfigSsh performs a merge with any union data inside the ConfigSaveReq, using the provided ConfigSsh
+func (t *ConfigSaveReq) MergeConfigSsh(v ConfigSsh) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t ConfigSaveReq) Discriminator() (string, error) {
+ var discriminator struct {
+ Discriminator string `json:"config_type"`
+ }
+ err := json.Unmarshal(t.union, &discriminator)
+ return discriminator.Discriminator, err
+}
+
+func (t ConfigSaveReq) ValueByDiscriminator() (interface{}, error) {
+ discriminator, err := t.Discriminator()
+ if err != nil {
+ return nil, err
+ }
+ switch discriminator {
+ case "another_server":
+ return t.AsConfigHttp()
+ case "apache_server":
+ return t.AsConfigHttp()
+ case "ssh_server":
+ return t.AsConfigSsh()
+ case "web_server":
+ return t.AsConfigHttp()
+ default:
+ return nil, errors.New("unknown discriminator value: " + discriminator)
+ }
+}
+
+func (t ConfigSaveReq) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *ConfigSaveReq) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
diff --git a/internal/test/issues/issue-1530/issue1530.yaml b/internal/test/issues/issue-1530/issue1530.yaml
new file mode 100644
index 0000000000..222d074b7b
--- /dev/null
+++ b/internal/test/issues/issue-1530/issue1530.yaml
@@ -0,0 +1,57 @@
+paths:
+ /config:
+ post:
+ summary: Save configuration
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ConfigSaveReq"
+ responses:
+ "200":
+ description: Configuration saved successfully
+components:
+ schemas:
+ ConfigHttp:
+ type: object
+ properties:
+ config_type:
+ type: string
+ host:
+ type: string
+ port:
+ type: integer
+ user:
+ type: string
+ password:
+ type: string
+ required:
+ - config_type
+ - host
+ - port
+ ConfigSaveReq:
+ oneOf:
+ - $ref: "#/components/schemas/ConfigHttp"
+ - $ref: "#/components/schemas/ConfigSsh"
+ discriminator:
+ propertyName: config_type
+ mapping:
+ ssh_server: "#/components/schemas/ConfigSsh"
+ apache_server: "#/components/schemas/ConfigHttp"
+ web_server: "#/components/schemas/ConfigHttp"
+ another_server: "#/components/schemas/ConfigHttp"
+ ConfigSsh:
+ type: object
+ properties:
+ config_type:
+ type: string
+ host:
+ type: string
+ port:
+ type: integer
+ user:
+ type: string
+ private_key:
+ type: string
+ required:
+ - config_type
\ No newline at end of file
diff --git a/internal/test/issues/issue-1530/issue1530_test.go b/internal/test/issues/issue-1530/issue1530_test.go
new file mode 100644
index 0000000000..a23f7ed2d8
--- /dev/null
+++ b/internal/test/issues/issue-1530/issue1530_test.go
@@ -0,0 +1,51 @@
+package issue1530_test
+
+import (
+ "testing"
+
+ issue1530 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1530"
+ "github.com/stretchr/testify/require"
+)
+
+func TestIssue1530(t *testing.T) {
+ httpConfigTypes := []string{
+ "another_server",
+ "apache_server",
+ "web_server",
+ }
+
+ for _, configType := range httpConfigTypes {
+ t.Run("http-"+configType, func(t *testing.T) {
+ saveReq := issue1530.ConfigSaveReq{}
+ err := saveReq.FromConfigHttp(issue1530.ConfigHttp{
+ ConfigType: configType,
+ Host: "example.com",
+ })
+ require.NoError(t, err)
+
+ cfg, err := saveReq.AsConfigHttp()
+ require.NoError(t, err)
+ require.Equal(t, configType, cfg.ConfigType)
+
+ cfgByDiscriminator, err := saveReq.ValueByDiscriminator()
+ require.NoError(t, err)
+ require.Equal(t, cfg, cfgByDiscriminator)
+ })
+ }
+
+ t.Run("ssh", func(t *testing.T) {
+ saveReq := issue1530.ConfigSaveReq{}
+ err := saveReq.FromConfigSsh(issue1530.ConfigSsh{
+ ConfigType: "ssh_server",
+ })
+ require.NoError(t, err)
+
+ cfg, err := saveReq.AsConfigSsh()
+ require.NoError(t, err)
+ require.Equal(t, "ssh_server", cfg.ConfigType)
+
+ cfgByDiscriminator, err := saveReq.ValueByDiscriminator()
+ require.NoError(t, err)
+ require.Equal(t, cfg, cfgByDiscriminator)
+ })
+}
diff --git a/internal/test/issues/issue-1676/api.yaml b/internal/test/issues/issue-1676/api.yaml
new file mode 100644
index 0000000000..717d75afd9
--- /dev/null
+++ b/internal/test/issues/issue-1676/api.yaml
@@ -0,0 +1,17 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Issue 1676
+paths:
+ /ping:
+ get:
+ responses:
+ '200':
+ headers:
+ MyHeader:
+ schema:
+ type: string
+ content:
+ text/plain:
+ schema:
+ type: string
diff --git a/internal/test/issues/issue-1676/cfg.yaml b/internal/test/issues/issue-1676/cfg.yaml
new file mode 100644
index 0000000000..964454fe2f
--- /dev/null
+++ b/internal/test/issues/issue-1676/cfg.yaml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
+package: issue1676
+output: ping.gen.go
+generate:
+ models: true
+ gorilla-server: true
+ strict-server: true
diff --git a/internal/test/issues/issue-1676/generate.go b/internal/test/issues/issue-1676/generate.go
new file mode 100644
index 0000000000..49aa70b8a9
--- /dev/null
+++ b/internal/test/issues/issue-1676/generate.go
@@ -0,0 +1,3 @@
+package issue1676
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/internal/test/issues/issue-1676/ping.gen.go b/internal/test/issues/issue-1676/ping.gen.go
new file mode 100644
index 0000000000..30229f8183
--- /dev/null
+++ b/internal/test/issues/issue-1676/ping.gen.go
@@ -0,0 +1,248 @@
+// Package issue1676 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1676
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+
+ "github.com/gorilla/mux"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /ping)
+ GetPing(w http.ResponseWriter, r *http.Request)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetPing operation middleware
+func (siw *ServerInterfaceWrapper) GetPing(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetPing(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+ BaseURL string
+ BaseRouter *mux.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = mux.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.HandleFunc(options.BaseURL+"/ping", wrapper.GetPing).Methods(http.MethodGet)
+
+ return r
+}
+
+type GetPingRequestObject struct {
+}
+
+type GetPingResponseObject interface {
+ VisitGetPingResponse(w http.ResponseWriter) error
+}
+
+type GetPing200ResponseHeaders struct {
+ MyHeader *string
+}
+
+type GetPing200TextResponse struct {
+ Body string
+ Headers GetPing200ResponseHeaders
+}
+
+func (response GetPing200TextResponse) VisitGetPingResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "text/plain")
+ if response.Headers.MyHeader != nil {
+ w.Header().Set("MyHeader", fmt.Sprint(*response.Headers.MyHeader))
+ }
+ w.WriteHeader(200)
+
+ _, err := w.Write([]byte(response.Body))
+ return err
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /ping)
+ GetPing(ctx context.Context, request GetPingRequestObject) (GetPingResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// GetPing operation middleware
+func (sh *strictHandler) GetPing(w http.ResponseWriter, r *http.Request) {
+ var request GetPingRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetPing(ctx, request.(GetPingRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetPing")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetPingResponseObject); ok {
+ if err := validResponse.VisitGetPingResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/internal/test/issues/issue-1914/cfg.yaml b/internal/test/issues/issue-1914/cfg.yaml
new file mode 100644
index 0000000000..1772f23885
--- /dev/null
+++ b/internal/test/issues/issue-1914/cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue1914
+output: client.gen.go
+generate:
+ client: true
+ models: true
diff --git a/internal/test/issues/issue-1914/client.gen.go b/internal/test/issues/issue-1914/client.gen.go
new file mode 100644
index 0000000000..4417fe5a8d
--- /dev/null
+++ b/internal/test/issues/issue-1914/client.gen.go
@@ -0,0 +1,427 @@
+// Package issue1914 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1914
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ openapi_types "github.com/oapi-codegen/runtime/types"
+)
+
+// PostPetTextBody defines parameters for PostPet.
+type PostPetTextBody = openapi_types.UUID
+
+// PostPet1234TextBody defines parameters for PostPet1234.
+type PostPet1234TextBody = float32
+
+// PostPetTextRequestBody defines body for PostPet for text/plain ContentType.
+type PostPetTextRequestBody = PostPetTextBody
+
+// PostPet1234TextRequestBody defines body for PostPet1234 for text/plain ContentType.
+type PostPet1234TextRequestBody = PostPet1234TextBody
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // PostPetWithBody request with any body
+ PostPetWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PostPetWithTextBody(ctx context.Context, body PostPetTextRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // PostPet1234WithBody request with any body
+ PostPet1234WithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PostPet1234WithTextBody(ctx context.Context, body PostPet1234TextRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) PostPetWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostPetRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostPetWithTextBody(ctx context.Context, body PostPetTextRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostPetRequestWithTextBody(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostPet1234WithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostPet1234RequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostPet1234WithTextBody(ctx context.Context, body PostPet1234TextRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostPet1234RequestWithTextBody(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewPostPetRequestWithTextBody calls the generic PostPet builder with text/plain body
+func NewPostPetRequestWithTextBody(server string, body PostPetTextRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ if stringer, ok := interface{}(body).(fmt.Stringer); ok {
+ bodyReader = strings.NewReader(stringer.String())
+ } else {
+ bodyReader = strings.NewReader(fmt.Sprint(body))
+ }
+ return NewPostPetRequestWithBody(server, "text/plain", bodyReader)
+}
+
+// NewPostPetRequestWithBody generates requests for PostPet with any type of body
+func NewPostPetRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/pet")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewPostPet1234RequestWithTextBody calls the generic PostPet1234 builder with text/plain body
+func NewPostPet1234RequestWithTextBody(server string, body PostPet1234TextRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ if stringer, ok := interface{}(body).(fmt.Stringer); ok {
+ bodyReader = strings.NewReader(stringer.String())
+ } else {
+ bodyReader = strings.NewReader(fmt.Sprint(body))
+ }
+ return NewPostPet1234RequestWithBody(server, "text/plain", bodyReader)
+}
+
+// NewPostPet1234RequestWithBody generates requests for PostPet1234 with any type of body
+func NewPostPet1234RequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/pet/1234")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // PostPetWithBodyWithResponse request with any body
+ PostPetWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostPetResponse, error)
+
+ PostPetWithTextBodyWithResponse(ctx context.Context, body PostPetTextRequestBody, reqEditors ...RequestEditorFn) (*PostPetResponse, error)
+
+ // PostPet1234WithBodyWithResponse request with any body
+ PostPet1234WithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostPet1234Response, error)
+
+ PostPet1234WithTextBodyWithResponse(ctx context.Context, body PostPet1234TextRequestBody, reqEditors ...RequestEditorFn) (*PostPet1234Response, error)
+}
+
+type PostPetResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r PostPetResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r PostPetResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PostPetResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostPetResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type PostPet1234Response struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r PostPet1234Response) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r PostPet1234Response) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PostPet1234Response) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostPet1234Response) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// PostPetWithBodyWithResponse request with arbitrary body returning *PostPetResponse
+func (c *ClientWithResponses) PostPetWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostPetResponse, error) {
+ rsp, err := c.PostPetWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostPetResponse(rsp)
+}
+
+func (c *ClientWithResponses) PostPetWithTextBodyWithResponse(ctx context.Context, body PostPetTextRequestBody, reqEditors ...RequestEditorFn) (*PostPetResponse, error) {
+ rsp, err := c.PostPetWithTextBody(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostPetResponse(rsp)
+}
+
+// PostPet1234WithBodyWithResponse request with arbitrary body returning *PostPet1234Response
+func (c *ClientWithResponses) PostPet1234WithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostPet1234Response, error) {
+ rsp, err := c.PostPet1234WithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostPet1234Response(rsp)
+}
+
+func (c *ClientWithResponses) PostPet1234WithTextBodyWithResponse(ctx context.Context, body PostPet1234TextRequestBody, reqEditors ...RequestEditorFn) (*PostPet1234Response, error) {
+ rsp, err := c.PostPet1234WithTextBody(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostPet1234Response(rsp)
+}
+
+// ParsePostPetResponse parses an HTTP response from a PostPetWithResponse call
+func ParsePostPetResponse(rsp *http.Response) (*PostPetResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &PostPetResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
+// ParsePostPet1234Response parses an HTTP response from a PostPet1234WithResponse call
+func ParsePostPet1234Response(rsp *http.Response) (*PostPet1234Response, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &PostPet1234Response{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
diff --git a/internal/test/issues/issue-1914/client_test.go b/internal/test/issues/issue-1914/client_test.go
new file mode 100644
index 0000000000..282c589179
--- /dev/null
+++ b/internal/test/issues/issue-1914/client_test.go
@@ -0,0 +1,44 @@
+package issue1914
+
+import (
+ "io"
+ "testing"
+
+ "github.com/google/uuid"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+const testServer = "https://localhost"
+
+func TestNewPostPetRequestWithTextBody_CorrectlyMarshalsUUID(t *testing.T) {
+ id := uuid.New()
+
+ req, err := NewPostPetRequestWithTextBody(testServer, id)
+ require.NoError(t, err)
+
+ defer req.Body.Close() //nolint:errcheck
+
+ bytes, err := io.ReadAll(req.Body)
+ require.NoError(t, err)
+
+ require.NotEmpty(t, bytes)
+
+ assert.Equal(t, id.String(), string(bytes))
+}
+
+func TestNewPostPet1234RequestWithTextBody_CorrectlyMarshalsFloat(t *testing.T) {
+ var id float32 = 1234.1
+
+ req, err := NewPostPet1234RequestWithTextBody(testServer, id)
+ require.NoError(t, err)
+
+ defer req.Body.Close() //nolint:errcheck
+
+ bytes, err := io.ReadAll(req.Body)
+ require.NoError(t, err)
+
+ require.NotEmpty(t, bytes)
+
+ assert.Equal(t, "1234.1", string(bytes))
+}
diff --git a/internal/test/issues/issue-1914/generate.go b/internal/test/issues/issue-1914/generate.go
new file mode 100644
index 0000000000..57e3c91587
--- /dev/null
+++ b/internal/test/issues/issue-1914/generate.go
@@ -0,0 +1,3 @@
+package issue1914
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=cfg.yaml spec.yaml
diff --git a/internal/test/issues/issue-1914/spec.yaml b/internal/test/issues/issue-1914/spec.yaml
new file mode 100644
index 0000000000..2f00f52f49
--- /dev/null
+++ b/internal/test/issues/issue-1914/spec.yaml
@@ -0,0 +1,19 @@
+openapi: 3.0.3
+paths:
+ /pet:
+ post:
+ description: Ensure that the `text/plain` format correctly handles coercing a UUID type to a string.
+ requestBody:
+ content:
+ text/plain:
+ schema:
+ type: string
+ format: uuid
+ /pet/1234:
+ post:
+ description: Ensure that the `text/plain` format correctly handles coercing a numerical type to a string.
+ requestBody:
+ content:
+ text/plain:
+ schema:
+ type: number
diff --git a/internal/test/issues/issue-1963/config.yaml b/internal/test/issues/issue-1963/config.yaml
new file mode 100644
index 0000000000..01b8499a74
--- /dev/null
+++ b/internal/test/issues/issue-1963/config.yaml
@@ -0,0 +1,6 @@
+package: issue1963
+output: issue1963.gen.go
+generate:
+ std-http-server: true
+ strict-server: true
+ models: true
diff --git a/internal/test/issues/issue-1963/generate.go b/internal/test/issues/issue-1963/generate.go
new file mode 100644
index 0000000000..89436b3beb
--- /dev/null
+++ b/internal/test/issues/issue-1963/generate.go
@@ -0,0 +1,3 @@
+package issue1963
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-1963/issue1963.gen.go b/internal/test/issues/issue-1963/issue1963.gen.go
new file mode 100644
index 0000000000..b2968de7b7
--- /dev/null
+++ b/internal/test/issues/issue-1963/issue1963.gen.go
@@ -0,0 +1,589 @@
+//go:build go1.22
+
+// Package issue1963 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1963
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "mime/multipart"
+ "net/http"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// Request defines model for Request.
+type Request struct {
+ Value *string `json:"value,omitempty"`
+}
+
+// Response defines model for Response.
+type Response struct {
+ Value *string `json:"value,omitempty"`
+}
+
+// MultipartEndpointMultipartBody defines parameters for MultipartEndpoint.
+type MultipartEndpointMultipartBody struct {
+ Field *string `json:"field,omitempty"`
+}
+
+// TextEndpointTextBody defines parameters for TextEndpoint.
+type TextEndpointTextBody = string
+
+// FormdataEndpointFormdataRequestBody defines body for FormdataEndpoint for application/x-www-form-urlencoded ContentType.
+type FormdataEndpointFormdataRequestBody = Request
+
+// JsonEndpointJSONRequestBody defines body for JsonEndpoint for application/json ContentType.
+type JsonEndpointJSONRequestBody = Request
+
+// MultipartEndpointMultipartRequestBody defines body for MultipartEndpoint for multipart/form-data ContentType.
+type MultipartEndpointMultipartRequestBody MultipartEndpointMultipartBody
+
+// TextEndpointTextRequestBody defines body for TextEndpoint for text/plain ContentType.
+type TextEndpointTextRequestBody = TextEndpointTextBody
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (POST /binary)
+ BinaryEndpoint(w http.ResponseWriter, r *http.Request)
+
+ // (POST /formdata)
+ FormdataEndpoint(w http.ResponseWriter, r *http.Request)
+
+ // (POST /json)
+ JsonEndpoint(w http.ResponseWriter, r *http.Request)
+
+ // (POST /multipart)
+ MultipartEndpoint(w http.ResponseWriter, r *http.Request)
+
+ // (POST /text)
+ TextEndpoint(w http.ResponseWriter, r *http.Request)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// BinaryEndpoint operation middleware
+func (siw *ServerInterfaceWrapper) BinaryEndpoint(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.BinaryEndpoint(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// FormdataEndpoint operation middleware
+func (siw *ServerInterfaceWrapper) FormdataEndpoint(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.FormdataEndpoint(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// JsonEndpoint operation middleware
+func (siw *ServerInterfaceWrapper) JsonEndpoint(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.JsonEndpoint(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// MultipartEndpoint operation middleware
+func (siw *ServerInterfaceWrapper) MultipartEndpoint(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.MultipartEndpoint(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// TextEndpoint operation middleware
+func (siw *ServerInterfaceWrapper) TextEndpoint(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.TextEndpoint(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{})
+}
+
+// ServeMux is an abstraction of [http.ServeMux].
+type ServeMux interface {
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+ http.Handler
+}
+
+type StdHTTPServerOptions struct {
+ BaseURL string
+ BaseRouter ServeMux
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/binary", wrapper.BinaryEndpoint)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/formdata", wrapper.FormdataEndpoint)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/json", wrapper.JsonEndpoint)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/multipart", wrapper.MultipartEndpoint)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/text", wrapper.TextEndpoint)
+
+ return m
+}
+
+type BinaryEndpointRequestObject struct {
+ Body io.Reader
+}
+
+type BinaryEndpointResponseObject interface {
+ VisitBinaryEndpointResponse(w http.ResponseWriter) error
+}
+
+type BinaryEndpoint200ApplicationoctetStreamResponse struct {
+ Body io.Reader
+ ContentLength int64
+}
+
+func (response BinaryEndpoint200ApplicationoctetStreamResponse) VisitBinaryEndpointResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "application/octet-stream")
+ if response.ContentLength != 0 {
+ w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
+ }
+ w.WriteHeader(200)
+
+ if closer, ok := response.Body.(io.ReadCloser); ok {
+ defer closer.Close()
+ }
+ _, err := io.Copy(w, response.Body)
+ return err
+}
+
+type FormdataEndpointRequestObject struct {
+ Body *FormdataEndpointFormdataRequestBody
+}
+
+type FormdataEndpointResponseObject interface {
+ VisitFormdataEndpointResponse(w http.ResponseWriter) error
+}
+
+type FormdataEndpoint200FormdataResponse Response
+
+func (response FormdataEndpoint200FormdataResponse) VisitFormdataEndpointResponse(w http.ResponseWriter) error {
+
+ form, err := runtime.MarshalForm(response, nil)
+ if err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
+ w.WriteHeader(200)
+ _, err = w.Write([]byte(form.Encode()))
+ return err
+}
+
+type JsonEndpointRequestObject struct {
+ Body *JsonEndpointJSONRequestBody
+}
+
+type JsonEndpointResponseObject interface {
+ VisitJsonEndpointResponse(w http.ResponseWriter) error
+}
+
+type JsonEndpoint200JSONResponse Response
+
+func (response JsonEndpoint200JSONResponse) VisitJsonEndpointResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type MultipartEndpointRequestObject struct {
+ Body *multipart.Reader
+}
+
+type MultipartEndpointResponseObject interface {
+ VisitMultipartEndpointResponse(w http.ResponseWriter) error
+}
+
+type MultipartEndpoint200MultipartResponse func(writer *multipart.Writer) error
+
+func (response MultipartEndpoint200MultipartResponse) VisitMultipartEndpointResponse(w http.ResponseWriter) error {
+ writer := multipart.NewWriter(w)
+
+ w.Header().Set("Content-Type", writer.FormDataContentType())
+ w.WriteHeader(200)
+
+ defer writer.Close()
+ return response(writer)
+}
+
+type TextEndpointRequestObject struct {
+ Body *TextEndpointTextRequestBody
+}
+
+type TextEndpointResponseObject interface {
+ VisitTextEndpointResponse(w http.ResponseWriter) error
+}
+
+type TextEndpoint200TextResponse string
+
+func (response TextEndpoint200TextResponse) VisitTextEndpointResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "text/plain")
+ w.WriteHeader(200)
+
+ _, err := w.Write([]byte(response))
+ return err
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (POST /binary)
+ BinaryEndpoint(ctx context.Context, request BinaryEndpointRequestObject) (BinaryEndpointResponseObject, error)
+
+ // (POST /formdata)
+ FormdataEndpoint(ctx context.Context, request FormdataEndpointRequestObject) (FormdataEndpointResponseObject, error)
+
+ // (POST /json)
+ JsonEndpoint(ctx context.Context, request JsonEndpointRequestObject) (JsonEndpointResponseObject, error)
+
+ // (POST /multipart)
+ MultipartEndpoint(ctx context.Context, request MultipartEndpointRequestObject) (MultipartEndpointResponseObject, error)
+
+ // (POST /text)
+ TextEndpoint(ctx context.Context, request TextEndpointRequestObject) (TextEndpointResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// BinaryEndpoint operation middleware
+func (sh *strictHandler) BinaryEndpoint(w http.ResponseWriter, r *http.Request) {
+ var request BinaryEndpointRequestObject
+
+ request.Body = r.Body
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.BinaryEndpoint(ctx, request.(BinaryEndpointRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "BinaryEndpoint")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(BinaryEndpointResponseObject); ok {
+ if err := validResponse.VisitBinaryEndpointResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// FormdataEndpoint operation middleware
+func (sh *strictHandler) FormdataEndpoint(w http.ResponseWriter, r *http.Request) {
+ var request FormdataEndpointRequestObject
+
+ if err := r.ParseForm(); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode formdata: %w", err))
+ return
+ }
+ var body FormdataEndpointFormdataRequestBody
+ if err := runtime.BindForm(&body, r.Form, nil, nil); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't bind formdata: %w", err))
+ return
+ }
+ request.Body = &body
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.FormdataEndpoint(ctx, request.(FormdataEndpointRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "FormdataEndpoint")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(FormdataEndpointResponseObject); ok {
+ if err := validResponse.VisitFormdataEndpointResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// JsonEndpoint operation middleware
+func (sh *strictHandler) JsonEndpoint(w http.ResponseWriter, r *http.Request) {
+ var request JsonEndpointRequestObject
+
+ var body JsonEndpointJSONRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ request.Body = &body
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.JsonEndpoint(ctx, request.(JsonEndpointRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "JsonEndpoint")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(JsonEndpointResponseObject); ok {
+ if err := validResponse.VisitJsonEndpointResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// MultipartEndpoint operation middleware
+func (sh *strictHandler) MultipartEndpoint(w http.ResponseWriter, r *http.Request) {
+ var request MultipartEndpointRequestObject
+
+ if reader, err := r.MultipartReader(); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode multipart body: %w", err))
+ return
+ } else {
+ request.Body = reader
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.MultipartEndpoint(ctx, request.(MultipartEndpointRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "MultipartEndpoint")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(MultipartEndpointResponseObject); ok {
+ if err := validResponse.VisitMultipartEndpointResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// TextEndpoint operation middleware
+func (sh *strictHandler) TextEndpoint(w http.ResponseWriter, r *http.Request) {
+ var request TextEndpointRequestObject
+
+ data, err := io.ReadAll(r.Body)
+ if err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't read body: %w", err))
+ return
+ }
+ body := TextEndpointTextRequestBody(data)
+ request.Body = &body
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.TextEndpoint(ctx, request.(TextEndpointRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "TextEndpoint")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(TextEndpointResponseObject); ok {
+ if err := validResponse.VisitTextEndpointResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/internal/test/issues/issue-1963/issue1963_test.go b/internal/test/issues/issue-1963/issue1963_test.go
new file mode 100644
index 0000000000..159e7ab920
--- /dev/null
+++ b/internal/test/issues/issue-1963/issue1963_test.go
@@ -0,0 +1,239 @@
+package issue1963
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "mime"
+ "mime/multipart"
+ "net/http"
+ "net/http/httptest"
+ "strings"
+ "testing"
+
+ "github.com/oapi-codegen/runtime"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+// These tests are regression tests for https://github.com/oapi-codegen/oapi-codegen/issues/1963.
+//
+// The issue: in generated strict server Visit*Response functions, WriteHeader
+// was called before marshalling the response body. If JSON encoding failed,
+// ResponseErrorHandlerFunc could not set a different status code because 200
+// was already written.
+//
+// The fix: JSON responses are buffered via bytes.Buffer before headers are sent.
+// Non-JSON responses retain the original headers-first ordering.
+
+// TestJsonEndpoint_Success verifies JSON responses buffer the body and set
+// Content-Type and status code correctly.
+func TestJsonEndpoint_Success(t *testing.T) {
+ value := "hello"
+ resp := JsonEndpoint200JSONResponse{Value: &value}
+ w := httptest.NewRecorder()
+
+ err := resp.VisitJsonEndpointResponse(w)
+ require.NoError(t, err)
+ assert.Equal(t, 200, w.Code)
+ assert.True(t, strings.HasPrefix(w.Header().Get("Content-Type"), "application/json"))
+
+ var body Response
+ require.NoError(t, json.NewDecoder(w.Body).Decode(&body))
+ assert.Equal(t, &value, body.Value)
+}
+
+// TestTextEndpoint_Success verifies text responses set Content-Type and status code.
+func TestTextEndpoint_Success(t *testing.T) {
+ resp := TextEndpoint200TextResponse("hello world")
+ w := httptest.NewRecorder()
+
+ err := resp.VisitTextEndpointResponse(w)
+ require.NoError(t, err)
+ assert.Equal(t, 200, w.Code)
+ assert.Equal(t, "text/plain", w.Header().Get("Content-Type"))
+ assert.Equal(t, "hello world", w.Body.String())
+}
+
+// TestFormdataEndpoint_Success verifies formdata responses set Content-Type and status code.
+func TestFormdataEndpoint_Success(t *testing.T) {
+ value := "test"
+ resp := FormdataEndpoint200FormdataResponse{Value: &value}
+ w := httptest.NewRecorder()
+
+ err := resp.VisitFormdataEndpointResponse(w)
+ require.NoError(t, err)
+ assert.Equal(t, 200, w.Code)
+ assert.Equal(t, "application/x-www-form-urlencoded", w.Header().Get("Content-Type"))
+ assert.Contains(t, w.Body.String(), "value=test")
+}
+
+// TestMultipartEndpoint_Success verifies multipart responses set Content-Type and status code.
+func TestMultipartEndpoint_Success(t *testing.T) {
+ resp := MultipartEndpoint200MultipartResponse(func(writer *multipart.Writer) error {
+ return writer.WriteField("field", "value")
+ })
+ w := httptest.NewRecorder()
+
+ err := resp.VisitMultipartEndpointResponse(w)
+ require.NoError(t, err)
+ assert.Equal(t, 200, w.Code)
+ ct, params, err := mime.ParseMediaType(w.Header().Get("Content-Type"))
+ require.NoError(t, err)
+ assert.Equal(t, "multipart/form-data", ct)
+
+ reader := multipart.NewReader(w.Body, params["boundary"])
+ part, err := reader.NextPart()
+ require.NoError(t, err)
+ assert.Equal(t, "field", part.FormName())
+ data, err := io.ReadAll(part)
+ require.NoError(t, err)
+ assert.Equal(t, "value", string(data))
+}
+
+// TestBinaryEndpoint_Success verifies binary (io.Reader) responses set Content-Type and status code.
+func TestBinaryEndpoint_Success(t *testing.T) {
+ body := strings.NewReader("binary data")
+ resp := BinaryEndpoint200ApplicationoctetStreamResponse{
+ Body: body,
+ ContentLength: int64(len("binary data")),
+ }
+ w := httptest.NewRecorder()
+
+ err := resp.VisitBinaryEndpointResponse(w)
+ require.NoError(t, err)
+ assert.Equal(t, 200, w.Code)
+ assert.Equal(t, "application/octet-stream", w.Header().Get("Content-Type"))
+ assert.Equal(t, "11", w.Header().Get("Content-Length"))
+ assert.Equal(t, "binary data", w.Body.String())
+}
+
+// TestJsonEndpoint_EncodingError_ErrorHandlerCanSetStatus is the core
+// regression test. It verifies that when JSON encoding fails, the
+// ResponseErrorHandlerFunc can still set the HTTP status code because nothing
+// has been written to the ResponseWriter yet.
+//
+// We use a custom StrictServerInterface implementation that returns a response
+// object whose Visit method will fail during JSON encoding.
+func TestJsonEndpoint_EncodingError_ErrorHandlerCanSetStatus(t *testing.T) {
+ server := &errorServer{}
+ var errHandlerCalled bool
+ handler := NewStrictHandlerWithOptions(server, nil, StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ errHandlerCalled = true
+ w.WriteHeader(http.StatusInternalServerError)
+ },
+ })
+ mux := http.NewServeMux()
+ HandlerFromMux(handler, mux)
+
+ body := `{"value": "test"}`
+ req := httptest.NewRequest(http.MethodPost, "/json", strings.NewReader(body))
+ req.Header.Set("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+
+ mux.ServeHTTP(w, req)
+
+ assert.True(t, errHandlerCalled, "ResponseErrorHandlerFunc should have been called")
+ assert.Equal(t, http.StatusInternalServerError, w.Code,
+ "error handler should be able to set status code to 500 when JSON encoding fails")
+ assert.Empty(t, w.Header().Get("Content-Type"),
+ "Content-Type should not be set when encoding fails before headers are written")
+}
+
+// errorServer implements StrictServerInterface and returns a response whose
+// JSON encoding will fail.
+type errorServer struct{}
+
+func (s *errorServer) JsonEndpoint(_ context.Context, _ JsonEndpointRequestObject) (JsonEndpointResponseObject, error) {
+ return &unmarshalableJSONResponse{}, nil
+}
+
+func (s *errorServer) TextEndpoint(_ context.Context, _ TextEndpointRequestObject) (TextEndpointResponseObject, error) {
+ return nil, fmt.Errorf("not implemented")
+}
+
+func (s *errorServer) FormdataEndpoint(_ context.Context, _ FormdataEndpointRequestObject) (FormdataEndpointResponseObject, error) {
+ return &unmarshalableFormdataResponse{}, nil
+}
+
+func (s *errorServer) MultipartEndpoint(_ context.Context, _ MultipartEndpointRequestObject) (MultipartEndpointResponseObject, error) {
+ return nil, fmt.Errorf("not implemented")
+}
+
+func (s *errorServer) BinaryEndpoint(_ context.Context, _ BinaryEndpointRequestObject) (BinaryEndpointResponseObject, error) {
+ return nil, fmt.Errorf("not implemented")
+}
+
+// TestFormdataEndpoint_MarshalError verifies that when form marshalling fails,
+// ResponseErrorHandlerFunc can set the status code because nothing has been
+// written to the ResponseWriter yet.
+func TestFormdataEndpoint_MarshalError_ErrorHandlerCanSetStatus(t *testing.T) {
+ server := &errorServer{}
+ var errHandlerCalled bool
+ handler := NewStrictHandlerWithOptions(server, nil, StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ errHandlerCalled = true
+ w.WriteHeader(http.StatusInternalServerError)
+ },
+ })
+ mux := http.NewServeMux()
+ HandlerFromMux(handler, mux)
+
+ body := "value=test"
+ req := httptest.NewRequest(http.MethodPost, "/formdata", strings.NewReader(body))
+ req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
+ w := httptest.NewRecorder()
+
+ mux.ServeHTTP(w, req)
+
+ assert.True(t, errHandlerCalled, "ResponseErrorHandlerFunc should have been called")
+ assert.Equal(t, http.StatusInternalServerError, w.Code,
+ "error handler should be able to set status code to 500 when form marshalling fails")
+ assert.Empty(t, w.Header().Get("Content-Type"),
+ "Content-Type should not be set when marshalling fails before headers are written")
+}
+
+// unmarshalableJSONResponse implements JsonEndpointResponseObject with a Visit
+// method that follows the exact same pattern as the generated code but
+// encodes a value that json.Encoder cannot marshal (a channel).
+type unmarshalableJSONResponse struct{}
+
+func (u *unmarshalableJSONResponse) VisitJsonEndpointResponse(w http.ResponseWriter) error {
+ var buf bytes.Buffer
+ // Channels cannot be JSON-encoded; this will return an error.
+ if err := json.NewEncoder(&buf).Encode(map[string]any{
+ "bad": make(chan int),
+ }); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+// unmarshalableFormdataResponse implements FormdataEndpointResponseObject with
+// a Visit method that follows the generated code pattern but passes a channel
+// to runtime.MarshalForm, which will always fail (it expects a struct or map).
+type unmarshalableFormdataResponse struct{}
+
+func (u *unmarshalableFormdataResponse) VisitFormdataEndpointResponse(w http.ResponseWriter) error {
+ // A channel is never a valid form body; MarshalForm will return an error.
+ form, err := runtime.MarshalForm(make(chan int), nil)
+ if err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
+ w.WriteHeader(200)
+ _, err = w.Write([]byte(form.Encode()))
+ return err
+}
diff --git a/internal/test/issues/issue-1963/spec.yaml b/internal/test/issues/issue-1963/spec.yaml
new file mode 100644
index 0000000000..a96d16a5af
--- /dev/null
+++ b/internal/test/issues/issue-1963/spec.yaml
@@ -0,0 +1,105 @@
+openapi: 3.0.3
+info:
+ title: issue-1963
+ version: 1.0.0
+paths:
+ /json:
+ post:
+ operationId: JsonEndpoint
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Request"
+ responses:
+ "200":
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/Response"
+ /text:
+ post:
+ operationId: TextEndpoint
+ requestBody:
+ required: true
+ content:
+ text/plain:
+ schema:
+ type: string
+ responses:
+ "200":
+ description: OK
+ content:
+ text/plain:
+ schema:
+ type: string
+ /formdata:
+ post:
+ operationId: FormdataEndpoint
+ requestBody:
+ required: true
+ content:
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: "#/components/schemas/Request"
+ responses:
+ "200":
+ description: OK
+ content:
+ application/x-www-form-urlencoded:
+ schema:
+ $ref: "#/components/schemas/Response"
+ /multipart:
+ post:
+ operationId: MultipartEndpoint
+ requestBody:
+ required: true
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ properties:
+ field:
+ type: string
+ responses:
+ "200":
+ description: OK
+ content:
+ multipart/form-data:
+ schema:
+ type: object
+ properties:
+ field:
+ type: string
+ /binary:
+ post:
+ operationId: BinaryEndpoint
+ requestBody:
+ required: true
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+ responses:
+ "200":
+ description: OK
+ content:
+ application/octet-stream:
+ schema:
+ type: string
+ format: binary
+components:
+ schemas:
+ Request:
+ type: object
+ properties:
+ value:
+ type: string
+ Response:
+ type: object
+ properties:
+ value:
+ type: string
diff --git a/internal/test/issues/issue-2010/config.base.yaml b/internal/test/issues/issue-2010/config.base.yaml
new file mode 100644
index 0000000000..f42cfee5be
--- /dev/null
+++ b/internal/test/issues/issue-2010/config.base.yaml
@@ -0,0 +1,10 @@
+---
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: spec_base
+generate:
+ chi-server: true
+ strict-server: true
+ models: true
+output: gen/spec_base/issue.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue-2010/config.other.yaml b/internal/test/issues/issue-2010/config.other.yaml
new file mode 100644
index 0000000000..17dde322c1
--- /dev/null
+++ b/internal/test/issues/issue-2010/config.other.yaml
@@ -0,0 +1,12 @@
+---
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: spec_other
+generate:
+ chi-server: true
+ strict-server: true
+ models: true
+import-mapping:
+ ./spec-base.yaml: "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-2010/gen/spec_base"
+output: gen/spec_other/issue.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue-2010/doc.go b/internal/test/issues/issue-2010/doc.go
new file mode 100644
index 0000000000..6c6465877f
--- /dev/null
+++ b/internal/test/issues/issue-2010/doc.go
@@ -0,0 +1,10 @@
+// Regression fixture for https://github.com/oapi-codegen/oapi-codegen/issues/2010.
+//
+// The base spec defines components/responses/400 with a JSON body. The "other"
+// spec references that response via an external $ref. With strict-server
+// enabled in both packages, the embedded response field name must agree across
+// packages so cross-package response casts compile.
+package issue_2010
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.base.yaml spec-base.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.other.yaml spec-other.yaml
diff --git a/internal/test/issues/issue-2010/gen/spec_base/.gitempty b/internal/test/issues/issue-2010/gen/spec_base/.gitempty
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/internal/test/issues/issue-2010/gen/spec_base/issue.gen.go b/internal/test/issues/issue-2010/gen/spec_base/issue.gen.go
new file mode 100644
index 0000000000..95fefde7d0
--- /dev/null
+++ b/internal/test/issues/issue-2010/gen/spec_base/issue.gen.go
@@ -0,0 +1,271 @@
+// Package spec_base provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package spec_base
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ "github.com/go-chi/chi/v5"
+)
+
+// N400 defines model for 400.
+type N400 struct {
+ Message string `json:"message"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /example)
+ GetExample(w http.ResponseWriter, r *http.Request)
+}
+
+// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
+
+type Unimplemented struct{}
+
+// (GET /example)
+func (_ Unimplemented) GetExample(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetExample operation middleware
+func (siw *ServerInterfaceWrapper) GetExample(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetExample(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{})
+}
+
+type ChiServerOptions struct {
+ BaseURL string
+ BaseRouter chi.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = chi.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/example", wrapper.GetExample)
+ })
+
+ return r
+}
+
+type N400JSONResponse struct {
+ Message string `json:"message"`
+}
+
+type GetExampleRequestObject struct {
+}
+
+type GetExampleResponseObject interface {
+ VisitGetExampleResponse(w http.ResponseWriter) error
+}
+
+type GetExample200Response struct {
+}
+
+func (response GetExample200Response) VisitGetExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(200)
+ return nil
+}
+
+type GetExample400JSONResponse struct{ N400JSONResponse }
+
+func (response GetExample400JSONResponse) VisitGetExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /example)
+ GetExample(ctx context.Context, request GetExampleRequestObject) (GetExampleResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// GetExample operation middleware
+func (sh *strictHandler) GetExample(w http.ResponseWriter, r *http.Request) {
+ var request GetExampleRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetExample(ctx, request.(GetExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetExample")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetExampleResponseObject); ok {
+ if err := validResponse.VisitGetExampleResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/internal/test/issues/issue-2010/gen/spec_other/.gitempty b/internal/test/issues/issue-2010/gen/spec_other/.gitempty
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/internal/test/issues/issue-2010/gen/spec_other/issue.gen.go b/internal/test/issues/issue-2010/gen/spec_other/issue.gen.go
new file mode 100644
index 0000000000..1c04f58afa
--- /dev/null
+++ b/internal/test/issues/issue-2010/gen/spec_other/issue.gen.go
@@ -0,0 +1,263 @@
+// Package spec_other provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package spec_other
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ "github.com/go-chi/chi/v5"
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-2010/gen/spec_base"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /example)
+ GetOtherExample(w http.ResponseWriter, r *http.Request)
+}
+
+// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
+
+type Unimplemented struct{}
+
+// (GET /example)
+func (_ Unimplemented) GetOtherExample(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetOtherExample operation middleware
+func (siw *ServerInterfaceWrapper) GetOtherExample(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetOtherExample(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{})
+}
+
+type ChiServerOptions struct {
+ BaseURL string
+ BaseRouter chi.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = chi.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/example", wrapper.GetOtherExample)
+ })
+
+ return r
+}
+
+type GetOtherExampleRequestObject struct {
+}
+
+type GetOtherExampleResponseObject interface {
+ VisitGetOtherExampleResponse(w http.ResponseWriter) error
+}
+
+type GetOtherExample200Response struct {
+}
+
+func (response GetOtherExample200Response) VisitGetOtherExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(200)
+ return nil
+}
+
+type GetOtherExample400JSONResponse struct{ externalRef0.N400JSONResponse }
+
+func (response GetOtherExample400JSONResponse) VisitGetOtherExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /example)
+ GetOtherExample(ctx context.Context, request GetOtherExampleRequestObject) (GetOtherExampleResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// GetOtherExample operation middleware
+func (sh *strictHandler) GetOtherExample(w http.ResponseWriter, r *http.Request) {
+ var request GetOtherExampleRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetOtherExample(ctx, request.(GetOtherExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetOtherExample")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetOtherExampleResponseObject); ok {
+ if err := validResponse.VisitGetOtherExampleResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/internal/test/issues/issue-2010/issue_test.go b/internal/test/issues/issue-2010/issue_test.go
new file mode 100644
index 0000000000..c35741a98a
--- /dev/null
+++ b/internal/test/issues/issue-2010/issue_test.go
@@ -0,0 +1,26 @@
+package issue_2010_test
+
+import (
+ "testing"
+
+ base "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-2010/gen/spec_base"
+ other "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-2010/gen/spec_other"
+)
+
+// Cross-package cast that broke in 2.1.0+ when both specs generate
+// strict-server. Compiling this file is the regression check: if the embedded
+// field names diverge between the local and external strict envelopes, the
+// conversion below fails to compile.
+var _ = func(v base.GetExample400JSONResponse) other.GetOtherExample400JSONResponse {
+ return other.GetOtherExample400JSONResponse(v)
+}
+
+func TestIssue2010ResponseCastAcrossPackages(t *testing.T) {
+ var a base.GetExampleResponseObject = base.GetExample400JSONResponse{}
+ switch v := a.(type) {
+ case base.GetExample400JSONResponse:
+ _ = other.GetOtherExample400JSONResponse(v)
+ default:
+ t.Fatalf("unexpected type %T", a)
+ }
+}
diff --git a/internal/test/issues/issue-2010/spec-base.yaml b/internal/test/issues/issue-2010/spec-base.yaml
new file mode 100644
index 0000000000..931e4d4f90
--- /dev/null
+++ b/internal/test/issues/issue-2010/spec-base.yaml
@@ -0,0 +1,27 @@
+openapi: 3.0.1
+info:
+ description: An example schema
+ title: ExampleAPI
+ version: 1.0.0
+paths:
+ /example:
+ get:
+ operationId: getExample
+ responses:
+ '200':
+ description: OK
+ '400':
+ $ref: "#/components/responses/400"
+components:
+ responses:
+ "400":
+ description: Bad Request
+ content:
+ application/json:
+ schema:
+ type: object
+ required:
+ - message
+ properties:
+ message:
+ type: string
diff --git a/internal/test/issues/issue-2010/spec-other.yaml b/internal/test/issues/issue-2010/spec-other.yaml
new file mode 100644
index 0000000000..f2ffd2305c
--- /dev/null
+++ b/internal/test/issues/issue-2010/spec-other.yaml
@@ -0,0 +1,14 @@
+openapi: 3.0.1
+info:
+ description: Another example schema
+ title: OtherAPI
+ version: 1.0.0
+paths:
+ /example:
+ get:
+ operationId: getOtherExample
+ responses:
+ '200':
+ description: OK
+ '400':
+ $ref: "./spec-base.yaml#/components/responses/400"
diff --git a/internal/test/issues/issue-2031/config.yaml b/internal/test/issues/issue-2031/config.yaml
new file mode 100644
index 0000000000..495396d560
--- /dev/null
+++ b/internal/test/issues/issue-2031/config.yaml
@@ -0,0 +1,4 @@
+package: issue2031
+generate:
+ models: true
+output: issue2031.gen.go
diff --git a/internal/test/issues/issue-2031/generate.go b/internal/test/issues/issue-2031/generate.go
new file mode 100644
index 0000000000..1e29681627
--- /dev/null
+++ b/internal/test/issues/issue-2031/generate.go
@@ -0,0 +1,3 @@
+package issue2031
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml openapi.yaml
diff --git a/internal/test/issues/issue-2031/issue2031.gen.go b/internal/test/issues/issue-2031/issue2031.gen.go
new file mode 100644
index 0000000000..1ae12da963
--- /dev/null
+++ b/internal/test/issues/issue-2031/issue2031.gen.go
@@ -0,0 +1,83 @@
+// Package issue2031 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue2031
+
+import (
+ "encoding/json"
+ "fmt"
+)
+
+// ArrayContainer defines model for ArrayContainer.
+type ArrayContainer struct {
+ Values []string `json:"values,omitempty"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// Getter for additional properties for ArrayContainer. Returns the specified
+// element and whether it was found
+func (a ArrayContainer) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for ArrayContainer
+func (a *ArrayContainer) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for ArrayContainer to handle AdditionalProperties
+func (a *ArrayContainer) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["values"]; found {
+ err = json.Unmarshal(raw, &a.Values)
+ if err != nil {
+ return fmt.Errorf("error reading 'values': %w", err)
+ }
+ delete(object, "values")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for ArrayContainer to handle AdditionalProperties
+func (a ArrayContainer) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Values != nil {
+ object["values"], err = json.Marshal(a.Values)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'values': %w", err)
+ }
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
diff --git a/internal/test/issues/issue-2031/issue2031_test.go b/internal/test/issues/issue-2031/issue2031_test.go
new file mode 100644
index 0000000000..fe631a8bcf
--- /dev/null
+++ b/internal/test/issues/issue-2031/issue2031_test.go
@@ -0,0 +1,18 @@
+package issue2031
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestMarshal(t *testing.T) {
+ value := ArrayContainer{}
+ content, err := json.Marshal(value)
+ require.NoError(t, err)
+ // the _optional array_ should be _omitted_ when null, not marshaled as null
+ // (which is not valid per the schema)
+ assert.Equal(t, "{}", string(content))
+}
diff --git a/internal/test/issues/issue-2031/openapi.yaml b/internal/test/issues/issue-2031/openapi.yaml
new file mode 100644
index 0000000000..54aa5eb404
--- /dev/null
+++ b/internal/test/issues/issue-2031/openapi.yaml
@@ -0,0 +1,27 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Issue 2031
+paths:
+ /test:
+ get:
+ responses:
+ "200":
+ description: A list of strings
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ArrayContainer"
+components:
+ schemas:
+ ArrayContainer:
+ type: object
+ # enabling additionalProperties is required to expose one variant of the bug
+ additionalProperties: true
+ properties:
+ # NOTE: the array property is NOT required and NOT nullable
+ values:
+ x-go-type-skip-optional-pointer: true
+ type: array
+ items:
+ type: string
diff --git a/internal/test/issues/issue-2031/prefer/config.yaml b/internal/test/issues/issue-2031/prefer/config.yaml
new file mode 100644
index 0000000000..4ec155a835
--- /dev/null
+++ b/internal/test/issues/issue-2031/prefer/config.yaml
@@ -0,0 +1,7 @@
+package: issue2031
+generate:
+ models: true
+ client: true
+output-options:
+ prefer-skip-optional-pointer: true
+output: issue2031.gen.go
diff --git a/internal/test/issues/issue-2031/prefer/generate.go b/internal/test/issues/issue-2031/prefer/generate.go
new file mode 100644
index 0000000000..1e29681627
--- /dev/null
+++ b/internal/test/issues/issue-2031/prefer/generate.go
@@ -0,0 +1,3 @@
+package issue2031
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml openapi.yaml
diff --git a/internal/test/issues/issue-2031/prefer/issue2031.gen.go b/internal/test/issues/issue-2031/prefer/issue2031.gen.go
new file mode 100644
index 0000000000..e37c69d6a1
--- /dev/null
+++ b/internal/test/issues/issue-2031/prefer/issue2031.gen.go
@@ -0,0 +1,269 @@
+// Package issue2031 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue2031
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// GetTestParams defines parameters for GetTest.
+type GetTestParams struct {
+ UserIds []int `form:"user_ids[],omitempty" json:"user_ids[],omitempty"`
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetTest request
+ GetTest(ctx context.Context, params *GetTestParams, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetTest(ctx context.Context, params *GetTestParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetTestRequest(c.Server, params)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetTestRequest generates requests for GetTest
+func NewGetTestRequest(server string, params *GetTestParams) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/test")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ if params != nil {
+ // queryValues collects non-styled parameters (passthrough, JSON)
+ // that are safe to round-trip through url.Values.Encode().
+ queryValues := queryURL.Query()
+ // rawQueryFragments collects pre-encoded query fragments from
+ // styled parameters, preserving literal commas as delimiters
+ // per the OpenAPI spec (e.g. "color=blue,black,brown").
+ var rawQueryFragments []string
+
+ if params.UserIds != nil {
+
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "user_ids[]", params.UserIds, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "array", Format: ""}); err != nil {
+ return nil, err
+ } else {
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
+ }
+ }
+
+ }
+
+ if encoded := queryValues.Encode(); encoded != "" {
+ rawQueryFragments = append(rawQueryFragments, encoded)
+ }
+ queryURL.RawQuery = strings.Join(rawQueryFragments, "&")
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetTestWithResponse request
+ GetTestWithResponse(ctx context.Context, params *GetTestParams, reqEditors ...RequestEditorFn) (*GetTestResponse, error)
+}
+
+type GetTestResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetTestResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetTestResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetTestResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetTestResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetTestWithResponse request returning *GetTestResponse
+func (c *ClientWithResponses) GetTestWithResponse(ctx context.Context, params *GetTestParams, reqEditors ...RequestEditorFn) (*GetTestResponse, error) {
+ rsp, err := c.GetTest(ctx, params, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetTestResponse(rsp)
+}
+
+// ParseGetTestResponse parses an HTTP response from a GetTestWithResponse call
+func ParseGetTestResponse(rsp *http.Response) (*GetTestResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetTestResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
diff --git a/internal/test/issues/issue-2031/prefer/issue2031_test.go b/internal/test/issues/issue-2031/prefer/issue2031_test.go
new file mode 100644
index 0000000000..cd0c55c8dd
--- /dev/null
+++ b/internal/test/issues/issue-2031/prefer/issue2031_test.go
@@ -0,0 +1,63 @@
+package issue2031
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestNewGetTestRequest(t *testing.T) {
+ t.Run("does not add the user_ids[] parameter if zero value", func(t *testing.T) {
+ params := GetTestParams{}
+
+ req, err := NewGetTestRequest("https://localhost", ¶ms)
+ require.NoError(t, err)
+
+ assert.Equal(t, "https://localhost/test", req.URL.String())
+ })
+
+ t.Run("does not add the user_ids[] parameter if nil", func(t *testing.T) {
+ params := GetTestParams{
+ UserIds: nil,
+ }
+
+ req, err := NewGetTestRequest("https://localhost", ¶ms)
+ require.NoError(t, err)
+
+ assert.Equal(t, "https://localhost/test", req.URL.String())
+ })
+
+ t.Run("adds the user_ids[] parameter if an explicitly initialised empty array", func(t *testing.T) {
+ params := GetTestParams{
+ UserIds: []int{},
+ }
+
+ req, err := NewGetTestRequest("https://localhost", ¶ms)
+ require.NoError(t, err)
+
+ assert.Equal(t, "https://localhost/test?user_ids%5B%5D=", req.URL.String())
+ })
+
+ t.Run("adds the user_ids[] parameter if array contains a value", func(t *testing.T) {
+ params := GetTestParams{
+ UserIds: []int{1},
+ }
+
+ req, err := NewGetTestRequest("https://localhost", ¶ms)
+ require.NoError(t, err)
+
+ assert.Equal(t, "https://localhost/test?user_ids%5B%5D=1", req.URL.String())
+ })
+
+ t.Run("handles multiple user_ids[] parameters", func(t *testing.T) {
+ params := GetTestParams{
+ UserIds: []int{1, 100},
+ }
+
+ req, err := NewGetTestRequest("https://localhost", ¶ms)
+ require.NoError(t, err)
+
+ assert.Equal(t, "https://localhost/test?user_ids%5B%5D=1&user_ids%5B%5D=100", req.URL.String())
+ })
+}
diff --git a/internal/test/issues/issue-2031/prefer/openapi.yaml b/internal/test/issues/issue-2031/prefer/openapi.yaml
new file mode 100644
index 0000000000..d88d8df2fb
--- /dev/null
+++ b/internal/test/issues/issue-2031/prefer/openapi.yaml
@@ -0,0 +1,17 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Issue 2031
+paths:
+ /test:
+ get:
+ parameters:
+ - name: "user_ids[]"
+ in: query
+ schema:
+ type: array
+ items:
+ type: integer
+ style: form
+ explode: true
+ required: false
diff --git a/internal/test/issues/issue-2113/common/spec.yaml b/internal/test/issues/issue-2113/common/spec.yaml
new file mode 100644
index 0000000000..dded5776fc
--- /dev/null
+++ b/internal/test/issues/issue-2113/common/spec.yaml
@@ -0,0 +1,22 @@
+openapi: "3.0.4"
+info:
+ title: Common
+ version: "0.0.1"
+paths: {}
+components:
+ schemas:
+ ProblemDetails:
+ type: object
+ properties:
+ title:
+ type: string
+ status:
+ type: integer
+ required: [title, status]
+ responses:
+ StandardError:
+ description: Error response
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ProblemDetails"
diff --git a/internal/test/issues/issue-2113/config.api.yaml b/internal/test/issues/issue-2113/config.api.yaml
new file mode 100644
index 0000000000..754af9fa49
--- /dev/null
+++ b/internal/test/issues/issue-2113/config.api.yaml
@@ -0,0 +1,11 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: api
+generate:
+ chi-server: true
+ strict-server: true
+ models: true
+import-mapping:
+ ./common/spec.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-2113/gen/common
+output: gen/api/api.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue-2113/config.common.yaml b/internal/test/issues/issue-2113/config.common.yaml
new file mode 100644
index 0000000000..ce1b531f80
--- /dev/null
+++ b/internal/test/issues/issue-2113/config.common.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: common
+generate:
+ models: true
+ strict-server: true
+output: gen/common/common.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue-2113/doc.go b/internal/test/issues/issue-2113/doc.go
new file mode 100644
index 0000000000..89ddb3d195
--- /dev/null
+++ b/internal/test/issues/issue-2113/doc.go
@@ -0,0 +1,4 @@
+package issue2113
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.common.yaml common/spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.api.yaml spec.yaml
diff --git a/internal/test/issues/issue-2113/gen/api/api.gen.go b/internal/test/issues/issue-2113/gen/api/api.gen.go
new file mode 100644
index 0000000000..b8a5c4a533
--- /dev/null
+++ b/internal/test/issues/issue-2113/gen/api/api.gen.go
@@ -0,0 +1,288 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ "github.com/go-chi/chi/v5"
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-2113/gen/common"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /things)
+ ListThings(w http.ResponseWriter, r *http.Request)
+}
+
+// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
+
+type Unimplemented struct{}
+
+// (GET /things)
+func (_ Unimplemented) ListThings(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// ListThings operation middleware
+func (siw *ServerInterfaceWrapper) ListThings(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.ListThings(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{})
+}
+
+type ChiServerOptions struct {
+ BaseURL string
+ BaseRouter chi.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = chi.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/things", wrapper.ListThings)
+ })
+
+ return r
+}
+
+type ListThingsRequestObject struct {
+}
+
+type ListThingsResponseObject interface {
+ VisitListThingsResponse(w http.ResponseWriter) error
+}
+
+type ListThings200JSONResponse []string
+
+func (response ListThings200JSONResponse) VisitListThingsResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type ListThings400JSONResponse struct {
+ externalRef0.StandardErrorJSONResponse
+}
+
+func (response ListThings400JSONResponse) VisitListThingsResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(400)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type ListThingsdefaultJSONResponse struct {
+ Body externalRef0.ProblemDetails
+ StatusCode int
+}
+
+func (response ListThingsdefaultJSONResponse) VisitListThingsResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(response.StatusCode)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /things)
+ ListThings(ctx context.Context, request ListThingsRequestObject) (ListThingsResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// ListThings operation middleware
+func (sh *strictHandler) ListThings(w http.ResponseWriter, r *http.Request) {
+ var request ListThingsRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.ListThings(ctx, request.(ListThingsRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "ListThings")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(ListThingsResponseObject); ok {
+ if err := validResponse.VisitListThingsResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/internal/test/issues/issue-2113/gen/common/common.gen.go b/internal/test/issues/issue-2113/gen/common/common.gen.go
new file mode 100644
index 0000000000..6a6bc94a1c
--- /dev/null
+++ b/internal/test/issues/issue-2113/gen/common/common.gen.go
@@ -0,0 +1,15 @@
+// Package common provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package common
+
+// ProblemDetails defines model for ProblemDetails.
+type ProblemDetails struct {
+ Status int `json:"status"`
+ Title string `json:"title"`
+}
+
+// StandardError defines model for StandardError.
+type StandardError = ProblemDetails
+
+type StandardErrorJSONResponse ProblemDetails
diff --git a/internal/test/issues/issue-2113/issue_test.go b/internal/test/issues/issue-2113/issue_test.go
new file mode 100644
index 0000000000..5d5dbbe48c
--- /dev/null
+++ b/internal/test/issues/issue-2113/issue_test.go
@@ -0,0 +1,22 @@
+package issue2113
+
+import (
+ "testing"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-2113/gen/api"
+ "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-2113/gen/common"
+)
+
+// TestExternalRefInResponse verifies that a $ref to an external
+// components/responses object correctly qualifies the schema type
+// with the external package import. See
+// https://github.com/oapi-codegen/oapi-codegen/issues/2113
+func TestExternalRefInResponse(t *testing.T) {
+ // This will fail to compile if the generated code uses
+ // ProblemDetails instead of common.ProblemDetails (via the
+ // externalRef alias) in the default response type.
+ _ = api.ListThingsdefaultJSONResponse{
+ Body: common.ProblemDetails{Title: "err", Status: 500},
+ StatusCode: 500,
+ }
+}
diff --git a/internal/test/issues/issue-2113/spec.yaml b/internal/test/issues/issue-2113/spec.yaml
new file mode 100644
index 0000000000..9f4f50d95d
--- /dev/null
+++ b/internal/test/issues/issue-2113/spec.yaml
@@ -0,0 +1,21 @@
+openapi: "3.0.4"
+info:
+ title: API
+ version: "0.0.1"
+paths:
+ /things:
+ get:
+ operationId: listThings
+ responses:
+ "200":
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: array
+ items:
+ type: string
+ "400":
+ $ref: "./common/spec.yaml#/components/responses/StandardError"
+ default:
+ $ref: "./common/spec.yaml#/components/responses/StandardError"
diff --git a/internal/test/issues/issue-2183/communication_test.go b/internal/test/issues/issue-2183/communication_test.go
new file mode 100644
index 0000000000..68c872eca3
--- /dev/null
+++ b/internal/test/issues/issue-2183/communication_test.go
@@ -0,0 +1,116 @@
+package issue2183
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+func TestQueryCommunication(t *testing.T) {
+
+ type ParamDefinition struct {
+ style string
+ explode bool
+ paramName string
+ value any
+ }
+
+ testCases := []struct {
+ Name string
+ // Params defines the query parameters to serialize and deserialize.
+ Params []ParamDefinition
+ // SpecQuery is the expected raw query string per the OpenAPI spec.
+ SpecQuery string
+ }{
+ {
+ Name: "explode=false",
+ Params: []ParamDefinition{{
+ style: "form",
+ explode: false,
+ paramName: "color",
+ value: []string{"blue", "black", "brown"},
+ }},
+ // https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#style-examples
+ SpecQuery: "color=blue,black,brown",
+ },
+ {
+ Name: "explode=false;commas",
+ Params: []ParamDefinition{{
+ style: "form",
+ explode: false,
+ paramName: "search_term",
+ value: []string{"a", "b", "c,d"},
+ }},
+ SpecQuery: "search_term=a,b,c%2Cd",
+ },
+ {
+ Name: "explode=true",
+ Params: []ParamDefinition{{
+ style: "form",
+ explode: true,
+ paramName: "color",
+ value: []string{"blue", "black", "brown"},
+ }},
+ SpecQuery: "color=blue&color=black&color=brown",
+ },
+ {
+ Name: "multiple params",
+ Params: []ParamDefinition{
+ {
+ style: "form",
+ explode: false,
+ paramName: "color",
+ value: []string{"blue", "black"},
+ },
+ {
+ style: "form",
+ explode: false,
+ paramName: "size",
+ value: []string{"s", "m", "l"},
+ },
+ },
+ SpecQuery: "color=blue,black&size=s,m,l",
+ },
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.Name, func(t *testing.T) {
+
+ // rawQueryFragments collects pre-encoded query fragments from
+ // styled parameters, matching the generated client pattern.
+ var rawQueryFragments []string
+
+ for _, param := range tc.Params {
+
+ // following code equivalent to generated client (after fix)
+ queryFrag, err := runtime.StyleParamWithOptions(param.style, param.explode, param.paramName, param.value, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery})
+ if err != nil {
+ t.Fatal(err)
+ }
+ rawQueryFragments = append(rawQueryFragments, queryFrag)
+ }
+
+ rawQuery := strings.Join(rawQueryFragments, "&")
+ t.Logf("client query: %s", rawQuery)
+ if tc.SpecQuery != "" && rawQuery != tc.SpecQuery {
+ t.Errorf("spec query: expected %q, got %q", tc.SpecQuery, rawQuery)
+ }
+
+ // following code equivalent to generated server
+ for _, param := range tc.Params {
+
+ dest := reflect.New(reflect.TypeOf(param.value))
+ err := runtime.BindRawQueryParameter(param.style, param.explode, true, param.paramName, rawQuery, dest.Interface())
+ if err != nil {
+ t.Error(err)
+ } else if !reflect.DeepEqual(dest.Elem().Interface(), param.value) {
+ t.Errorf("expecting %v, got %v", param.value, dest.Elem().Interface())
+ }
+
+ }
+
+ })
+ }
+}
diff --git a/internal/test/issues/issue-2185/config.yaml b/internal/test/issues/issue-2185/config.yaml
new file mode 100644
index 0000000000..71a7ba132e
--- /dev/null
+++ b/internal/test/issues/issue-2185/config.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue2185
+output: issue2185.gen.go
+generate:
+ models: true
+output-options:
+ skip-prune: true
+ nullable-type: true
diff --git a/internal/test/issues/issue-2185/generate.go b/internal/test/issues/issue-2185/generate.go
new file mode 100644
index 0000000000..9f5224eaeb
--- /dev/null
+++ b/internal/test/issues/issue-2185/generate.go
@@ -0,0 +1,3 @@
+package issue2185
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-2185/issue2185.gen.go b/internal/test/issues/issue-2185/issue2185.gen.go
new file mode 100644
index 0000000000..6474c9c4d0
--- /dev/null
+++ b/internal/test/issues/issue-2185/issue2185.gen.go
@@ -0,0 +1,13 @@
+// Package issue2185 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue2185
+
+import (
+ "github.com/oapi-codegen/nullable"
+)
+
+// Container defines model for Container.
+type Container struct {
+ MayBeNull []nullable.Nullable[string] `json:"may-be-null"`
+}
diff --git a/internal/test/issues/issue-2185/issue2185_test.go b/internal/test/issues/issue-2185/issue2185_test.go
new file mode 100644
index 0000000000..cc98e2b4d3
--- /dev/null
+++ b/internal/test/issues/issue-2185/issue2185_test.go
@@ -0,0 +1,19 @@
+package issue2185
+
+import (
+ "testing"
+
+ "github.com/oapi-codegen/nullable"
+ "github.com/stretchr/testify/require"
+)
+
+func TestContainer_UsesNullableType(t *testing.T) {
+ c := Container{
+ MayBeNull: []nullable.Nullable[string]{
+ nullable.NewNullNullable[string](),
+ },
+ }
+
+ require.Len(t, c.MayBeNull, 1)
+ require.True(t, c.MayBeNull[0].IsNull())
+}
diff --git a/internal/test/issues/issue-2185/spec.yaml b/internal/test/issues/issue-2185/spec.yaml
new file mode 100644
index 0000000000..814048bc8f
--- /dev/null
+++ b/internal/test/issues/issue-2185/spec.yaml
@@ -0,0 +1,15 @@
+openapi: "3.0.3"
+info:
+ title: test
+ version: 1.0.0
+components:
+ schemas:
+ Container:
+ required:
+ - "may-be-null"
+ properties:
+ "may-be-null":
+ type: array
+ items:
+ type: string
+ nullable: true
diff --git a/internal/test/issues/issue-2190/config.yaml b/internal/test/issues/issue-2190/config.yaml
new file mode 100644
index 0000000000..da89951cdc
--- /dev/null
+++ b/internal/test/issues/issue-2190/config.yaml
@@ -0,0 +1,9 @@
+package: issue2190
+output: issue2190.gen.go
+generate:
+ std-http-server: true
+ strict-server: true
+ models: true
+ client: true
+output-options:
+ nullable-type: true
diff --git a/internal/test/issues/issue-2190/generate.go b/internal/test/issues/issue-2190/generate.go
new file mode 100644
index 0000000000..74169c3fe3
--- /dev/null
+++ b/internal/test/issues/issue-2190/generate.go
@@ -0,0 +1,3 @@
+package issue2190
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-2190/issue2190.gen.go b/internal/test/issues/issue-2190/issue2190.gen.go
new file mode 100644
index 0000000000..cddf869b5d
--- /dev/null
+++ b/internal/test/issues/issue-2190/issue2190.gen.go
@@ -0,0 +1,509 @@
+//go:build go1.22
+
+// Package issue2190 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue2190
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+// Success defines model for Success.
+type Success = string
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetTest request
+ GetTest(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetTest(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetTestRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetTestRequest generates requests for GetTest
+func NewGetTestRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/v1/test")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetTestWithResponse request
+ GetTestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetTestResponse, error)
+}
+
+type GetTestResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Success
+}
+
+// GetJSON200 returns JSON200
+func (r GetTestResponse) GetJSON200() *Success {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetTestResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetTestResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetTestResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetTestResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetTestWithResponse request returning *GetTestResponse
+func (c *ClientWithResponses) GetTestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetTestResponse, error) {
+ rsp, err := c.GetTest(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetTestResponse(rsp)
+}
+
+// ParseGetTestResponse parses an HTTP response from a GetTestWithResponse call
+func ParseGetTestResponse(rsp *http.Response) (*GetTestResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetTestResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Success
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /v1/test)
+ GetTest(w http.ResponseWriter, r *http.Request)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetTest operation middleware
+func (siw *ServerInterfaceWrapper) GetTest(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetTest(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{})
+}
+
+// ServeMux is an abstraction of [http.ServeMux].
+type ServeMux interface {
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+ http.Handler
+}
+
+type StdHTTPServerOptions struct {
+ BaseURL string
+ BaseRouter ServeMux
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/v1/test", wrapper.GetTest)
+
+ return m
+}
+
+type SuccessJSONResponse string
+
+type UnauthorizedTextResponse string
+
+type GetTestRequestObject struct {
+}
+
+type GetTestResponseObject interface {
+ VisitGetTestResponse(w http.ResponseWriter) error
+}
+
+type GetTest200JSONResponse struct{ SuccessJSONResponse }
+
+func (response GetTest200JSONResponse) VisitGetTestResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type GetTest401TextResponse UnauthorizedTextResponse
+
+func (response GetTest401TextResponse) VisitGetTestResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "text/plain")
+ w.WriteHeader(401)
+
+ _, err := w.Write([]byte(response))
+ return err
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /v1/test)
+ GetTest(ctx context.Context, request GetTestRequestObject) (GetTestResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// GetTest operation middleware
+func (sh *strictHandler) GetTest(w http.ResponseWriter, r *http.Request) {
+ var request GetTestRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetTest(ctx, request.(GetTestRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetTest")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetTestResponseObject); ok {
+ if err := validResponse.VisitGetTestResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/internal/test/issues/issue-2190/issue2190_test.go b/internal/test/issues/issue-2190/issue2190_test.go
new file mode 100644
index 0000000000..8dc7a0b075
--- /dev/null
+++ b/internal/test/issues/issue-2190/issue2190_test.go
@@ -0,0 +1,37 @@
+package issue2190
+
+import (
+ "net/http/httptest"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+// TestGetTest401TextResponse verifies that the generated VisitGetTestResponse
+// method on GetTest401TextResponse produces a valid text/plain 401 response.
+// This is a regression test for https://github.com/oapi-codegen/oapi-codegen/issues/2190
+// where the generated code tried to do []byte(response) on a struct type,
+// which does not compile.
+func TestGetTest401TextResponse(t *testing.T) {
+ resp := GetTest401TextResponse("Unauthorized")
+ w := httptest.NewRecorder()
+
+ err := resp.VisitGetTestResponse(w)
+ require.NoError(t, err)
+ assert.Equal(t, 401, w.Code)
+ assert.Equal(t, "text/plain", w.Header().Get("Content-Type"))
+ assert.Equal(t, "Unauthorized", w.Body.String())
+}
+
+// TestGetTest200JSONResponse verifies that the 200 JSON response path also works.
+func TestGetTest200JSONResponse(t *testing.T) {
+ resp := GetTest200JSONResponse{SuccessJSONResponse("hello")}
+ w := httptest.NewRecorder()
+
+ err := resp.VisitGetTestResponse(w)
+ require.NoError(t, err)
+ assert.Equal(t, 200, w.Code)
+ assert.Equal(t, "application/json", w.Header().Get("Content-Type"))
+ assert.Contains(t, w.Body.String(), "hello")
+}
diff --git a/internal/test/issues/issue-2190/spec.yaml b/internal/test/issues/issue-2190/spec.yaml
new file mode 100644
index 0000000000..2844100e3d
--- /dev/null
+++ b/internal/test/issues/issue-2190/spec.yaml
@@ -0,0 +1,30 @@
+openapi: 3.0.3
+info:
+ title: test
+ version: 1.0.0
+servers:
+ - url: https://te.st
+paths:
+ /v1/test:
+ get:
+ operationId: GetTest
+ responses:
+ "200":
+ $ref: "#/components/responses/Success"
+ "401":
+ $ref: "#/components/responses/Unauthorized"
+components:
+ responses:
+ Success:
+ description: Success
+ content:
+ application/json:
+ schema:
+ type: string
+ Unauthorized:
+ description: Unauthorized
+ content:
+ text/plain:
+ schema:
+ type: string
+ example: "Unauthorized"
diff --git a/internal/test/issues/issue-2232/config.yaml b/internal/test/issues/issue-2232/config.yaml
new file mode 100644
index 0000000000..6368de1d4d
--- /dev/null
+++ b/internal/test/issues/issue-2232/config.yaml
@@ -0,0 +1,5 @@
+package: issue2232
+output: issue2232.gen.go
+generate:
+ std-http-server: true
+ models: true
diff --git a/internal/test/issues/issue-2232/generate.go b/internal/test/issues/issue-2232/generate.go
new file mode 100644
index 0000000000..f6767c10e1
--- /dev/null
+++ b/internal/test/issues/issue-2232/generate.go
@@ -0,0 +1,3 @@
+package issue2232
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-2232/issue2232.gen.go b/internal/test/issues/issue-2232/issue2232.gen.go
new file mode 100644
index 0000000000..a63393b342
--- /dev/null
+++ b/internal/test/issues/issue-2232/issue2232.gen.go
@@ -0,0 +1,263 @@
+//go:build go1.22
+
+// Package issue2232 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue2232
+
+import (
+ "errors"
+ "fmt"
+ "net/http"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// Defines values for GetEndpointParamsEnvParamLevel.
+const (
+ GetEndpointParamsEnvParamLevelDev GetEndpointParamsEnvParamLevel = "dev"
+ GetEndpointParamsEnvParamLevelLive GetEndpointParamsEnvParamLevel = "live"
+)
+
+// Valid indicates whether the value is a known member of the GetEndpointParamsEnvParamLevel enum.
+func (e GetEndpointParamsEnvParamLevel) Valid() bool {
+ switch e {
+ case GetEndpointParamsEnvParamLevelDev:
+ return true
+ case GetEndpointParamsEnvParamLevelLive:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for GetEndpointParamsEnvSchemaLevel.
+const (
+ GetEndpointParamsEnvSchemaLevelDev GetEndpointParamsEnvSchemaLevel = "dev"
+ GetEndpointParamsEnvSchemaLevelLive GetEndpointParamsEnvSchemaLevel = "live"
+)
+
+// Valid indicates whether the value is a known member of the GetEndpointParamsEnvSchemaLevel enum.
+func (e GetEndpointParamsEnvSchemaLevel) Valid() bool {
+ switch e {
+ case GetEndpointParamsEnvSchemaLevelDev:
+ return true
+ case GetEndpointParamsEnvSchemaLevelLive:
+ return true
+ default:
+ return false
+ }
+}
+
+// GetEndpointParams defines parameters for GetEndpoint.
+type GetEndpointParams struct {
+ EnvParamLevel GetEndpointParamsEnvParamLevel `form:"env_param_level" json:"env_param_level" validate:"required,oneof=dev live"`
+ EnvSchemaLevel GetEndpointParamsEnvSchemaLevel `form:"env_schema_level" json:"env_schema_level" validate:"required,oneof=dev live"`
+ Limit *int `form:"limit,omitempty" json:"limit,omitempty" validate:"min=0,max=100"`
+}
+
+// GetEndpointParamsEnvParamLevel defines parameters for GetEndpoint.
+type GetEndpointParamsEnvParamLevel string
+
+// GetEndpointParamsEnvSchemaLevel defines parameters for GetEndpoint.
+type GetEndpointParamsEnvSchemaLevel string
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /v1/endpoint)
+ GetEndpoint(w http.ResponseWriter, r *http.Request, params GetEndpointParams)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetEndpoint operation middleware
+func (siw *ServerInterfaceWrapper) GetEndpoint(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetEndpointParams
+
+ // ------------- Required query parameter "env_param_level" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, true, "env_param_level", r.URL.Query(), ¶ms.EnvParamLevel, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "env_param_level"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "env_param_level", Err: err})
+ }
+ return
+ }
+
+ // ------------- Required query parameter "env_schema_level" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, true, "env_schema_level", r.URL.Query(), ¶ms.EnvSchemaLevel, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "env_schema_level"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "env_schema_level", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "limit" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "limit", r.URL.Query(), ¶ms.Limit, runtime.BindQueryParameterOptions{Type: "integer", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "limit"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "limit", Err: err})
+ }
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetEndpoint(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{})
+}
+
+// ServeMux is an abstraction of [http.ServeMux].
+type ServeMux interface {
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+ http.Handler
+}
+
+type StdHTTPServerOptions struct {
+ BaseURL string
+ BaseRouter ServeMux
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/v1/endpoint", wrapper.GetEndpoint)
+
+ return m
+}
diff --git a/internal/test/issues/issue-2232/issue2232_test.go b/internal/test/issues/issue-2232/issue2232_test.go
new file mode 100644
index 0000000000..a8ae51836e
--- /dev/null
+++ b/internal/test/issues/issue-2232/issue2232_test.go
@@ -0,0 +1,41 @@
+package issue2232
+
+import (
+ "reflect"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+// TestExtraTagsOnQueryParams verifies that x-oapi-codegen-extra-tags is applied
+// to query parameter struct fields regardless of whether the extension is placed
+// at the parameter level or at the schema level within the parameter.
+// This is a regression test for https://github.com/oapi-codegen/oapi-codegen/issues/2232
+func TestExtraTagsOnQueryParams(t *testing.T) {
+ paramType := reflect.TypeOf(GetEndpointParams{})
+
+ t.Run("parameter-level extension", func(t *testing.T) {
+ field, ok := paramType.FieldByName("EnvParamLevel")
+ require.True(t, ok, "field EnvParamLevel should exist")
+
+ assert.Equal(t, `required,oneof=dev live`, field.Tag.Get("validate"),
+ "x-oapi-codegen-extra-tags at parameter level should produce validate tag")
+ })
+
+ t.Run("schema-level extension", func(t *testing.T) {
+ field, ok := paramType.FieldByName("EnvSchemaLevel")
+ require.True(t, ok, "field EnvSchemaLevel should exist")
+
+ assert.Equal(t, `required,oneof=dev live`, field.Tag.Get("validate"),
+ "x-oapi-codegen-extra-tags at schema level within a parameter should produce validate tag")
+ })
+
+ t.Run("schema-level extension on optional param", func(t *testing.T) {
+ field, ok := paramType.FieldByName("Limit")
+ require.True(t, ok, "field Limit should exist")
+
+ assert.Equal(t, `min=0,max=100`, field.Tag.Get("validate"),
+ "x-oapi-codegen-extra-tags at schema level within an optional parameter should produce validate tag")
+ })
+}
diff --git a/internal/test/issues/issue-2232/spec.yaml b/internal/test/issues/issue-2232/spec.yaml
new file mode 100644
index 0000000000..0fea5cba83
--- /dev/null
+++ b/internal/test/issues/issue-2232/spec.yaml
@@ -0,0 +1,46 @@
+openapi: "3.0.3"
+info:
+ title: test
+ version: 1.0.0
+paths:
+ /v1/endpoint:
+ get:
+ operationId: GetEndpoint
+ parameters:
+ - name: env_param_level
+ in: query
+ required: true
+ schema:
+ type: string
+ enum:
+ - dev
+ - live
+ x-oapi-codegen-extra-tags:
+ validate: "required,oneof=dev live"
+ - name: env_schema_level
+ in: query
+ required: true
+ schema:
+ type: string
+ enum:
+ - dev
+ - live
+ x-oapi-codegen-extra-tags:
+ validate: "required,oneof=dev live"
+ - name: limit
+ in: query
+ required: false
+ schema:
+ type: integer
+ x-oapi-codegen-extra-tags:
+ validate: "min=0,max=100"
+ responses:
+ "200":
+ description: Success
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ message:
+ type: string
diff --git a/internal/test/issues/issue-2238/config.yaml b/internal/test/issues/issue-2238/config.yaml
new file mode 100644
index 0000000000..cbb78b8d30
--- /dev/null
+++ b/internal/test/issues/issue-2238/config.yaml
@@ -0,0 +1,7 @@
+package: issue2238
+generate:
+ models: true
+ client: true
+output-options:
+ prefer-skip-optional-pointer: true
+output: issue2238.gen.go
diff --git a/internal/test/issues/issue-2238/generate.go b/internal/test/issues/issue-2238/generate.go
new file mode 100644
index 0000000000..5c10773236
--- /dev/null
+++ b/internal/test/issues/issue-2238/generate.go
@@ -0,0 +1,3 @@
+package issue2238
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml openapi.yaml
diff --git a/internal/test/issues/issue-2238/issue2238.gen.go b/internal/test/issues/issue-2238/issue2238.gen.go
new file mode 100644
index 0000000000..11d329f7d4
--- /dev/null
+++ b/internal/test/issues/issue-2238/issue2238.gen.go
@@ -0,0 +1,275 @@
+// Package issue2238 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue2238
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// GetTestParams defines parameters for GetTest.
+type GetTestParams struct {
+ XTags []string `json:"X-Tags,omitempty"`
+ Tags []string `form:"tags,omitempty" json:"tags,omitempty"`
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetTest request
+ GetTest(ctx context.Context, params *GetTestParams, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetTest(ctx context.Context, params *GetTestParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetTestRequest(c.Server, params)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetTestRequest generates requests for GetTest
+func NewGetTestRequest(server string, params *GetTestParams) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/test")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ if params != nil {
+
+ if params.XTags != nil {
+ var headerParam0 string
+
+ headerParam0, err = runtime.StyleParamWithOptions("simple", false, "X-Tags", params.XTags, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "array", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Set("X-Tags", headerParam0)
+ }
+
+ }
+
+ if params != nil {
+
+ if params.Tags != nil {
+ var cookieParam0 string
+
+ cookieParam0, err = runtime.StyleParamWithOptions("simple", true, "tags", params.Tags, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "array", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ cookie0 := &http.Cookie{
+ Name: "tags",
+ Value: cookieParam0,
+ }
+ req.AddCookie(cookie0)
+ }
+ }
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetTestWithResponse request
+ GetTestWithResponse(ctx context.Context, params *GetTestParams, reqEditors ...RequestEditorFn) (*GetTestResponse, error)
+}
+
+type GetTestResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetTestResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetTestResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetTestResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetTestResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetTestWithResponse request returning *GetTestResponse
+func (c *ClientWithResponses) GetTestWithResponse(ctx context.Context, params *GetTestParams, reqEditors ...RequestEditorFn) (*GetTestResponse, error) {
+ rsp, err := c.GetTest(ctx, params, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetTestResponse(rsp)
+}
+
+// ParseGetTestResponse parses an HTTP response from a GetTestWithResponse call
+func ParseGetTestResponse(rsp *http.Response) (*GetTestResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetTestResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
diff --git a/internal/test/issues/issue-2238/issue2238_test.go b/internal/test/issues/issue-2238/issue2238_test.go
new file mode 100644
index 0000000000..8c399efa52
--- /dev/null
+++ b/internal/test/issues/issue-2238/issue2238_test.go
@@ -0,0 +1,56 @@
+package issue2238
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestNewGetTestRequest(t *testing.T) {
+ t.Run("nil header array param is not sent", func(t *testing.T) {
+ params := GetTestParams{
+ XTags: nil,
+ }
+
+ req, err := NewGetTestRequest("https://localhost", ¶ms)
+ require.NoError(t, err)
+
+ assert.Empty(t, req.Header.Values("X-Tags"))
+ })
+
+ t.Run("non-nil header array param is sent", func(t *testing.T) {
+ params := GetTestParams{
+ XTags: []string{"a", "b"},
+ }
+
+ req, err := NewGetTestRequest("https://localhost", ¶ms)
+ require.NoError(t, err)
+
+ assert.NotEmpty(t, req.Header.Values("X-Tags"))
+ })
+
+ t.Run("nil cookie array param is not sent", func(t *testing.T) {
+ params := GetTestParams{
+ Tags: nil,
+ }
+
+ req, err := NewGetTestRequest("https://localhost", ¶ms)
+ require.NoError(t, err)
+
+ assert.Empty(t, req.Cookies())
+ })
+
+ t.Run("non-nil cookie array param is sent", func(t *testing.T) {
+ params := GetTestParams{
+ Tags: []string{"a", "b"},
+ }
+
+ req, err := NewGetTestRequest("https://localhost", ¶ms)
+ require.NoError(t, err)
+
+ cookies := req.Cookies()
+ require.Len(t, cookies, 1)
+ assert.Equal(t, "tags", cookies[0].Name)
+ })
+}
diff --git a/internal/test/issues/issue-2238/openapi.yaml b/internal/test/issues/issue-2238/openapi.yaml
new file mode 100644
index 0000000000..4e026542ac
--- /dev/null
+++ b/internal/test/issues/issue-2238/openapi.yaml
@@ -0,0 +1,22 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Issue 2238
+paths:
+ /test:
+ get:
+ parameters:
+ - name: X-Tags
+ in: header
+ schema:
+ type: array
+ items:
+ type: string
+ required: false
+ - name: tags
+ in: cookie
+ schema:
+ type: array
+ items:
+ type: string
+ required: false
diff --git a/internal/test/issues/issue-2329/config.yaml b/internal/test/issues/issue-2329/config.yaml
new file mode 100644
index 0000000000..8ec05d874a
--- /dev/null
+++ b/internal/test/issues/issue-2329/config.yaml
@@ -0,0 +1,5 @@
+package: issue2329
+generate:
+ models: true
+ client: true
+output: issue2329.gen.go
diff --git a/internal/test/issues/issue-2329/generate.go b/internal/test/issues/issue-2329/generate.go
new file mode 100644
index 0000000000..0b97157539
--- /dev/null
+++ b/internal/test/issues/issue-2329/generate.go
@@ -0,0 +1,3 @@
+package issue2329
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml openapi.yaml
diff --git a/internal/test/issues/issue-2329/issue2329.gen.go b/internal/test/issues/issue-2329/issue2329.gen.go
new file mode 100644
index 0000000000..0248c2fd11
--- /dev/null
+++ b/internal/test/issues/issue-2329/issue2329.gen.go
@@ -0,0 +1,518 @@
+// Package issue2329 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue2329
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// Thing defines model for Thing.
+type Thing struct {
+ Labels []string `json:"labels,omitempty"`
+ Tags map[string]string `json:"tags,omitempty"`
+ AdditionalProperties map[string]string `json:"-"`
+}
+
+// ListThingsParams defines parameters for ListThings.
+type ListThingsParams struct {
+ Tags map[string]string `json:"tags,omitempty"`
+ Labels []string `form:"labels,omitempty" json:"labels,omitempty"`
+}
+
+// CreateThingJSONRequestBody defines body for CreateThing for application/json ContentType.
+type CreateThingJSONRequestBody = Thing
+
+// Getter for additional properties for Thing. Returns the specified
+// element and whether it was found
+func (a Thing) Get(fieldName string) (value string, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Thing
+func (a *Thing) Set(fieldName string, value string) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]string)
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Thing to handle AdditionalProperties
+func (a *Thing) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["labels"]; found {
+ err = json.Unmarshal(raw, &a.Labels)
+ if err != nil {
+ return fmt.Errorf("error reading 'labels': %w", err)
+ }
+ delete(object, "labels")
+ }
+
+ if raw, found := object["tags"]; found {
+ err = json.Unmarshal(raw, &a.Tags)
+ if err != nil {
+ return fmt.Errorf("error reading 'tags': %w", err)
+ }
+ delete(object, "tags")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]string)
+ for fieldName, fieldBuf := range object {
+ var fieldVal string
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Thing to handle AdditionalProperties
+func (a Thing) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Labels != nil {
+ object["labels"], err = json.Marshal(a.Labels)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'labels': %w", err)
+ }
+ }
+
+ if a.Tags != nil {
+ object["tags"], err = json.Marshal(a.Tags)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'tags': %w", err)
+ }
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // ListThings request
+ ListThings(ctx context.Context, params *ListThingsParams, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // CreateThingWithBody request with any body
+ CreateThingWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ CreateThing(ctx context.Context, body CreateThingJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) ListThings(ctx context.Context, params *ListThingsParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewListThingsRequest(c.Server, params)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) CreateThingWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewCreateThingRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) CreateThing(ctx context.Context, body CreateThingJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewCreateThingRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewListThingsRequest generates requests for ListThings
+func NewListThingsRequest(server string, params *ListThingsParams) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/things")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ if params != nil {
+ // queryValues collects non-styled parameters (passthrough, JSON)
+ // that are safe to round-trip through url.Values.Encode().
+ queryValues := queryURL.Query()
+ // rawQueryFragments collects pre-encoded query fragments from
+ // styled parameters, preserving literal commas as delimiters
+ // per the OpenAPI spec (e.g. "color=blue,black,brown").
+ var rawQueryFragments []string
+
+ if params.Tags != nil {
+
+ if queryFrag, err := runtime.StyleParamWithOptions("deepObject", true, "tags", params.Tags, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "object", Format: ""}); err != nil {
+ return nil, err
+ } else {
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
+ }
+ }
+
+ }
+
+ if params.Labels != nil {
+
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "labels", params.Labels, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "array", Format: ""}); err != nil {
+ return nil, err
+ } else {
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
+ }
+ }
+
+ }
+
+ if encoded := queryValues.Encode(); encoded != "" {
+ rawQueryFragments = append(rawQueryFragments, encoded)
+ }
+ queryURL.RawQuery = strings.Join(rawQueryFragments, "&")
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewCreateThingRequest calls the generic CreateThing builder with application/json body
+func NewCreateThingRequest(server string, body CreateThingJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewCreateThingRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewCreateThingRequestWithBody generates requests for CreateThing with any type of body
+func NewCreateThingRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/things")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // ListThingsWithResponse request
+ ListThingsWithResponse(ctx context.Context, params *ListThingsParams, reqEditors ...RequestEditorFn) (*ListThingsResponse, error)
+
+ // CreateThingWithBodyWithResponse request with any body
+ CreateThingWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateThingResponse, error)
+
+ CreateThingWithResponse(ctx context.Context, body CreateThingJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateThingResponse, error)
+}
+
+type ListThingsResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r ListThingsResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r ListThingsResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r ListThingsResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r ListThingsResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type CreateThingResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r CreateThingResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r CreateThingResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r CreateThingResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r CreateThingResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// ListThingsWithResponse request returning *ListThingsResponse
+func (c *ClientWithResponses) ListThingsWithResponse(ctx context.Context, params *ListThingsParams, reqEditors ...RequestEditorFn) (*ListThingsResponse, error) {
+ rsp, err := c.ListThings(ctx, params, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseListThingsResponse(rsp)
+}
+
+// CreateThingWithBodyWithResponse request with arbitrary body returning *CreateThingResponse
+func (c *ClientWithResponses) CreateThingWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateThingResponse, error) {
+ rsp, err := c.CreateThingWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseCreateThingResponse(rsp)
+}
+
+func (c *ClientWithResponses) CreateThingWithResponse(ctx context.Context, body CreateThingJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateThingResponse, error) {
+ rsp, err := c.CreateThing(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseCreateThingResponse(rsp)
+}
+
+// ParseListThingsResponse parses an HTTP response from a ListThingsWithResponse call
+func ParseListThingsResponse(rsp *http.Response) (*ListThingsResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &ListThingsResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
+// ParseCreateThingResponse parses an HTTP response from a CreateThingWithResponse call
+func ParseCreateThingResponse(rsp *http.Response) (*CreateThingResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &CreateThingResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
diff --git a/internal/test/issues/issue-2329/issue2329_test.go b/internal/test/issues/issue-2329/issue2329_test.go
new file mode 100644
index 0000000000..cb534dc05e
--- /dev/null
+++ b/internal/test/issues/issue-2329/issue2329_test.go
@@ -0,0 +1,80 @@
+package issue2329
+
+import (
+ "encoding/json"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+// TestNewListThingsRequest verifies that map- and slice-typed optional query
+// parameters marked with `x-go-type-skip-optional-pointer: true` produce
+// client request code that compiles. Before the fix, the client template
+// emitted `*params.Tags` / `*params.Labels`, which does not compile because
+// the fields are declared as `map[string]string` and `[]string`.
+func TestNewListThingsRequest(t *testing.T) {
+ t.Run("nil map and slice query params are not sent", func(t *testing.T) {
+ params := ListThingsParams{}
+
+ req, err := NewListThingsRequest("https://localhost", ¶ms)
+ require.NoError(t, err)
+
+ assert.Empty(t, req.URL.RawQuery)
+ })
+
+ t.Run("non-nil map query param (deepObject) is serialized", func(t *testing.T) {
+ params := ListThingsParams{
+ Tags: map[string]string{"color": "blue"},
+ }
+
+ req, err := NewListThingsRequest("https://localhost", ¶ms)
+ require.NoError(t, err)
+
+ assert.Contains(t, req.URL.RawQuery, "tags[color]=blue")
+ })
+
+ t.Run("non-nil slice query param (form, explode) is serialized", func(t *testing.T) {
+ params := ListThingsParams{
+ Labels: []string{"a", "b"},
+ }
+
+ req, err := NewListThingsRequest("https://localhost", ¶ms)
+ require.NoError(t, err)
+
+ assert.Contains(t, req.URL.RawQuery, "labels=a")
+ assert.Contains(t, req.URL.RawQuery, "labels=b")
+ })
+}
+
+// TestThingMarshalJSON verifies the body-schema custom-marshal path. The
+// Thing schema has additionalProperties, so codegen emits a custom
+// MarshalJSON that walks named properties one at a time. Map- and
+// slice-typed properties marked with `x-go-type-skip-optional-pointer: true`
+// must both be guarded by a nil-check there — otherwise an unset map
+// property serialises as `"tags":null` while an unset slice property is
+// omitted, producing inconsistent output for the same OpenAPI flag.
+func TestThingMarshalJSON(t *testing.T) {
+ t.Run("zero-value Thing omits both nil map and nil slice properties", func(t *testing.T) {
+ b, err := json.Marshal(Thing{})
+ require.NoError(t, err)
+
+ var got map[string]json.RawMessage
+ require.NoError(t, json.Unmarshal(b, &got))
+
+ assert.NotContains(t, got, "tags", "nil map property must be omitted, not serialised as null")
+ assert.NotContains(t, got, "labels", "nil slice property must be omitted, not serialised as null")
+ })
+
+ t.Run("populated Thing serialises both map and slice properties", func(t *testing.T) {
+ thing := Thing{
+ Tags: map[string]string{"color": "blue"},
+ Labels: []string{"a", "b"},
+ }
+ b, err := json.Marshal(thing)
+ require.NoError(t, err)
+
+ assert.Contains(t, string(b), `"tags":{"color":"blue"}`)
+ assert.Contains(t, string(b), `"labels":["a","b"]`)
+ })
+}
diff --git a/internal/test/issues/issue-2329/openapi.yaml b/internal/test/issues/issue-2329/openapi.yaml
new file mode 100644
index 0000000000..43c53b5775
--- /dev/null
+++ b/internal/test/issues/issue-2329/openapi.yaml
@@ -0,0 +1,54 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Issue 2329
+paths:
+ /things:
+ get:
+ operationId: listThings
+ parameters:
+ - name: tags
+ in: query
+ style: deepObject
+ x-go-type-skip-optional-pointer: true
+ schema:
+ type: object
+ additionalProperties:
+ type: string
+ - name: labels
+ in: query
+ x-go-type-skip-optional-pointer: true
+ schema:
+ type: array
+ items:
+ type: string
+ responses:
+ "200":
+ description: OK
+ post:
+ operationId: createThing
+ requestBody:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Thing'
+ responses:
+ "200":
+ description: OK
+components:
+ schemas:
+ Thing:
+ type: object
+ additionalProperties:
+ type: string
+ properties:
+ tags:
+ x-go-type-skip-optional-pointer: true
+ type: object
+ additionalProperties:
+ type: string
+ labels:
+ x-go-type-skip-optional-pointer: true
+ type: array
+ items:
+ type: string
diff --git a/internal/test/issues/issue-2367/api.gen.go b/internal/test/issues/issue-2367/api.gen.go
new file mode 100644
index 0000000000..1270af2079
--- /dev/null
+++ b/internal/test/issues/issue-2367/api.gen.go
@@ -0,0 +1,174 @@
+// Package issue2367 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue2367
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /hello)
+ GetHello(c *gin.Context)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandler func(*gin.Context, error, int)
+}
+
+type MiddlewareFunc func(c *gin.Context)
+
+// GetHello operation middleware
+func (siw *ServerInterfaceWrapper) GetHello(c *gin.Context) {
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetHello(c)
+}
+
+// GinServerOptions provides options for the Gin server.
+type GinServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ ErrorHandler func(*gin.Context, error, int)
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router gin.IRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, GinServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) {
+ errorHandler := options.ErrorHandler
+ if errorHandler == nil {
+ errorHandler = func(c *gin.Context, err error, statusCode int) {
+ c.JSON(statusCode, gin.H{"msg": err.Error()})
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandler: errorHandler,
+ }
+
+ router.GET(options.BaseURL+"/hello", wrapper.GetHello)
+}
+
+type GetHelloRequestObject struct {
+}
+
+type GetHelloResponseObject interface {
+ VisitGetHelloResponse(w http.ResponseWriter) error
+}
+
+type GetHello200Response struct {
+}
+
+func (response GetHello200Response) VisitGetHelloResponse(w http.ResponseWriter) error {
+ w.WriteHeader(200)
+ return nil
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /hello)
+ GetHello(ctx context.Context, request GetHelloRequestObject) (GetHelloResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx *gin.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictGinServerOptions struct {
+ // RequestErrorHandlerFunc is called when a request cannot be parsed or
+ // decoded. It is invoked for JSON bind failures, form parse/bind errors,
+ // multipart reader errors, media type parse errors, missing multipart
+ // boundaries, and request body read errors. The default returns 400.
+ RequestErrorHandlerFunc func(ctx *gin.Context, err error)
+ // HandlerErrorFunc is called when the application handler (or any
+ // middleware wrapping it) returns a non-nil error. The default returns 500.
+ HandlerErrorFunc func(ctx *gin.Context, err error)
+ // ResponseErrorHandlerFunc is called when the response object fails to
+ // serialize (Visit*Response returns an error) or when the handler returns
+ // an unexpected response type. The default returns 500.
+ ResponseErrorHandlerFunc func(ctx *gin.Context, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictGinServerOptions{
+ RequestErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ },
+ HandlerErrorFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ ResponseErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictGinServerOptions) ServerInterface {
+ if options.RequestErrorHandlerFunc == nil {
+ options.RequestErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.HandlerErrorFunc == nil {
+ options.HandlerErrorFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.ResponseErrorHandlerFunc == nil {
+ options.ResponseErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictGinServerOptions
+}
+
+// GetHello operation middleware
+func (sh *strictHandler) GetHello(ctx *gin.Context) {
+ var request GetHelloRequestObject
+
+ handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.GetHello(ctx, request.(GetHelloRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetHello")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ sh.options.HandlerErrorFunc(ctx, err)
+ } else if validResponse, ok := response.(GetHelloResponseObject); ok {
+ if err := validResponse.VisitGetHelloResponse(ctx.Writer); err != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/internal/test/issues/issue-2367/cfg.yaml b/internal/test/issues/issue-2367/cfg.yaml
new file mode 100644
index 0000000000..cacc01e1ff
--- /dev/null
+++ b/internal/test/issues/issue-2367/cfg.yaml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue2367
+output: api.gen.go
+generate:
+ gin-server: true
+ strict-server: true
+ models: true
diff --git a/internal/test/issues/issue-2367/generate.go b/internal/test/issues/issue-2367/generate.go
new file mode 100644
index 0000000000..407393a8a3
--- /dev/null
+++ b/internal/test/issues/issue-2367/generate.go
@@ -0,0 +1,3 @@
+package issue2367
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=cfg.yaml spec.yaml
diff --git a/internal/test/issues/issue-2367/issue_2367_test.go b/internal/test/issues/issue-2367/issue_2367_test.go
new file mode 100644
index 0000000000..24a1d5843e
--- /dev/null
+++ b/internal/test/issues/issue-2367/issue_2367_test.go
@@ -0,0 +1,23 @@
+package issue2367
+
+import (
+ "testing"
+
+ "github.com/gin-gonic/gin"
+ "github.com/stretchr/testify/assert"
+)
+
+// stubServer satisfies ServerInterface and lets the test prove the generated
+// package compiles end-to-end. The bug in issue 2367 emitted a constant
+// referencing a context-key type that was never declared (because the spec's
+// `security:` named a scheme not present under components/securitySchemes),
+// so the generated file failed to compile. Instantiating the interface here
+// would not be reachable if that regression returned.
+type stubServer struct{}
+
+func (stubServer) GetHello(c *gin.Context) {}
+
+func TestGeneratedServerCompilesWithUndefinedSecurityScheme(t *testing.T) {
+ var iface ServerInterface = stubServer{}
+ assert.NotNil(t, iface)
+}
diff --git a/internal/test/issues/issue-2367/spec.yaml b/internal/test/issues/issue-2367/spec.yaml
new file mode 100644
index 0000000000..6f7253d1a0
--- /dev/null
+++ b/internal/test/issues/issue-2367/spec.yaml
@@ -0,0 +1,13 @@
+openapi: "3.0.0"
+info:
+ title: issue-2367
+ version: 1.0.0
+security:
+ - api_key: []
+paths:
+ /hello:
+ get:
+ operationId: getHello
+ responses:
+ "200":
+ description: ok
diff --git a/internal/test/issues/issue-312/config.yaml b/internal/test/issues/issue-312/config.yaml
index a0db7e9783..39cb190515 100644
--- a/internal/test/issues/issue-312/config.yaml
+++ b/internal/test/issues/issue-312/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: issue312
generate:
echo-server: true
diff --git a/internal/test/issues/issue-312/doc.go b/internal/test/issues/issue-312/doc.go
index 8eb982df90..768a4595b8 100644
--- a/internal/test/issues/issue-312/doc.go
+++ b/internal/test/issues/issue-312/doc.go
@@ -1,3 +1,3 @@
package issue312
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-312/issue.gen.go b/internal/test/issues/issue-312/issue.gen.go
index 4320c8dbb4..25763f9374 100644
--- a/internal/test/issues/issue-312/issue.gen.go
+++ b/internal/test/issues/issue-312/issue.gen.go
@@ -1,11 +1,11 @@
// Package issue312 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package issue312
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -169,7 +169,7 @@ func NewGetPetRequest(server string, petId string) (*http.Request, error) {
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("simple", false, "petId", runtime.ParamLocationPath, petId)
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "petId", petId, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
if err != nil {
return nil, err
}
@@ -189,7 +189,7 @@ func NewGetPetRequest(server string, petId string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -227,7 +227,7 @@ func NewValidatePetsRequestWithBody(server string, contentType string, body io.R
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -295,6 +295,16 @@ type GetPetResponse struct {
JSON200 *Pet
}
+// GetJSON200 returns JSON200
+func (r GetPetResponse) GetJSON200() *Pet {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetPetResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetPetResponse) Status() string {
if r.HTTPResponse != nil {
@@ -311,6 +321,14 @@ func (r GetPetResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetPetResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type ValidatePetsResponse struct {
Body []byte
HTTPResponse *http.Response
@@ -318,6 +336,21 @@ type ValidatePetsResponse struct {
JSONDefault *Error
}
+// GetJSON200 returns JSON200
+func (r ValidatePetsResponse) GetJSON200() *[]Pet {
+ return r.JSON200
+}
+
+// GetJSONDefault returns JSONDefault
+func (r ValidatePetsResponse) GetJSONDefault() *Error {
+ return r.JSONDefault
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r ValidatePetsResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r ValidatePetsResponse) Status() string {
if r.HTTPResponse != nil {
@@ -334,6 +367,14 @@ func (r ValidatePetsResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r ValidatePetsResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// GetPetWithResponse request returning *GetPetResponse
func (c *ClientWithResponses) GetPetWithResponse(ctx context.Context, petId string, reqEditors ...RequestEditorFn) (*GetPetResponse, error) {
rsp, err := c.GetPet(ctx, petId, reqEditors...)
@@ -440,7 +481,7 @@ func (w *ServerInterfaceWrapper) GetPet(ctx echo.Context) error {
// ------------- Path parameter "petId" -------------
var petId string
- err = runtime.BindStyledParameterWithLocation("simple", false, "petId", runtime.ParamLocationPath, ctx.Param("petId"), &petId)
+ err = runtime.BindStyledParameterWithOptions("simple", "petId", ctx.Param("petId"), &petId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter petId: %s", err))
}
@@ -474,53 +515,74 @@ type EchoRouter interface {
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
}
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
- router.GET(baseURL+"/pets/:petId", wrapper.GetPet)
- router.POST(baseURL+"/pets:validate", wrapper.ValidatePets)
+ router.GET(options.BaseURL+"/pets/:petId", wrapper.GetPet, options.OperationMiddlewares["getPet"]...)
+ router.POST(options.BaseURL+"/pets:validate", wrapper.ValidatePets, options.OperationMiddlewares["validatePets"]...)
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/6xUPW/bMBD9K8S1o2A58aaxRVF4KTIUXQIPrHSSmZof5Z2MGgb/e3Gk7NqxjAzNFIX3",
- "eO/de0cfofU2eIeOCZojULtFq/Pnlxh9lI8QfcDIBvNx6zuUvx1SG01g4x00BaxyrYLeR6sZGjCOV49Q",
- "AR8Cln9xwAipAotEerjb6FQ+XyWOxg2QUgURf48mYgfNM0yEJ/gmVfCEfCvaaTvD9X2LSirK94q3qALy",
- "4k3K3GpzRvmfL9gyFOJv2ha+W3a6T08X/CQCDKPN+FdKzqQ6Rn2YVUYz0gRnXO9vFXzeYvuLVFGrkFod",
- "jBtETtBRW2SMJIYY3knDNdGIavXwqBiJoYI9RiqdHhbLxVIU+oBOBwMNrPJRBUHzNk9Ty3z1MSCvuyQH",
- "Q4lKyLUoWnfQwFdkiVDunSU0z0cwQiO9oJrihNwJLk3gOGI1LfGMgWkjYAreUQnkcbksO+0YXRajQ9iZ",
- "NsupX0hmO170+xixhwY+1P9eTT09mVpUZ6+vPd7rnekk2pwXjdbqeChzyqkazB6dMh06Nr3BuMi47FWT",
- "72rOqxs88W2CPyZE3h2oXnl5qj6VoviExJ98d3jPqcvWp+t1lCTSf7p9fgdv2n7zMu7HQJBrvR53/G4u",
- "lN/KGdrR4Z+ALWOncMJcLsF1fCml9DcAAP//Z6kfG5EFAAA=",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "rFQ9b9swEP0rxLWjYDnxprFFUXgpMhRdAg+sdJKZmh/lnYwaBv97caTs2rGMDM0Uhfd47917Rx+h9TZ4",
+ "h44JmiNQu0Wr8+eXGH2UjxB9wMgG83HrO5S/HVIbTWDjHTQFrHKtgt5HqxkaMI5Xj1ABHwKWf3HACKkC",
+ "i0R6uNvoVD5fJY7GDZBSBRF/jyZiB80zTIQn+CZV8IR8K9ppO8P1fYtKKsr3ireoAvLiTcrcanNG+Z8v",
+ "2DIU4m/aFr5bdrpPTxf8JAIMo834V0rOpDpGfZhVRjPSBGdc728VfN5i+4tUUauQWh2MG0RO0FFbZIwk",
+ "hhjeScM10Yhq9fCoGImhgj1GKp0eFsvFUhT6gE4HAw2s8lEFQfM2T1PLfPUxIK+7JAdDiUrItShad9DA",
+ "V2SJUO6dJTTPRzBCI72gmuKE3AkuTeA4YjUt8YyBaSNgCt5RCeRxuSw77RhdFqND2Jk2y6lfSGY7XvT7",
+ "GLGHBj7U/15NPT2ZWlRnr6893uud6STanBeN1up4KHPKqRrMHp0yHTo2vcG4yLjsVZPvas6rGzzxbYI/",
+ "JkTeHaheeXmqPpWi+ITEn3x3eM+py9an63WUJNJ/un1+B2/afvMy7sdAkGu9Hnf8bi6U38oZ2tHhn4At",
+ "Y6dwwlwuwXV8KaX0NwAA//8=",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -528,7 +590,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -546,12 +608,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -577,3 +639,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-518/config.yaml b/internal/test/issues/issue-518/config.yaml
new file mode 100644
index 0000000000..5b1cf72492
--- /dev/null
+++ b/internal/test/issues/issue-518/config.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue518
+generate:
+ echo-server: true
+ models: true
+output: issue518.gen.go
diff --git a/internal/test/issues/issue-518/doc.go b/internal/test/issues/issue-518/doc.go
new file mode 100644
index 0000000000..5276da3dd7
--- /dev/null
+++ b/internal/test/issues/issue-518/doc.go
@@ -0,0 +1,3 @@
+package issue518
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-518/issue518.gen.go b/internal/test/issues/issue-518/issue518.gen.go
new file mode 100644
index 0000000000..79f72d1430
--- /dev/null
+++ b/internal/test/issues/issue-518/issue518.gen.go
@@ -0,0 +1,106 @@
+// Package issue518 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue518
+
+import (
+ "github.com/labstack/echo/v4"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /alpha)
+ GetAlpha(ctx echo.Context) error
+
+ // (GET /beta)
+ GetBeta(ctx echo.Context) error
+
+ // (GET /gamma)
+ GetGamma(ctx echo.Context) error
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+// GetAlpha converts echo context to params.
+func (w *ServerInterfaceWrapper) GetAlpha(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetAlpha(ctx)
+ return err
+}
+
+// GetBeta converts echo context to params.
+func (w *ServerInterfaceWrapper) GetBeta(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetBeta(ctx)
+ return err
+}
+
+// GetGamma converts echo context to params.
+func (w *ServerInterfaceWrapper) GetGamma(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetGamma(ctx)
+ return err
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+}
+
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
+}
+
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.GET(options.BaseURL+"/alpha", wrapper.GetAlpha, options.OperationMiddlewares["get-alpha"]...)
+ router.GET(options.BaseURL+"/beta", wrapper.GetBeta, options.OperationMiddlewares["get-beta"]...)
+ router.GET(options.BaseURL+"/gamma", wrapper.GetGamma, options.OperationMiddlewares["GetGamma"]...)
+
+}
diff --git a/internal/test/issues/issue-518/issue518_test.go b/internal/test/issues/issue-518/issue518_test.go
new file mode 100644
index 0000000000..af58469dab
--- /dev/null
+++ b/internal/test/issues/issue-518/issue518_test.go
@@ -0,0 +1,106 @@
+package issue518
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/labstack/echo/v4"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+type stubServer struct{}
+
+func (stubServer) GetAlpha(ctx echo.Context) error { return ctx.NoContent(http.StatusOK) }
+func (stubServer) GetBeta(ctx echo.Context) error { return ctx.NoContent(http.StatusOK) }
+func (stubServer) GetGamma(ctx echo.Context) error { return ctx.NoContent(http.StatusOK) }
+
+// recordingMiddleware appends a tag to the slice it closes over each time it
+// runs. Lets the test assert which routes the middleware ran on.
+func recordingMiddleware(record *[]string, tag string) echo.MiddlewareFunc {
+ return func(next echo.HandlerFunc) echo.HandlerFunc {
+ return func(c echo.Context) error {
+ *record = append(*record, tag)
+ return next(c)
+ }
+ }
+}
+
+func TestRegisterHandlersWithOptions_PerOperationMiddleware(t *testing.T) {
+ var calls []string
+
+ e := echo.New()
+ RegisterHandlersWithOptions(e, stubServer{}, RegisterHandlersOptions{
+ OperationMiddlewares: map[string][]echo.MiddlewareFunc{
+ // Spec-form key (kebab-case), proving the map is NOT keyed on the
+ // normalized Go identifier "GetAlpha".
+ "get-alpha": {recordingMiddleware(&calls, "alpha-mw")},
+ },
+ })
+
+ srv := httptest.NewServer(e)
+ defer srv.Close()
+
+ for _, path := range []string{"/alpha", "/beta", "/gamma"} {
+ resp, err := http.Get(srv.URL + path)
+ require.NoError(t, err)
+ require.NoError(t, resp.Body.Close())
+ require.Equal(t, http.StatusOK, resp.StatusCode, "path %s", path)
+ }
+
+ // Middleware fires only on /alpha, not /beta or /gamma.
+ assert.Equal(t, []string{"alpha-mw"}, calls)
+}
+
+func TestRegisterHandlersWithOptions_FallbackKeyForGeneratedOperationId(t *testing.T) {
+ var calls []string
+
+ e := echo.New()
+ // /gamma has no spec operationId, so the codegen generated one. Per the
+ // MiddlewareKey() fallback, the map key in this case is the normalized
+ // OperationId — copy whatever the wrapper method is named.
+ RegisterHandlersWithOptions(e, stubServer{}, RegisterHandlersOptions{
+ OperationMiddlewares: map[string][]echo.MiddlewareFunc{
+ "GetGamma": {recordingMiddleware(&calls, "gamma-mw")},
+ },
+ })
+
+ srv := httptest.NewServer(e)
+ defer srv.Close()
+
+ resp, err := http.Get(srv.URL + "/gamma")
+ require.NoError(t, err)
+ require.NoError(t, resp.Body.Close())
+ require.Equal(t, http.StatusOK, resp.StatusCode)
+ assert.Equal(t, []string{"gamma-mw"}, calls)
+}
+
+func TestRegisterHandlers_BackwardsCompatible(t *testing.T) {
+ // Existing call sites using RegisterHandlers / RegisterHandlersWithBaseURL
+ // must keep working — they delegate to RegisterHandlersWithOptions with no
+ // per-operation middleware.
+ e := echo.New()
+ RegisterHandlers(e, stubServer{})
+
+ srv := httptest.NewServer(e)
+ defer srv.Close()
+
+ resp, err := http.Get(srv.URL + "/alpha")
+ require.NoError(t, err)
+ require.NoError(t, resp.Body.Close())
+ assert.Equal(t, http.StatusOK, resp.StatusCode)
+}
+
+func TestRegisterHandlersWithBaseURL_BackwardsCompatible(t *testing.T) {
+ e := echo.New()
+ RegisterHandlersWithBaseURL(e, stubServer{}, "/api")
+
+ srv := httptest.NewServer(e)
+ defer srv.Close()
+
+ resp, err := http.Get(srv.URL + "/api/alpha")
+ require.NoError(t, err)
+ require.NoError(t, resp.Body.Close())
+ assert.Equal(t, http.StatusOK, resp.StatusCode)
+}
diff --git a/internal/test/issues/issue-518/spec.yaml b/internal/test/issues/issue-518/spec.yaml
new file mode 100644
index 0000000000..2bc84308b6
--- /dev/null
+++ b/internal/test/issues/issue-518/spec.yaml
@@ -0,0 +1,26 @@
+openapi: 3.0.0
+info:
+ title: issue-518 per-operation middleware regression
+ version: '1.0'
+paths:
+ /alpha:
+ get:
+ # Deliberately kebab-case to exercise that OperationMiddlewares is keyed
+ # on the spec's raw operationId, not the normalized Go identifier.
+ operationId: get-alpha
+ responses:
+ '200':
+ description: OK
+ /beta:
+ get:
+ operationId: get-beta
+ responses:
+ '200':
+ description: OK
+ /gamma:
+ # No operationId on this one — codegen generates a default. The map key
+ # falls back to the normalized OperationId in that case.
+ get:
+ responses:
+ '200':
+ description: OK
diff --git a/internal/test/issues/issue-52/config.yaml b/internal/test/issues/issue-52/config.yaml
index 8ea198ff2d..1277b9c971 100644
--- a/internal/test/issues/issue-52/config.yaml
+++ b/internal/test/issues/issue-52/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: issue52
generate:
echo-server: true
diff --git a/internal/test/issues/issue-52/doc.go b/internal/test/issues/issue-52/doc.go
index f29e0e9f83..3d239ebdcf 100644
--- a/internal/test/issues/issue-52/doc.go
+++ b/internal/test/issues/issue-52/doc.go
@@ -1,3 +1,3 @@
package issue52
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-52/issue.gen.go b/internal/test/issues/issue-52/issue.gen.go
index 031c507f3a..5e0a502a4c 100644
--- a/internal/test/issues/issue-52/issue.gen.go
+++ b/internal/test/issues/issue-52/issue.gen.go
@@ -1,11 +1,11 @@
// Package issue52 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package issue52
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -142,7 +142,7 @@ func NewExampleGetRequest(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -203,6 +203,16 @@ type ExampleGetResponse struct {
JSON200 *Document
}
+// GetJSON200 returns JSON200
+func (r ExampleGetResponse) GetJSON200() *Document {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r ExampleGetResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r ExampleGetResponse) Status() string {
if r.HTTPResponse != nil {
@@ -219,6 +229,14 @@ func (r ExampleGetResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r ExampleGetResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// ExampleGetWithResponse request returning *ExampleGetResponse
func (c *ClientWithResponses) ExampleGetWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ExampleGetResponse, error) {
rsp, err := c.ExampleGet(ctx, reqEditors...)
@@ -290,49 +308,70 @@ type EchoRouter interface {
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
}
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
- router.GET(baseURL+"/example", wrapper.ExampleGet)
+ router.GET(options.BaseURL+"/example", wrapper.ExampleGet, options.OperationMiddlewares["exampleGet"]...)
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/5RSwU7rMBD8lWjfO0ZJXt/NNyQQQgjBiROXxd42Lo5t2ZuKqsq/o3XaQgQCcYo92Zmd",
- "He8BdBhi8OQ5gzpA1j0NWI4XKeH+Ed1IcrNMQ4H/JlqDgj/tO7E9stq5eqqB95FAAYqE3C+DHgfyLAIx",
- "hUiJLRW5tSVnygmNsWyDR/ewqPhNw/C8Jc0wfUZqOI+yNICLMb9r9iGQqYbMyfrNmXhsN6NfGRDI+nWQ",
- "YkNZJxtlWlBwhy9U5TFRxT1ylUiPKdsdVaKQK0xU9eiNI1PN1t3+yUMNbNlJB3rFITqCGnaU8qzZNV3z",
- "T2yGSB6jBQX/m65ZQQ0RuS+TtyeiOsCGytuIOoqtGwMKrub/18RQQ6Icg89zaKuuk48Ono+vijE6qwu3",
- "3WbxcFqmn2I970aJaBnN/a2g0zS9BQAA//+hEzLlqAIAAA==",
+ "lFLBTuswEPyVaN87Rkle3803JBBCCMGJE5fF3jYujm3Zm4qqyr+jddpCBAJxij3ZmZ0d7wF0GGLw5DmD",
+ "OkDWPQ1Yjhcp4f4R3Uhys0xDgf8mWoOCP+07sT2y2rl6qoH3kUABioTcL4MeB/IsAjGFSIktFbm1JWfK",
+ "CY2xbINH97Co+E3D8LwlzTB9Rmo4j7I0gIsxv2v2IZCphszJ+s2ZeGw3o18ZEMj6dZBiQ1knG2VaUHCH",
+ "L1TlMVHFPXKVSI8p2x1VopArTFT16I0jU83W3f7JQw1s2UkHesUhOoIadpTyrNk1XfNPbIZIHqMFBf+b",
+ "rllBDRG5L5O3J6I6wIbK24g6iq0bAwqu5v/XxFBDohyDz3Noq66Tjw6ej6+KMTqrC7fdZvFwWqafYj3v",
+ "RoloGc39raDTNL0FAAD//w==",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -340,7 +379,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -358,12 +397,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -389,3 +428,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-52/issue_test.go b/internal/test/issues/issue-52/issue_test.go
index 0d90bf68b4..0288c2aead 100644
--- a/internal/test/issues/issue-52/issue_test.go
+++ b/internal/test/issues/issue-52/issue_test.go
@@ -4,8 +4,8 @@ import (
_ "embed"
"testing"
- "github.com/deepmap/oapi-codegen/pkg/codegen"
"github.com/getkin/kin-openapi/openapi3"
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/codegen"
"github.com/stretchr/testify/require"
)
diff --git a/internal/test/issues/issue-579/gen.go b/internal/test/issues/issue-579/gen.go
index d34774f7ea..7b198d0cdf 100644
--- a/internal/test/issues/issue-579/gen.go
+++ b/internal/test/issues/issue-579/gen.go
@@ -1,3 +1,3 @@
package issue579
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --package=issue579 --generate=types,skip-prune --alias-types -o issue.gen.go spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --package=issue579 --generate=types,skip-prune --alias-types -o issue.gen.go spec.yaml
diff --git a/internal/test/issues/issue-579/issue.gen.go b/internal/test/issues/issue-579/issue.gen.go
index d46a029aaa..54326646d9 100644
--- a/internal/test/issues/issue-579/issue.gen.go
+++ b/internal/test/issues/issue-579/issue.gen.go
@@ -1,6 +1,6 @@
// Package issue579 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package issue579
import (
diff --git a/internal/test/issues/issue-832/config.yaml b/internal/test/issues/issue-832/config.yaml
index e1eb4e5f6a..446d7a14e6 100644
--- a/internal/test/issues/issue-832/config.yaml
+++ b/internal/test/issues/issue-832/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: issue_832
generate:
models: true
diff --git a/internal/test/issues/issue-832/generate.go b/internal/test/issues/issue-832/generate.go
index 877007acbb..79b06c7131 100644
--- a/internal/test/issues/issue-832/generate.go
+++ b/internal/test/issues/issue-832/generate.go
@@ -1,3 +1,3 @@
package issue_832
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-832/issue.gen.go b/internal/test/issues/issue-832/issue.gen.go
index b950e3e0af..8b0d1e2123 100644
--- a/internal/test/issues/issue-832/issue.gen.go
+++ b/internal/test/issues/issue-832/issue.gen.go
@@ -1,11 +1,11 @@
// Package issue_832 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package issue_832
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/url"
@@ -23,6 +23,22 @@ const (
Two Document_Status = "two"
)
+// Valid indicates whether the value is a known member of the Document_Status enum.
+func (e Document_Status) Valid() bool {
+ switch e {
+ case Four:
+ return true
+ case One:
+ return true
+ case Three:
+ return true
+ case Two:
+ return true
+ default:
+ return false
+ }
+}
+
// Document defines model for Document.
type Document struct {
Name *string `json:"name,omitempty"`
@@ -37,32 +53,34 @@ type DocumentStatus struct {
Value *string `json:"value,omitempty"`
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/7ySz0/rMAzH/5XK7x27tq/vljMIIYQ47AgIhdRbM9o4Styxaer/jpxuReOHxIlL4zq2",
- "vx/HPoCh3pNDxxHUAaJpsdfJvCAz9OhYbB/IY2CL6cbpHuXkvUdQEDlYt4Yxh8iahxSCbuhB3QM5hBz4",
- "leTbBpS/FQ0BHvMP6TnsFmtaiHMxCcwET8up7jjOSfS8QcOieQpaztrnsFvdDV/Rfq4lLutWJMENRhOs",
- "Z0sOFNzqF8ziEDDjVnMW0Awh2i1mUiFmOmDWatd02GSTeLd/cNKx5U4UcKd730nvWwxxqlkVVfFPGiCP",
- "TnsLCv4XVVFDDl5zm9jLU6I6wBrTJKS6FqzrBhRcTvdXyJBDwOjJxantuqrkMOT4OEPtfWdNyi03URhO",
- "4xbrb8AVKPhTvu9DeVyGct6E9ETnT3N3I94xn1nrH8DWv0E7L813zOP4FgAA//8tucJ2/gIAAA==",
+ "vJLPT+swDMf/lcrvHbu2r++WMwghhDjsCAiF1Fsz2jhK3LFp6v+OnG5F44fEiUvjOra/H8c+gKHek0PH",
+ "EdQBommx18m8IDP06FhsH8hjYIvpxuke5eS9R1AQOVi3hjGHyJqHFIJu6EHdAzmEHPiV5NsGlL8VDQEe",
+ "8w/pOewWa1qIczEJzARPy6nuOM5J9LxBw6J5ClrO2uewW90NX9F+riUu61YkwQ1GE6xnSw4U3OoXzOIQ",
+ "MONWcxbQDCHaLWZSIWY6YNZq13TYZJN4t39w0rHlThRwp3vfSe9bDHGqWRVV8U8aII9OewsK/hdVUUMO",
+ "XnOb2MtTojrAGtMkpLoWrOsGFFxO91fIkEPA6MnFqe26quQw5Pg4Q+19Z03KLTdRGE7jFutvwBUo+FO+",
+ "70N5XIZy3oT0ROdPc3cj3jGfWesfwNa/QTsvzXfM4/gWAAD//w==",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -70,7 +88,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -88,12 +106,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -119,3 +137,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-936/api.gen.go b/internal/test/issues/issue-936/api.gen.go
index 806140da05..6b7c0cf220 100644
--- a/internal/test/issues/issue-936/api.gen.go
+++ b/internal/test/issues/issue-936/api.gen.go
@@ -1,6 +1,6 @@
// Package issue936 provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package issue936
import (
@@ -90,7 +90,7 @@ func (t *FilterPredicate) MergeFilterValue(v FilterValue) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -116,7 +116,7 @@ func (t *FilterPredicate) MergeFilterPredicate1(v FilterPredicate1) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -142,7 +142,7 @@ func (t *FilterPredicate) MergeFilterPredicateOp(v FilterPredicateOp) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -168,7 +168,7 @@ func (t *FilterPredicate) MergeFilterPredicateRangeOp(v FilterPredicateRangeOp)
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -204,7 +204,7 @@ func (t *FilterPredicateOp_Any) MergeFilterPredicateOpAny0(v FilterPredicateOpAn
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -240,7 +240,7 @@ func (t *FilterPredicateOp_None) MergeFilterPredicate(v FilterPredicate) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -266,7 +266,7 @@ func (t *FilterPredicateOp_None) MergeFilterPredicateOpNone1(v FilterPredicateOp
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -302,7 +302,7 @@ func (t *FilterRangeValue) MergeFilterRangeValue0(v FilterRangeValue0) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -328,7 +328,7 @@ func (t *FilterRangeValue) MergeFilterRangeValue1(v FilterRangeValue1) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -364,7 +364,7 @@ func (t *FilterValue) MergeFilterValue0(v FilterValue0) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -390,7 +390,7 @@ func (t *FilterValue) MergeFilterValue1(v FilterValue1) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -416,7 +416,7 @@ func (t *FilterValue) MergeFilterValue2(v FilterValue2) error {
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
diff --git a/internal/test/issues/issue-936/gen.go b/internal/test/issues/issue-936/gen.go
index e21b0500de..f1e62f42f1 100644
--- a/internal/test/issues/issue-936/gen.go
+++ b/internal/test/issues/issue-936/gen.go
@@ -1,3 +1,3 @@
package issue936
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.config.yaml spec.yaml
diff --git a/internal/test/issues/issue-936/server.config.yaml b/internal/test/issues/issue-936/server.config.yaml
index aa459d00dd..76b85471ab 100644
--- a/internal/test/issues/issue-936/server.config.yaml
+++ b/internal/test/issues/issue-936/server.config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: issue936
output: api.gen.go
generate:
diff --git a/internal/test/issues/issue-970/config.yaml b/internal/test/issues/issue-970/config.yaml
new file mode 100644
index 0000000000..d23778565d
--- /dev/null
+++ b/internal/test/issues/issue-970/config.yaml
@@ -0,0 +1,6 @@
+package: issue970
+output: issue970.gen.go
+generate:
+ std-http-server: true
+ strict-server: true
+ models: true
diff --git a/internal/test/issues/issue-970/generate.go b/internal/test/issues/issue-970/generate.go
new file mode 100644
index 0000000000..addc711e6d
--- /dev/null
+++ b/internal/test/issues/issue-970/generate.go
@@ -0,0 +1,3 @@
+package issue970
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-970/issue970.gen.go b/internal/test/issues/issue-970/issue970.gen.go
new file mode 100644
index 0000000000..a19d0f2aae
--- /dev/null
+++ b/internal/test/issues/issue-970/issue970.gen.go
@@ -0,0 +1,375 @@
+//go:build go1.22
+
+// Package issue970 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue970
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "net/http"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// Defines values for OnetimeEventKind.
+const (
+ Onetime OnetimeEventKind = "onetime"
+)
+
+// Valid indicates whether the value is a known member of the OnetimeEventKind enum.
+func (e OnetimeEventKind) Valid() bool {
+ switch e {
+ case Onetime:
+ return true
+ default:
+ return false
+ }
+}
+
+// Defines values for RepeatableEventKind.
+const (
+ Repeatable RepeatableEventKind = "repeatable"
+)
+
+// Valid indicates whether the value is a known member of the RepeatableEventKind enum.
+func (e RepeatableEventKind) Valid() bool {
+ switch e {
+ case Repeatable:
+ return true
+ default:
+ return false
+ }
+}
+
+// Event defines model for Event.
+type Event struct {
+ union json.RawMessage
+}
+
+// OnetimeEvent defines model for OnetimeEvent.
+type OnetimeEvent struct {
+ Kind OnetimeEventKind `json:"kind"`
+ Name string `json:"name"`
+}
+
+// OnetimeEventKind defines model for OnetimeEvent.Kind.
+type OnetimeEventKind string
+
+// RepeatableEvent defines model for RepeatableEvent.
+type RepeatableEvent struct {
+ Interval string `json:"interval"`
+ Kind RepeatableEventKind `json:"kind"`
+}
+
+// RepeatableEventKind defines model for RepeatableEvent.Kind.
+type RepeatableEventKind string
+
+// AsOnetimeEvent returns the union data inside the Event as a OnetimeEvent
+func (t Event) AsOnetimeEvent() (OnetimeEvent, error) {
+ var body OnetimeEvent
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOnetimeEvent overwrites any union data inside the Event as the provided OnetimeEvent
+func (t *Event) FromOnetimeEvent(v OnetimeEvent) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOnetimeEvent performs a merge with any union data inside the Event, using the provided OnetimeEvent
+func (t *Event) MergeOnetimeEvent(v OnetimeEvent) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsRepeatableEvent returns the union data inside the Event as a RepeatableEvent
+func (t Event) AsRepeatableEvent() (RepeatableEvent, error) {
+ var body RepeatableEvent
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromRepeatableEvent overwrites any union data inside the Event as the provided RepeatableEvent
+func (t *Event) FromRepeatableEvent(v RepeatableEvent) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeRepeatableEvent performs a merge with any union data inside the Event, using the provided RepeatableEvent
+func (t *Event) MergeRepeatableEvent(v RepeatableEvent) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t Event) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *Event) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /event)
+ GetEvent(w http.ResponseWriter, r *http.Request)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetEvent operation middleware
+func (siw *ServerInterfaceWrapper) GetEvent(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetEvent(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{})
+}
+
+// ServeMux is an abstraction of [http.ServeMux].
+type ServeMux interface {
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+ http.Handler
+}
+
+type StdHTTPServerOptions struct {
+ BaseURL string
+ BaseRouter ServeMux
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/event", wrapper.GetEvent)
+
+ return m
+}
+
+type GetEventRequestObject struct {
+}
+
+type GetEventResponseObject interface {
+ VisitGetEventResponse(w http.ResponseWriter) error
+}
+
+type GetEvent200JSONResponse Event
+
+func (t GetEvent200JSONResponse) MarshalJSON() ([]byte, error) {
+ return Event(t).MarshalJSON()
+}
+
+func (t *GetEvent200JSONResponse) UnmarshalJSON(b []byte) error {
+ return (*Event)(t).UnmarshalJSON(b)
+}
+
+func (response GetEvent200JSONResponse) VisitGetEventResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /event)
+ GetEvent(ctx context.Context, request GetEventRequestObject) (GetEventResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// GetEvent operation middleware
+func (sh *strictHandler) GetEvent(w http.ResponseWriter, r *http.Request) {
+ var request GetEventRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetEvent(ctx, request.(GetEventRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetEvent")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetEventResponseObject); ok {
+ if err := validResponse.VisitGetEventResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/internal/test/issues/issue-970/issue970_test.go b/internal/test/issues/issue-970/issue970_test.go
new file mode 100644
index 0000000000..20a5f52d43
--- /dev/null
+++ b/internal/test/issues/issue-970/issue970_test.go
@@ -0,0 +1,64 @@
+package issue970
+
+import (
+ "encoding/json"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+// TestUnionResponseMarshalsUnderlying is a regression test for
+// https://github.com/oapi-codegen/oapi-codegen/issues/970.
+//
+// The strict-server response type for a content schema that is a $ref to a
+// oneOf/anyOf union must encode as the union's JSON, not {}. Named defined
+// types do not inherit methods, so we generate a delegating MarshalJSON.
+func TestUnionResponseMarshalsUnderlying(t *testing.T) {
+ var ev Event
+ require.NoError(t, ev.FromOnetimeEvent(OnetimeEvent{
+ Kind: Onetime,
+ Name: "birthday",
+ }))
+
+ resp := GetEvent200JSONResponse(ev)
+
+ got, err := json.Marshal(resp)
+ require.NoError(t, err)
+ assert.JSONEq(t, `{"kind":"onetime","name":"birthday"}`, string(got),
+ "union response must marshal via delegating MarshalJSON, not as {}")
+}
+
+// TestUnionResponseVisitWritesBody verifies the end-to-end strict-server Visit
+// path — the HTTP response body must contain the union's JSON.
+func TestUnionResponseVisitWritesBody(t *testing.T) {
+ var ev Event
+ require.NoError(t, ev.FromRepeatableEvent(RepeatableEvent{
+ Kind: Repeatable,
+ Interval: "weekly",
+ }))
+
+ resp := GetEvent200JSONResponse(ev)
+ w := httptest.NewRecorder()
+
+ require.NoError(t, resp.VisitGetEventResponse(w))
+ assert.Equal(t, 200, w.Code)
+ assert.Equal(t, "application/json", w.Header().Get("Content-Type"))
+ assert.JSONEq(t, `{"kind":"repeatable","interval":"weekly"}`, w.Body.String())
+}
+
+// TestUnionResponseRoundtrip verifies the delegating UnmarshalJSON also works,
+// so clients parsing a response body can recover the union value.
+func TestUnionResponseRoundtrip(t *testing.T) {
+ src := []byte(`{"kind":"onetime","name":"release"}`)
+
+ var resp GetEvent200JSONResponse
+ require.NoError(t, json.Unmarshal(src, &resp))
+
+ ev := Event(resp)
+ onetime, err := ev.AsOnetimeEvent()
+ require.NoError(t, err)
+ assert.Equal(t, Onetime, onetime.Kind)
+ assert.Equal(t, "release", onetime.Name)
+}
diff --git a/internal/test/issues/issue-970/spec.yaml b/internal/test/issues/issue-970/spec.yaml
new file mode 100644
index 0000000000..4bb106d74d
--- /dev/null
+++ b/internal/test/issues/issue-970/spec.yaml
@@ -0,0 +1,33 @@
+openapi: 3.0.0
+info:
+ title: Issue 970 Regression
+ version: "1.0"
+paths:
+ /event:
+ get:
+ operationId: getEvent
+ responses:
+ '200':
+ description: ok
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Event'
+components:
+ schemas:
+ Event:
+ oneOf:
+ - $ref: '#/components/schemas/OnetimeEvent'
+ - $ref: '#/components/schemas/RepeatableEvent'
+ OnetimeEvent:
+ type: object
+ required: [kind, name]
+ properties:
+ kind: { type: string, enum: [onetime] }
+ name: { type: string }
+ RepeatableEvent:
+ type: object
+ required: [kind, interval]
+ properties:
+ kind: { type: string, enum: [repeatable] }
+ interval: { type: string }
diff --git a/internal/test/issues/issue-grab_import_names/config.yaml b/internal/test/issues/issue-grab_import_names/config.yaml
index 3248a4893f..85e3f15e69 100644
--- a/internal/test/issues/issue-grab_import_names/config.yaml
+++ b/internal/test/issues/issue-grab_import_names/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: grabimportnames
generate:
echo-server: true
diff --git a/internal/test/issues/issue-grab_import_names/doc.go b/internal/test/issues/issue-grab_import_names/doc.go
index 5c73385b07..e986569fcb 100644
--- a/internal/test/issues/issue-grab_import_names/doc.go
+++ b/internal/test/issues/issue-grab_import_names/doc.go
@@ -1,3 +1,3 @@
package grabimportnames
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-grab_import_names/issue.gen.go b/internal/test/issues/issue-grab_import_names/issue.gen.go
index b6ceeaabc7..08e66b4fcb 100644
--- a/internal/test/issues/issue-grab_import_names/issue.gen.go
+++ b/internal/test/issues/issue-grab_import_names/issue.gen.go
@@ -1,11 +1,11 @@
// Package grabimportnames provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package grabimportnames
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -138,7 +138,7 @@ func NewGetFooRequest(server string, params *GetFooParams) (*http.Request, error
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -148,7 +148,7 @@ func NewGetFooRequest(server string, params *GetFooParams) (*http.Request, error
if params.Foo != nil {
var headerParam0 string
- headerParam0, err = runtime.StyleParamWithLocation("simple", false, "Foo", runtime.ParamLocationHeader, *params.Foo)
+ headerParam0, err = runtime.StyleParamWithOptions("simple", false, "Foo", *params.Foo, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "string", Format: ""})
if err != nil {
return nil, err
}
@@ -159,7 +159,7 @@ func NewGetFooRequest(server string, params *GetFooParams) (*http.Request, error
if params.Bar != nil {
var headerParam1 string
- headerParam1, err = runtime.StyleParamWithLocation("simple", false, "Bar", runtime.ParamLocationHeader, *params.Bar)
+ headerParam1, err = runtime.StyleParamWithOptions("simple", false, "Bar", *params.Bar, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "string", Format: ""})
if err != nil {
return nil, err
}
@@ -225,6 +225,16 @@ type GetFooResponse struct {
JSON200 *string
}
+// GetJSON200 returns JSON200
+func (r GetFooResponse) GetJSON200() *string {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetFooResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetFooResponse) Status() string {
if r.HTTPResponse != nil {
@@ -241,6 +251,14 @@ func (r GetFooResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetFooResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// GetFooWithResponse request returning *GetFooResponse
func (c *ClientWithResponses) GetFooWithResponse(ctx context.Context, params *GetFooParams, reqEditors ...RequestEditorFn) (*GetFooResponse, error) {
rsp, err := c.GetFoo(ctx, params, reqEditors...)
@@ -304,7 +322,7 @@ func (w *ServerInterfaceWrapper) GetFoo(ctx echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for Foo, got %d", n))
}
- err = runtime.BindStyledParameterWithLocation("simple", false, "Foo", runtime.ParamLocationHeader, valueList[0], &Foo)
+ err = runtime.BindStyledParameterWithOptions("simple", "Foo", valueList[0], &Foo, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "string", Format: ""})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter Foo: %s", err))
}
@@ -319,7 +337,7 @@ func (w *ServerInterfaceWrapper) GetFoo(ctx echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for Bar, got %d", n))
}
- err = runtime.BindStyledParameterWithLocation("simple", false, "Bar", runtime.ParamLocationHeader, valueList[0], &Bar)
+ err = runtime.BindStyledParameterWithOptions("simple", "Bar", valueList[0], &Bar, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "string", Format: ""})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter Bar: %s", err))
}
@@ -347,49 +365,69 @@ type EchoRouter interface {
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
}
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
- router.GET(baseURL+"/foo", wrapper.GetFoo)
+ router.GET(options.BaseURL+"/foo", wrapper.GetFoo, options.OperationMiddlewares["GetFoo"]...)
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/3yRzWrrQAyFX0VoPSgmudyFl6W0dN9dKWXiKPEUzw+SUpIGv3uZcVahqTdCwvrm6JwL",
- "hrTP2F/Qgk2MPRIROvxi0ZAT9thRRx3ODnPh5EvAHjfU0RodFm+j1t3VPjfGga2WHesgodgCWIC5sPg6",
- "edlhj89sTzk3hPjIxqLYv91ubr3y/38E27OxEgxjIBhyMj4ZAQ9jJmCRLEqwj0Zw+A6FYDQrBCETfGpO",
- "BFfdm6oiVOzIfseCDpOP9eJFiQ4jR9+cOJc6VpOQDjjP7lbXlfhRf1SCagOBHJOFyATLnhK09vG4nL10",
- "ryEyHGUiOMWJ4OzjdFfWg5c/Zb07FNaSk3ILYd11tTSDUsvBlzKFoT2/ql7U2X3e7H4Jbm7fTwAAAP//",
- "VfuleiYCAAA=",
+ "fJHNautADIVfRWg9KCa53IWXpbR0310pZeIo8RTPD5JSkga/e5lxVqGpN0LC+ubonAuGtM/YX9CCTYw9",
+ "EhE6/GLRkBP22FFHHc4Oc+HkS8AeN9TRGh0Wb6PW3dU+N8aBrZYd6yCh2AJYgLmw+Dp52WGPz2xPOTeE",
+ "+MjGoti/3W5uvfL/fwTbs7ESDGMgGHIyPhkBD2MmYJEsSrCPRnD4DoVgNCsEIRN8ak4EV92bqiJU7Mh+",
+ "x4IOk4/14kWJDiNH35w4lzpWk5AOOM/uVteV+FF/VIJqA4Eck4XIBMueErT28bicvXSvITIcZSI4xYng",
+ "7ON0V9aDlz9lvTsU1pKTcgth3XW1NINSy8GXMoWhPb+qXtTZfd7sfglubt9PAAAA//8=",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -397,7 +435,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -415,12 +453,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -446,3 +484,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-grab_import_names/issue_test.go b/internal/test/issues/issue-grab_import_names/issue_test.go
index 8dffcd22b2..7d299fa22a 100644
--- a/internal/test/issues/issue-grab_import_names/issue_test.go
+++ b/internal/test/issues/issue-grab_import_names/issue_test.go
@@ -3,8 +3,8 @@ package grabimportnames
import (
"testing"
- "github.com/deepmap/oapi-codegen/pkg/codegen"
"github.com/getkin/kin-openapi/openapi3"
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/codegen"
"github.com/stretchr/testify/require"
)
diff --git a/internal/test/issues/issue-head-digit-of-httpheader/config.yaml b/internal/test/issues/issue-head-digit-of-httpheader/config.yaml
index 1f7ce9d390..37457c892a 100644
--- a/internal/test/issues/issue-head-digit-of-httpheader/config.yaml
+++ b/internal/test/issues/issue-head-digit-of-httpheader/config.yaml
@@ -1,4 +1,5 @@
---
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: headdigitofhttpheader
generate:
strict-server: true
diff --git a/internal/test/issues/issue-head-digit-of-httpheader/doc.go b/internal/test/issues/issue-head-digit-of-httpheader/doc.go
index 0c4cfc13a0..63904053bf 100644
--- a/internal/test/issues/issue-head-digit-of-httpheader/doc.go
+++ b/internal/test/issues/issue-head-digit-of-httpheader/doc.go
@@ -1,3 +1,3 @@
package headdigitofhttpheader
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go b/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go
index 5b070c616e..12df040ba4 100644
--- a/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go
+++ b/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go
@@ -1,10 +1,10 @@
// Package headdigitofhttpheader provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package headdigitofhttpheader
type N200ResponseHeaders struct {
- N000Foo string
+ N000Foo *string
}
type N200Response struct {
Headers N200ResponseHeaders
diff --git a/internal/test/issues/issue-head-digit-of-operation-id/config.yaml b/internal/test/issues/issue-head-digit-of-operation-id/config.yaml
index 5823c79ebb..9ac5a0a128 100644
--- a/internal/test/issues/issue-head-digit-of-operation-id/config.yaml
+++ b/internal/test/issues/issue-head-digit-of-operation-id/config.yaml
@@ -1,4 +1,5 @@
---
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: head_digit_of_operation_id
generate:
strict-server: true
diff --git a/internal/test/issues/issue-head-digit-of-operation-id/doc.go b/internal/test/issues/issue-head-digit-of-operation-id/doc.go
index 6faae82c83..fb08e63e86 100644
--- a/internal/test/issues/issue-head-digit-of-operation-id/doc.go
+++ b/internal/test/issues/issue-head-digit-of-operation-id/doc.go
@@ -1,3 +1,3 @@
package head_digit_of_operation_id
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go b/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go
index 7bc67aa178..00c0844afc 100644
--- a/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go
+++ b/internal/test/issues/issue-head-digit-of-operation-id/issue.gen.go
@@ -1,4 +1,4 @@
// Package head_digit_of_operation_id provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package head_digit_of_operation_id
diff --git a/internal/test/issues/issue-illegal_enum_names/config.yaml b/internal/test/issues/issue-illegal_enum_names/config.yaml
index 9b426a0d54..e8bbe0e352 100644
--- a/internal/test/issues/issue-illegal_enum_names/config.yaml
+++ b/internal/test/issues/issue-illegal_enum_names/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: illegalenumnames
generate:
echo-server: true
diff --git a/internal/test/issues/issue-illegal_enum_names/doc.go b/internal/test/issues/issue-illegal_enum_names/doc.go
index de0c23ffdb..d8fb076b49 100644
--- a/internal/test/issues/issue-illegal_enum_names/doc.go
+++ b/internal/test/issues/issue-illegal_enum_names/doc.go
@@ -1,3 +1,3 @@
package illegalenumnames
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue-illegal_enum_names/issue.gen.go b/internal/test/issues/issue-illegal_enum_names/issue.gen.go
index b34b1d77a2..09859b13cd 100644
--- a/internal/test/issues/issue-illegal_enum_names/issue.gen.go
+++ b/internal/test/issues/issue-illegal_enum_names/issue.gen.go
@@ -1,11 +1,11 @@
// Package illegalenumnames provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package illegalenumnames
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -22,18 +22,46 @@ import (
// Defines values for Bar.
const (
- BarBar Bar = "Bar"
- BarEmpty Bar = ""
- BarFoo Bar = "Foo"
- BarFoo1 Bar = " Foo"
- BarFoo2 Bar = " Foo "
- BarFoo3 Bar = "_Foo_"
- BarFooBar Bar = "Foo Bar"
- BarFooBar1 Bar = "Foo-Bar"
- BarN1 Bar = "1"
- BarN1Foo Bar = "1Foo"
+ BarBar Bar = "Bar"
+ BarEmpty Bar = ""
+ BarFoo Bar = "Foo"
+ BarFoo1 Bar = " Foo"
+ BarFoo2 Bar = " Foo "
+ BarFooBar Bar = "Foo Bar"
+ BarFooBar1 Bar = "Foo-Bar"
+ BarN1 Bar = "1"
+ BarN1Foo Bar = "1Foo"
+ BarUnderscoreFoo Bar = "_Foo_"
)
+// Valid indicates whether the value is a known member of the Bar enum.
+func (e Bar) Valid() bool {
+ switch e {
+ case BarBar:
+ return true
+ case BarEmpty:
+ return true
+ case BarFoo:
+ return true
+ case BarFoo1:
+ return true
+ case BarFoo2:
+ return true
+ case BarFooBar:
+ return true
+ case BarFooBar1:
+ return true
+ case BarN1:
+ return true
+ case BarN1Foo:
+ return true
+ case BarUnderscoreFoo:
+ return true
+ default:
+ return false
+ }
+}
+
// Bar defines model for Bar.
type Bar string
@@ -145,7 +173,7 @@ func NewGetFooRequest(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -206,6 +234,16 @@ type GetFooResponse struct {
JSON200 *[]Bar
}
+// GetJSON200 returns JSON200
+func (r GetFooResponse) GetJSON200() *[]Bar {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetFooResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetFooResponse) Status() string {
if r.HTTPResponse != nil {
@@ -222,6 +260,14 @@ func (r GetFooResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetFooResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// GetFooWithResponse request returning *GetFooResponse
func (c *ClientWithResponses) GetFooWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetFooResponse, error) {
rsp, err := c.GetFoo(ctx, reqEditors...)
@@ -293,48 +339,68 @@ type EchoRouter interface {
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
}
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
- router.GET(baseURL+"/foo", wrapper.GetFoo)
+ router.GET(options.BaseURL+"/foo", wrapper.GetFoo, options.OperationMiddlewares["GetFoo"]...)
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/0xQQU4DMQz8SjVwDNml3HLkUMQbEKqirbcN6tpRYpCqKn9HzkIhl5kkHtszV0yyZGFi",
- "rQhX1OlES+z0ORYD4s8F4Q1w2InA9ffONzf2sLLH/wWb9WKwgcN+J7K3Grw76CUTAqqWxEe01hwSz2Lj",
- "NOnZ/rz3cPiiUpMwAkY/+hHNQTJxzAkBT370WzjkqKe+8TBL73EkNZBMJWoSfj0g4IV03ahQzcKVumQ7",
- "jgaTsBJ3Vcz5nKauGz6qzf5NxVhSWrrwvtCMgLvhL7/hJ7zBAmg3l7GUeFlNHqhOJWVdLZnF1s93AAAA",
- "//9U8KAOhgEAAA==",
+ "TFBBTgMxDPxKNXAM2aXccuRQxBsQqqKttw3q2lFikKoqf0fOQiGXmSQe2zNXTLJkYWKtCFfU6URL7PQ5",
+ "FgPizwXhDXDYicD19843N/awssf/BZv1YrCBw34nsrcavDvoJRMCqpbER7TWHBLPYuM06dn+vPdw+KJS",
+ "kzACRj/6Ec1BMnHMCQFPfvRbOOSop77xMEvvcSQ1kEwlahJ+PSDghXTdqFDNwpW6ZDuOBpOwEndVzPmc",
+ "pq4bPqrN/k3FWFJauvC+0IyAu+Evv+EnvMECaDeXsZR4WU0eqE4lZV0tmcXWz3cAAAD//w==",
}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -342,7 +408,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -360,12 +426,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -391,3 +457,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue-illegal_enum_names/issue_test.go b/internal/test/issues/issue-illegal_enum_names/issue_test.go
index 3df57c8eea..22f3cb3d26 100644
--- a/internal/test/issues/issue-illegal_enum_names/issue_test.go
+++ b/internal/test/issues/issue-illegal_enum_names/issue_test.go
@@ -6,8 +6,8 @@ import (
"go/token"
"testing"
- "github.com/deepmap/oapi-codegen/pkg/codegen"
"github.com/getkin/kin-openapi/openapi3"
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/codegen"
"github.com/stretchr/testify/require"
)
@@ -33,15 +33,19 @@ func TestIllegalEnumNames(t *testing.T) {
constDefs := make(map[string]string)
for _, d := range f.Decls {
- switch decl := d.(type) {
- case *ast.GenDecl:
- if token.CONST == decl.Tok {
- for _, s := range decl.Specs {
- switch spec := s.(type) {
- case *ast.ValueSpec:
- constDefs[spec.Names[0].Name] = spec.Names[0].Obj.Decl.(*ast.ValueSpec).Values[0].(*ast.BasicLit).Value
- }
- }
+ decl, ok := d.(*ast.GenDecl)
+ if !ok || decl.Tok != token.CONST {
+ continue
+ }
+
+ for _, s := range decl.Specs {
+ spec, ok := s.(*ast.ValueSpec)
+ if !ok {
+ continue
+ }
+
+ if v, ok := spec.Names[0].Obj.Decl.(*ast.ValueSpec).Values[0].(*ast.BasicLit); ok {
+ constDefs[spec.Names[0].Name] = v.Value
}
}
}
@@ -54,6 +58,6 @@ func TestIllegalEnumNames(t *testing.T) {
require.Equal(t, `"1Foo"`, constDefs["BarN1Foo"])
require.Equal(t, `" Foo"`, constDefs["BarFoo1"])
require.Equal(t, `" Foo "`, constDefs["BarFoo2"])
- require.Equal(t, `"_Foo_"`, constDefs["BarFoo3"])
+ require.Equal(t, `"_Foo_"`, constDefs["BarUnderscoreFoo"])
require.Equal(t, `"1"`, constDefs["BarN1"])
}
diff --git a/internal/test/issues/issue-removed-external-ref/config.base.yaml b/internal/test/issues/issue-removed-external-ref/config.base.yaml
index 17d4d2f085..14faed834b 100644
--- a/internal/test/issues/issue-removed-external-ref/config.base.yaml
+++ b/internal/test/issues/issue-removed-external-ref/config.base.yaml
@@ -1,11 +1,12 @@
---
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: spec_base
generate:
chi-server: true
strict-server: true
models: true
import-mapping:
- spec-ext.yaml: "github.com/deepmap/oapi-codegen/internal/test/issues/issue-removed-external-ref/gen/spec_ext"
+ spec-ext.yaml: "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-removed-external-ref/gen/spec_ext"
output: gen/spec_base/issue.gen.go
output-options:
skip-prune: true
diff --git a/internal/test/issues/issue-removed-external-ref/config.ext.yaml b/internal/test/issues/issue-removed-external-ref/config.ext.yaml
index 9d0478065a..efb166ed2f 100644
--- a/internal/test/issues/issue-removed-external-ref/config.ext.yaml
+++ b/internal/test/issues/issue-removed-external-ref/config.ext.yaml
@@ -1,4 +1,5 @@
---
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: spec_ext
generate:
chi-server: true
diff --git a/internal/test/issues/issue-removed-external-ref/doc.go b/internal/test/issues/issue-removed-external-ref/doc.go
index 7cb5ab0d8b..6af4d981ff 100644
--- a/internal/test/issues/issue-removed-external-ref/doc.go
+++ b/internal/test/issues/issue-removed-external-ref/doc.go
@@ -1,4 +1,4 @@
package head_digit_of_httpheader
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.ext.yaml spec-ext.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.base.yaml spec-base.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.ext.yaml spec-ext.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.base.yaml spec-base.yaml
diff --git a/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go b/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go
index 85d296d061..5a8e36dde0 100644
--- a/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go
+++ b/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go
@@ -1,17 +1,17 @@
// Package spec_base provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package spec_base
import (
+ "bytes"
"context"
"encoding/json"
"fmt"
"net/http"
- externalRef0 "github.com/deepmap/oapi-codegen/internal/test/issues/issue-removed-external-ref/gen/spec_ext"
"github.com/go-chi/chi/v5"
- strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-removed-external-ref/gen/spec_ext"
)
// DirectBar defines model for DirectBar.
@@ -59,7 +59,6 @@ type MiddlewareFunc func(http.Handler) http.Handler
// PostInvalidExtRefTrouble operation middleware
func (siw *ServerInterfaceWrapper) PostInvalidExtRefTrouble(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.PostInvalidExtRefTrouble(w, r)
@@ -69,12 +68,11 @@ func (siw *ServerInterfaceWrapper) PostInvalidExtRefTrouble(w http.ResponseWrite
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// PostNoTrouble operation middleware
func (siw *ServerInterfaceWrapper) PostNoTrouble(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.PostNoTrouble(w, r)
@@ -84,7 +82,7 @@ func (siw *ServerInterfaceWrapper) PostNoTrouble(w http.ResponseWriter, r *http.
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
type UnescapedCookieParamError struct {
@@ -222,10 +220,15 @@ type PostInvalidExtRefTrouble300JSONResponse struct {
}
func (response PostInvalidExtRefTrouble300JSONResponse) VisitPostInvalidExtRefTroubleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(300)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type PostNoTroubleRequestObject struct {
@@ -243,10 +246,15 @@ type PostNoTrouble200JSONResponse struct {
}
func (response PostNoTrouble200JSONResponse) VisitPostNoTroubleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
// StrictServerInterface represents all server handlers.
@@ -259,8 +267,8 @@ type StrictServerInterface interface {
PostNoTrouble(ctx context.Context, request PostNoTroubleRequestObject) (PostNoTroubleResponseObject, error)
}
-type StrictHandlerFunc = strictnethttp.StrictHttpHandlerFunc
-type StrictMiddlewareFunc = strictnethttp.StrictHttpMiddlewareFunc
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
type StrictHTTPServerOptions struct {
RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
diff --git a/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go b/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go
index d19736a1cb..b7809cd969 100644
--- a/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go
+++ b/internal/test/issues/issue-removed-external-ref/gen/spec_ext/issue.gen.go
@@ -1,14 +1,14 @@
// Package spec_ext provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package spec_ext
import (
+ "context"
"fmt"
"net/http"
"github.com/go-chi/chi/v5"
- strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"
)
// CamelSchema defines model for CamelSchema.
@@ -165,8 +165,8 @@ type PascalJSONResponse PascalSchema
type StrictServerInterface interface {
}
-type StrictHandlerFunc = strictnethttp.StrictHttpHandlerFunc
-type StrictMiddlewareFunc = strictnethttp.StrictHttpMiddlewareFunc
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
type StrictHTTPServerOptions struct {
RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
diff --git a/internal/test/issues/issue1469/config.yaml b/internal/test/issues/issue1469/config.yaml
new file mode 100644
index 0000000000..0995b5f9fc
--- /dev/null
+++ b/internal/test/issues/issue1469/config.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue1469
+generate:
+ fiber-server: true
+output: main.gen.go
diff --git a/internal/test/issues/issue1469/doc.go b/internal/test/issues/issue1469/doc.go
new file mode 100644
index 0000000000..d72f419f61
--- /dev/null
+++ b/internal/test/issues/issue1469/doc.go
@@ -0,0 +1,3 @@
+package issue1469
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue1469/main.gen.go b/internal/test/issues/issue1469/main.gen.go
new file mode 100644
index 0000000000..4a1161368c
--- /dev/null
+++ b/internal/test/issues/issue1469/main.gen.go
@@ -0,0 +1,69 @@
+// Package issue1469 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1469
+
+import (
+ "github.com/gofiber/fiber/v2"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /test)
+ Test(c *fiber.Ctx) error
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []HandlerMiddlewareFunc
+}
+
+type MiddlewareFunc fiber.Handler
+type HandlerMiddlewareFunc func(c *fiber.Ctx, next fiber.Handler) error
+
+// Test operation middleware
+func (siw *ServerInterfaceWrapper) Test(c *fiber.Ctx) error {
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.Test(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// FiberServerOptions provides options for the Fiber server.
+type FiberServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ HandlerMiddlewares []HandlerMiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router fiber.Router, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, FiberServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.HandlerMiddlewares,
+ }
+
+ for _, m := range options.Middlewares {
+ router.Use(fiber.Handler(m))
+ }
+
+ router.Get(options.BaseURL+"/test", wrapper.Test)
+
+}
diff --git a/internal/test/issues/issue1469/main_test.go b/internal/test/issues/issue1469/main_test.go
new file mode 100644
index 0000000000..3af67244a9
--- /dev/null
+++ b/internal/test/issues/issue1469/main_test.go
@@ -0,0 +1,35 @@
+package issue1469
+
+import (
+ "testing"
+
+ "github.com/gofiber/fiber/v2"
+ "github.com/stretchr/testify/assert"
+)
+
+type impl struct{}
+
+// (GET /test)
+func (i *impl) Test(c *fiber.Ctx) error {
+ panic("not implemented") // TODO: Implement
+}
+
+func TestIssue1469(t *testing.T) {
+ server := &impl{}
+
+ r := fiber.New()
+
+ assert.NotPanics(t, func() {
+ RegisterHandlers(r, server)
+ })
+
+ assert.NotPanics(t, func() {
+ RegisterHandlersWithOptions(r, server, FiberServerOptions{
+ Middlewares: []MiddlewareFunc{
+ func(c *fiber.Ctx) error {
+ return nil
+ },
+ },
+ })
+ })
+}
diff --git a/internal/test/issues/issue1469/spec.yaml b/internal/test/issues/issue1469/spec.yaml
new file mode 100644
index 0000000000..69a8a3e280
--- /dev/null
+++ b/internal/test/issues/issue1469/spec.yaml
@@ -0,0 +1,13 @@
+openapi: "3.0.1"
+paths:
+ /test:
+ get:
+ operationId: test
+ requestBody:
+ content:
+ application/json:
+ schema:
+ type: object
+ responses:
+ 200:
+ description: good
diff --git a/internal/test/issues/issue1561/config.yaml b/internal/test/issues/issue1561/config.yaml
new file mode 100644
index 0000000000..e1df8f3b7e
--- /dev/null
+++ b/internal/test/issues/issue1561/config.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue1561
+generate:
+ models: true
+output: issue1561.gen.go
+output-options:
+ skip-prune: true
+ prefer-skip-optional-pointer-on-container-types: true
diff --git a/internal/test/issues/issue1561/generate.go b/internal/test/issues/issue1561/generate.go
new file mode 100644
index 0000000000..21cf1d305d
--- /dev/null
+++ b/internal/test/issues/issue1561/generate.go
@@ -0,0 +1,3 @@
+package issue1561
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml openapi.yaml
diff --git a/internal/test/issues/issue1561/issue1561.gen.go b/internal/test/issues/issue1561/issue1561.gen.go
new file mode 100644
index 0000000000..f011e318c1
--- /dev/null
+++ b/internal/test/issues/issue1561/issue1561.gen.go
@@ -0,0 +1,21 @@
+// Package issue1561 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1561
+
+// Pong defines model for Pong.
+type Pong struct {
+ Ping string `json:"ping"`
+}
+
+// ResponseBody defines model for ResponseBody.
+type ResponseBody struct {
+ AMap map[string]Pong `json:"a_map,omitempty"`
+ ASlice []Pong `json:"a_slice,omitempty"`
+ ASliceWithAdditionalProps []map[string]Pong `json:"a_slice_with_additional_props,omitempty"`
+ AdditionalProps map[string]Pong `json:"additional_props,omitempty"`
+ Bytes []byte `json:"bytes,omitempty"`
+ BytesWithOverride *[]byte `json:"bytes_with_override,omitempty"`
+ RequiredSlice []Pong `json:"required_slice"`
+ UnknownObject map[string]interface{} `json:"unknown_object,omitempty"`
+}
diff --git a/internal/test/issues/issue1561/issue1561_test.go b/internal/test/issues/issue1561/issue1561_test.go
new file mode 100644
index 0000000000..0873793feb
--- /dev/null
+++ b/internal/test/issues/issue1561/issue1561_test.go
@@ -0,0 +1,64 @@
+package issue1561
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestResponseBody_DoesNotHaveOptionalPointerToContainerTypes(t *testing.T) {
+ pong0 := Pong{
+ Ping: "0th",
+ }
+
+ pong1 := Pong{
+ Ping: "1th",
+ }
+
+ slice := []Pong{
+ pong0,
+ pong1,
+ }
+
+ m := map[string]Pong{
+ "0": pong0,
+ "1": pong1,
+ }
+
+ byteData := []byte("some bytes")
+
+ body := ResponseBody{
+ RequiredSlice: slice,
+ ASlice: slice,
+ AMap: m,
+ UnknownObject: map[string]any{},
+ AdditionalProps: m,
+ ASliceWithAdditionalProps: []map[string]Pong{m},
+ Bytes: byteData,
+ BytesWithOverride: &byteData,
+ }
+
+ assert.NotNil(t, body.RequiredSlice)
+ assert.NotZero(t, body.RequiredSlice)
+
+ assert.NotNil(t, body.ASlice)
+ assert.NotZero(t, body.ASlice)
+
+ assert.NotNil(t, body.AMap)
+ assert.NotZero(t, body.AMap)
+
+ assert.NotNil(t, body.UnknownObject)
+ assert.Empty(t, body.UnknownObject)
+
+ assert.NotNil(t, body.AdditionalProps)
+ assert.NotZero(t, body.AdditionalProps)
+
+ assert.NotNil(t, body.ASliceWithAdditionalProps)
+ assert.NotZero(t, body.ASliceWithAdditionalProps)
+
+ assert.NotNil(t, body.Bytes)
+ assert.NotZero(t, body.Bytes)
+
+ assert.NotNil(t, body.BytesWithOverride)
+ assert.NotZero(t, body.BytesWithOverride)
+}
diff --git a/internal/test/issues/issue1561/openapi.yaml b/internal/test/issues/issue1561/openapi.yaml
new file mode 100644
index 0000000000..4e5cf771c0
--- /dev/null
+++ b/internal/test/issues/issue1561/openapi.yaml
@@ -0,0 +1,49 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: "When using `prefer-skip-optional-pointer-on-container-types`, container types do not have an 'optional pointer'"
+paths:
+components:
+ schemas:
+ ResponseBody:
+ type: object
+ required:
+ - required_slice
+ properties:
+ required_slice:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pong'
+ a_slice:
+ type: array
+ items:
+ $ref: '#/components/schemas/Pong'
+ a_map:
+ additionalProperties:
+ $ref: '#/components/schemas/Pong'
+ unknown_object:
+ type: object
+ additional_props:
+ type: object
+ additionalProperties:
+ $ref: '#/components/schemas/Pong'
+ a_slice_with_additional_props:
+ type: array
+ items:
+ additionalProperties:
+ $ref: '#/components/schemas/Pong'
+ bytes:
+ type: string
+ format: byte
+ bytes_with_override:
+ type: string
+ format: byte
+ x-go-type-skip-optional-pointer: false
+ Pong:
+ type: object
+ required:
+ - ping
+ properties:
+ ping:
+ type: string
+ example: pong
diff --git a/internal/test/issues/issue1767/config.yaml b/internal/test/issues/issue1767/config.yaml
new file mode 100644
index 0000000000..c1bfe0b5b6
--- /dev/null
+++ b/internal/test/issues/issue1767/config.yaml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue1767
+generate:
+ models: true
+output: issue1767.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue1767/generate.go b/internal/test/issues/issue1767/generate.go
new file mode 100644
index 0000000000..3f8e1ef572
--- /dev/null
+++ b/internal/test/issues/issue1767/generate.go
@@ -0,0 +1,3 @@
+package issue1767
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml openapi.yaml
diff --git a/internal/test/issues/issue1767/issue1767.gen.go b/internal/test/issues/issue1767/issue1767.gen.go
new file mode 100644
index 0000000000..1e7bdaddbb
--- /dev/null
+++ b/internal/test/issues/issue1767/issue1767.gen.go
@@ -0,0 +1,17 @@
+// Package issue1767 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1767
+
+import (
+ openapi_types "github.com/oapi-codegen/runtime/types"
+)
+
+// Alarm Alarm Information
+type Alarm struct {
+ // UnderscoreId Identifier of the Alarm.
+ UnderscoreId *openapi_types.UUID `json:"_id,omitempty"`
+
+ // Id Identifier of the Alarm.
+ Id *openapi_types.UUID `json:"id,omitempty"`
+}
diff --git a/internal/test/issues/issue1767/openapi.yaml b/internal/test/issues/issue1767/openapi.yaml
new file mode 100644
index 0000000000..5964395ed0
--- /dev/null
+++ b/internal/test/issues/issue1767/openapi.yaml
@@ -0,0 +1,20 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: "An underscore in the name of a field is remapped to `Underscore`"
+paths:
+components:
+ schemas:
+ Alarm:
+ description: |
+ Alarm Information
+ type: object
+ properties:
+ _id:
+ description: Identifier of the Alarm.
+ type: string
+ format: uuid
+ id:
+ description: Identifier of the Alarm.
+ type: string
+ format: uuid
diff --git a/internal/test/issues/issue1799/chi/out.gen.go b/internal/test/issues/issue1799/chi/out.gen.go
new file mode 100644
index 0000000000..29b13ef98f
--- /dev/null
+++ b/internal/test/issues/issue1799/chi/out.gen.go
@@ -0,0 +1,518 @@
+// Package chi provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package chi
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+
+ "github.com/go-chi/chi/v5"
+)
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = string
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostObject.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams2" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostObject for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /get-multibody)
+ GetGetMultibody(w http.ResponseWriter, r *http.Request)
+
+ // (GET /object)
+ GetObject(w http.ResponseWriter, r *http.Request)
+
+ // (POST /post-multibody)
+ PostPostMultibody(w http.ResponseWriter, r *http.Request)
+
+ // (POST /post-object)
+ PostPostObject(w http.ResponseWriter, r *http.Request)
+}
+
+// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
+
+type Unimplemented struct{}
+
+// (GET /get-multibody)
+func (_ Unimplemented) GetGetMultibody(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /object)
+func (_ Unimplemented) GetObject(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (POST /post-multibody)
+func (_ Unimplemented) PostPostMultibody(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (POST /post-object)
+func (_ Unimplemented) PostPostObject(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetGetMultibody operation middleware
+func (siw *ServerInterfaceWrapper) GetGetMultibody(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetGetMultibody(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetObject operation middleware
+func (siw *ServerInterfaceWrapper) GetObject(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetObject(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// PostPostMultibody operation middleware
+func (siw *ServerInterfaceWrapper) PostPostMultibody(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.PostPostMultibody(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// PostPostObject operation middleware
+func (siw *ServerInterfaceWrapper) PostPostObject(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.PostPostObject(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{})
+}
+
+type ChiServerOptions struct {
+ BaseURL string
+ BaseRouter chi.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = chi.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/get-multibody", wrapper.GetGetMultibody)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/object", wrapper.GetObject)
+ })
+ r.Group(func(r chi.Router) {
+ r.Post(options.BaseURL+"/post-multibody", wrapper.PostPostMultibody)
+ })
+ r.Group(func(r chi.Router) {
+ r.Post(options.BaseURL+"/post-object", wrapper.PostPostObject)
+ })
+
+ return r
+}
+
+type GetGetMultibodyRequestObject struct {
+}
+
+type GetGetMultibodyResponseObject interface {
+ VisitGetGetMultibodyResponse(w http.ResponseWriter) error
+}
+
+type GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse string
+
+func (response GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse) VisitGetGetMultibodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Response string
+
+func (response GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Response) VisitGetGetMultibodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type GetObjectRequestObject struct {
+}
+
+type GetObjectResponseObject interface {
+ VisitGetObjectResponse(w http.ResponseWriter) error
+}
+
+type GetObject200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse string
+
+func (response GetObject200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse) VisitGetObjectResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type PostPostMultibodyRequestObject struct {
+ ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody *PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body *PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody
+}
+
+type PostPostMultibodyResponseObject interface {
+ VisitPostPostMultibodyResponse(w http.ResponseWriter) error
+}
+
+type PostPostObjectRequestObject struct {
+ Body *PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+}
+
+type PostPostObjectResponseObject interface {
+ VisitPostPostObjectResponse(w http.ResponseWriter) error
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /get-multibody)
+ GetGetMultibody(ctx context.Context, request GetGetMultibodyRequestObject) (GetGetMultibodyResponseObject, error)
+
+ // (GET /object)
+ GetObject(ctx context.Context, request GetObjectRequestObject) (GetObjectResponseObject, error)
+
+ // (POST /post-multibody)
+ PostPostMultibody(ctx context.Context, request PostPostMultibodyRequestObject) (PostPostMultibodyResponseObject, error)
+
+ // (POST /post-object)
+ PostPostObject(ctx context.Context, request PostPostObjectRequestObject) (PostPostObjectResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// GetGetMultibody operation middleware
+func (sh *strictHandler) GetGetMultibody(w http.ResponseWriter, r *http.Request) {
+ var request GetGetMultibodyRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetGetMultibody(ctx, request.(GetGetMultibodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetGetMultibody")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetGetMultibodyResponseObject); ok {
+ if err := validResponse.VisitGetGetMultibodyResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// GetObject operation middleware
+func (sh *strictHandler) GetObject(w http.ResponseWriter, r *http.Request) {
+ var request GetObjectRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetObject(ctx, request.(GetObjectRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetObject")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetObjectResponseObject); ok {
+ if err := validResponse.VisitGetObjectResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// PostPostMultibody operation middleware
+func (sh *strictHandler) PostPostMultibody(w http.ResponseWriter, r *http.Request) {
+ var request PostPostMultibodyRequestObject
+
+ if strings.HasPrefix(r.Header.Get("Content-Type"), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") {
+
+ var body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = &body
+ }
+ }
+ if strings.HasPrefix(r.Header.Get("Content-Type"), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"") {
+
+ var body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = &body
+ }
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.PostPostMultibody(ctx, request.(PostPostMultibodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostPostMultibody")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(PostPostMultibodyResponseObject); ok {
+ if err := validResponse.VisitPostPostMultibodyResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// PostPostObject operation middleware
+func (sh *strictHandler) PostPostObject(w http.ResponseWriter, r *http.Request) {
+ var request PostPostObjectRequestObject
+
+ var body PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.PostPostObject(ctx, request.(PostPostObjectRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostPostObject")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(PostPostObjectResponseObject); ok {
+ if err := validResponse.VisitPostPostObjectResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/internal/test/issues/issue1799/client/out.gen.go b/internal/test/issues/issue1799/client/out.gen.go
new file mode 100644
index 0000000000..3ad144a2c5
--- /dev/null
+++ b/internal/test/issues/issue1799/client/out.gen.go
@@ -0,0 +1,721 @@
+// Package client provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package client
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = string
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostObject.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams2" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostObject for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetGetMultibody request
+ GetGetMultibody(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // GetObject request
+ GetObject(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // PostPostMultibodyWithBody request with any body
+ PostPostMultibodyWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PostPostMultibodyWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody(ctx context.Context, body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PostPostMultibodyWithApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body(ctx context.Context, body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // PostPostObjectWithBody request with any body
+ PostPostObjectWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PostPostObjectWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody(ctx context.Context, body PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetGetMultibody(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetGetMultibodyRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) GetObject(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetObjectRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostPostMultibodyWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostPostMultibodyRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostPostMultibodyWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody(ctx context.Context, body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostPostMultibodyRequestWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostPostMultibodyWithApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body(ctx context.Context, body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostPostMultibodyRequestWithApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostPostObjectWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostPostObjectRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostPostObjectWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody(ctx context.Context, body PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostPostObjectRequestWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetGetMultibodyRequest generates requests for GetGetMultibody
+func NewGetGetMultibodyRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/get-multibody")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewGetObjectRequest generates requests for GetObject
+func NewGetObjectRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/object")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewPostPostMultibodyRequestWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody calls the generic PostPostMultibody builder with application/ld+json; profile="https://www.w3.org/ns/activitystreams" body
+func NewPostPostMultibodyRequestWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody(server string, body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPostPostMultibodyRequestWithBody(server, "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"", bodyReader)
+}
+
+// NewPostPostMultibodyRequestWithApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body calls the generic PostPostMultibody builder with application/ld+json; profile="https://www.w3.org/ns/activitystreams2" body
+func NewPostPostMultibodyRequestWithApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body(server string, body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPostPostMultibodyRequestWithBody(server, "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"", bodyReader)
+}
+
+// NewPostPostMultibodyRequestWithBody generates requests for PostPostMultibody with any type of body
+func NewPostPostMultibodyRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/post-multibody")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewPostPostObjectRequestWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody calls the generic PostPostObject builder with application/ld+json; profile="https://www.w3.org/ns/activitystreams" body
+func NewPostPostObjectRequestWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody(server string, body PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPostPostObjectRequestWithBody(server, "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"", bodyReader)
+}
+
+// NewPostPostObjectRequestWithBody generates requests for PostPostObject with any type of body
+func NewPostPostObjectRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/post-object")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetGetMultibodyWithResponse request
+ GetGetMultibodyWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetGetMultibodyResponse, error)
+
+ // GetObjectWithResponse request
+ GetObjectWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetObjectResponse, error)
+
+ // PostPostMultibodyWithBodyWithResponse request with any body
+ PostPostMultibodyWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostPostMultibodyResponse, error)
+
+ PostPostMultibodyWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBodyWithResponse(ctx context.Context, body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody, reqEditors ...RequestEditorFn) (*PostPostMultibodyResponse, error)
+
+ PostPostMultibodyWithApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2BodyWithResponse(ctx context.Context, body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody, reqEditors ...RequestEditorFn) (*PostPostMultibodyResponse, error)
+
+ // PostPostObjectWithBodyWithResponse request with any body
+ PostPostObjectWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostPostObjectResponse, error)
+
+ PostPostObjectWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBodyWithResponse(ctx context.Context, body PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody, reqEditors ...RequestEditorFn) (*PostPostObjectResponse, error)
+}
+
+type GetGetMultibodyResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ ApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams200 *string
+ ApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams2200 *string
+}
+
+// GetApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams200 returns ApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams200
+func (r GetGetMultibodyResponse) GetApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams200() *string {
+ return r.ApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams200
+}
+
+// GetApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams2200 returns ApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams2200
+func (r GetGetMultibodyResponse) GetApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams2200() *string {
+ return r.ApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams2200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetGetMultibodyResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetGetMultibodyResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetGetMultibodyResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetGetMultibodyResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetObjectResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ ApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams200 *string
+}
+
+// GetApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams200 returns ApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams200
+func (r GetObjectResponse) GetApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams200() *string {
+ return r.ApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetObjectResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetObjectResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetObjectResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetObjectResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type PostPostMultibodyResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r PostPostMultibodyResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r PostPostMultibodyResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PostPostMultibodyResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostPostMultibodyResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type PostPostObjectResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r PostPostObjectResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r PostPostObjectResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PostPostObjectResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostPostObjectResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetGetMultibodyWithResponse request returning *GetGetMultibodyResponse
+func (c *ClientWithResponses) GetGetMultibodyWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetGetMultibodyResponse, error) {
+ rsp, err := c.GetGetMultibody(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetGetMultibodyResponse(rsp)
+}
+
+// GetObjectWithResponse request returning *GetObjectResponse
+func (c *ClientWithResponses) GetObjectWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetObjectResponse, error) {
+ rsp, err := c.GetObject(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetObjectResponse(rsp)
+}
+
+// PostPostMultibodyWithBodyWithResponse request with arbitrary body returning *PostPostMultibodyResponse
+func (c *ClientWithResponses) PostPostMultibodyWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostPostMultibodyResponse, error) {
+ rsp, err := c.PostPostMultibodyWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostPostMultibodyResponse(rsp)
+}
+
+func (c *ClientWithResponses) PostPostMultibodyWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBodyWithResponse(ctx context.Context, body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody, reqEditors ...RequestEditorFn) (*PostPostMultibodyResponse, error) {
+ rsp, err := c.PostPostMultibodyWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostPostMultibodyResponse(rsp)
+}
+
+func (c *ClientWithResponses) PostPostMultibodyWithApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2BodyWithResponse(ctx context.Context, body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody, reqEditors ...RequestEditorFn) (*PostPostMultibodyResponse, error) {
+ rsp, err := c.PostPostMultibodyWithApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostPostMultibodyResponse(rsp)
+}
+
+// PostPostObjectWithBodyWithResponse request with arbitrary body returning *PostPostObjectResponse
+func (c *ClientWithResponses) PostPostObjectWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostPostObjectResponse, error) {
+ rsp, err := c.PostPostObjectWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostPostObjectResponse(rsp)
+}
+
+func (c *ClientWithResponses) PostPostObjectWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBodyWithResponse(ctx context.Context, body PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody, reqEditors ...RequestEditorFn) (*PostPostObjectResponse, error) {
+ rsp, err := c.PostPostObjectWithApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostPostObjectResponse(rsp)
+}
+
+// ParseGetGetMultibodyResponse parses an HTTP response from a GetGetMultibodyWithResponse call
+func ParseGetGetMultibodyResponse(rsp *http.Response) (*GetGetMultibodyResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetGetMultibodyResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case rsp.Header.Get("Content-Type") == "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"" && rsp.StatusCode == 200:
+ var dest string
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.ApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams200 = &dest
+
+ case rsp.Header.Get("Content-Type") == "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"" && rsp.StatusCode == 200:
+ var dest string
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.ApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams2200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseGetObjectResponse parses an HTTP response from a GetObjectWithResponse call
+func ParseGetObjectResponse(rsp *http.Response) (*GetObjectResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetObjectResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest string
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.ApplicationldJSONProfilehttpswwwW3Orgnsactivitystreams200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParsePostPostMultibodyResponse parses an HTTP response from a PostPostMultibodyWithResponse call
+func ParsePostPostMultibodyResponse(rsp *http.Response) (*PostPostMultibodyResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &PostPostMultibodyResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
+// ParsePostPostObjectResponse parses an HTTP response from a PostPostObjectWithResponse call
+func ParsePostPostObjectResponse(rsp *http.Response) (*PostPostObjectResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &PostPostObjectResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
diff --git a/internal/test/issues/issue1799/config-chi-server.yaml b/internal/test/issues/issue1799/config-chi-server.yaml
new file mode 100644
index 0000000000..481a0e20a9
--- /dev/null
+++ b/internal/test/issues/issue1799/config-chi-server.yaml
@@ -0,0 +1,8 @@
+package: chi
+generate:
+ chi-server: true
+ strict-server: true
+ models: true
+output: chi/out.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue1799/config-client.yaml b/internal/test/issues/issue1799/config-client.yaml
new file mode 100644
index 0000000000..94ee59f486
--- /dev/null
+++ b/internal/test/issues/issue1799/config-client.yaml
@@ -0,0 +1,7 @@
+package: client
+generate:
+ client: true
+ models: true
+output: client/out.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue1799/config-echo-server.yaml b/internal/test/issues/issue1799/config-echo-server.yaml
new file mode 100644
index 0000000000..a7de2f3447
--- /dev/null
+++ b/internal/test/issues/issue1799/config-echo-server.yaml
@@ -0,0 +1,8 @@
+package: echo
+generate:
+ echo-server: true
+ strict-server: true
+ models: true
+output: echo/out.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue1799/config-fiber-server.yaml b/internal/test/issues/issue1799/config-fiber-server.yaml
new file mode 100644
index 0000000000..9ffccf199c
--- /dev/null
+++ b/internal/test/issues/issue1799/config-fiber-server.yaml
@@ -0,0 +1,8 @@
+package: fiber
+generate:
+ fiber-server: true
+ strict-server: true
+ models: true
+output: fiber/out.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue1799/config-gin-server.yaml b/internal/test/issues/issue1799/config-gin-server.yaml
new file mode 100644
index 0000000000..9b4a9ad231
--- /dev/null
+++ b/internal/test/issues/issue1799/config-gin-server.yaml
@@ -0,0 +1,8 @@
+package: gin
+generate:
+ gin-server: true
+ strict-server: true
+ models: true
+output: gin/out.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue1799/config-gorilla-server.yaml b/internal/test/issues/issue1799/config-gorilla-server.yaml
new file mode 100644
index 0000000000..544d7d5806
--- /dev/null
+++ b/internal/test/issues/issue1799/config-gorilla-server.yaml
@@ -0,0 +1,8 @@
+package: gorilla
+generate:
+ gorilla-server: true
+ strict-server: true
+ models: true
+output: gorilla/out.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue1799/config-iris-server.yaml b/internal/test/issues/issue1799/config-iris-server.yaml
new file mode 100644
index 0000000000..c46e183bf2
--- /dev/null
+++ b/internal/test/issues/issue1799/config-iris-server.yaml
@@ -0,0 +1,8 @@
+package: iris
+generate:
+ iris-server: true
+ strict-server: true
+ models: true
+output: iris/out.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue1799/config-std-http-server.yaml b/internal/test/issues/issue1799/config-std-http-server.yaml
new file mode 100644
index 0000000000..8ac59593a4
--- /dev/null
+++ b/internal/test/issues/issue1799/config-std-http-server.yaml
@@ -0,0 +1,8 @@
+package: stdhttp
+generate:
+ std-http-server: true
+ strict-server: true
+ models: true
+output: std-http/out.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue1799/echo/out.gen.go b/internal/test/issues/issue1799/echo/out.gen.go
new file mode 100644
index 0000000000..846e85ae9e
--- /dev/null
+++ b/internal/test/issues/issue1799/echo/out.gen.go
@@ -0,0 +1,369 @@
+// Package echo provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package echo
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+
+ "github.com/labstack/echo/v4"
+)
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = string
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostObject.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams2" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostObject for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /get-multibody)
+ GetGetMultibody(ctx echo.Context) error
+
+ // (GET /object)
+ GetObject(ctx echo.Context) error
+
+ // (POST /post-multibody)
+ PostPostMultibody(ctx echo.Context) error
+
+ // (POST /post-object)
+ PostPostObject(ctx echo.Context) error
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+// GetGetMultibody converts echo context to params.
+func (w *ServerInterfaceWrapper) GetGetMultibody(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetGetMultibody(ctx)
+ return err
+}
+
+// GetObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetObject(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetObject(ctx)
+ return err
+}
+
+// PostPostMultibody converts echo context to params.
+func (w *ServerInterfaceWrapper) PostPostMultibody(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.PostPostMultibody(ctx)
+ return err
+}
+
+// PostPostObject converts echo context to params.
+func (w *ServerInterfaceWrapper) PostPostObject(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.PostPostObject(ctx)
+ return err
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+}
+
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
+}
+
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.GET(options.BaseURL+"/get-multibody", wrapper.GetGetMultibody, options.OperationMiddlewares["GetGetMultibody"]...)
+ router.GET(options.BaseURL+"/object", wrapper.GetObject, options.OperationMiddlewares["GetObject"]...)
+ router.POST(options.BaseURL+"/post-multibody", wrapper.PostPostMultibody, options.OperationMiddlewares["PostPostMultibody"]...)
+ router.POST(options.BaseURL+"/post-object", wrapper.PostPostObject, options.OperationMiddlewares["PostPostObject"]...)
+
+}
+
+type GetGetMultibodyRequestObject struct {
+}
+
+type GetGetMultibodyResponseObject interface {
+ VisitGetGetMultibodyResponse(w http.ResponseWriter) error
+}
+
+type GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse string
+
+func (response GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse) VisitGetGetMultibodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Response string
+
+func (response GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Response) VisitGetGetMultibodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type GetObjectRequestObject struct {
+}
+
+type GetObjectResponseObject interface {
+ VisitGetObjectResponse(w http.ResponseWriter) error
+}
+
+type GetObject200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse string
+
+func (response GetObject200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse) VisitGetObjectResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type PostPostMultibodyRequestObject struct {
+ ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody *PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body *PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody
+}
+
+type PostPostMultibodyResponseObject interface {
+ VisitPostPostMultibodyResponse(w http.ResponseWriter) error
+}
+
+type PostPostObjectRequestObject struct {
+ Body *PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+}
+
+type PostPostObjectResponseObject interface {
+ VisitPostPostObjectResponse(w http.ResponseWriter) error
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /get-multibody)
+ GetGetMultibody(ctx context.Context, request GetGetMultibodyRequestObject) (GetGetMultibodyResponseObject, error)
+
+ // (GET /object)
+ GetObject(ctx context.Context, request GetObjectRequestObject) (GetObjectResponseObject, error)
+
+ // (POST /post-multibody)
+ PostPostMultibody(ctx context.Context, request PostPostMultibodyRequestObject) (PostPostMultibodyResponseObject, error)
+
+ // (POST /post-object)
+ PostPostObject(ctx context.Context, request PostPostObjectRequestObject) (PostPostObjectResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx echo.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+}
+
+// GetGetMultibody operation middleware
+func (sh *strictHandler) GetGetMultibody(ctx echo.Context) error {
+ var request GetGetMultibodyRequestObject
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.GetGetMultibody(ctx.Request().Context(), request.(GetGetMultibodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetGetMultibody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(GetGetMultibodyResponseObject); ok {
+ return validResponse.VisitGetGetMultibodyResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// GetObject operation middleware
+func (sh *strictHandler) GetObject(ctx echo.Context) error {
+ var request GetObjectRequestObject
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.GetObject(ctx.Request().Context(), request.(GetObjectRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetObject")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(GetObjectResponseObject); ok {
+ return validResponse.VisitGetObjectResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// PostPostMultibody operation middleware
+func (sh *strictHandler) PostPostMultibody(ctx echo.Context) error {
+ var request PostPostMultibodyRequestObject
+
+ if strings.HasPrefix(ctx.Request().Header.Get("Content-Type"), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") {
+ var body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ if err := ctx.Bind(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ return err
+ }
+ } else {
+ request.ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = &body
+ }
+ }
+ if strings.HasPrefix(ctx.Request().Header.Get("Content-Type"), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"") {
+ var body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody
+ if err := ctx.Bind(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ return err
+ }
+ } else {
+ request.ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = &body
+ }
+ }
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.PostPostMultibody(ctx.Request().Context(), request.(PostPostMultibodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostPostMultibody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(PostPostMultibodyResponseObject); ok {
+ return validResponse.VisitPostPostMultibodyResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// PostPostObject operation middleware
+func (sh *strictHandler) PostPostObject(ctx echo.Context) error {
+ var request PostPostObjectRequestObject
+
+ var body PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ if err := ctx.Bind(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ return err
+ }
+ } else {
+ request.Body = &body
+ }
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.PostPostObject(ctx.Request().Context(), request.(PostPostObjectRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostPostObject")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(PostPostObjectResponseObject); ok {
+ return validResponse.VisitPostPostObjectResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
diff --git a/internal/test/issues/issue1799/fiber/out.gen.go b/internal/test/issues/issue1799/fiber/out.gen.go
new file mode 100644
index 0000000000..d2867215ad
--- /dev/null
+++ b/internal/test/issues/issue1799/fiber/out.gen.go
@@ -0,0 +1,380 @@
+// Package fiber provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package fiber
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "io"
+ "strings"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = string
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostObject.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams2" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostObject for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /get-multibody)
+ GetGetMultibody(c *fiber.Ctx) error
+
+ // (GET /object)
+ GetObject(c *fiber.Ctx) error
+
+ // (POST /post-multibody)
+ PostPostMultibody(c *fiber.Ctx) error
+
+ // (POST /post-object)
+ PostPostObject(c *fiber.Ctx) error
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []HandlerMiddlewareFunc
+}
+
+type MiddlewareFunc fiber.Handler
+type HandlerMiddlewareFunc func(c *fiber.Ctx, next fiber.Handler) error
+
+// GetGetMultibody operation middleware
+func (siw *ServerInterfaceWrapper) GetGetMultibody(c *fiber.Ctx) error {
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetGetMultibody(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetObject operation middleware
+func (siw *ServerInterfaceWrapper) GetObject(c *fiber.Ctx) error {
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetObject(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// PostPostMultibody operation middleware
+func (siw *ServerInterfaceWrapper) PostPostMultibody(c *fiber.Ctx) error {
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.PostPostMultibody(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// PostPostObject operation middleware
+func (siw *ServerInterfaceWrapper) PostPostObject(c *fiber.Ctx) error {
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.PostPostObject(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// FiberServerOptions provides options for the Fiber server.
+type FiberServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ HandlerMiddlewares []HandlerMiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router fiber.Router, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, FiberServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.HandlerMiddlewares,
+ }
+
+ for _, m := range options.Middlewares {
+ router.Use(fiber.Handler(m))
+ }
+
+ router.Get(options.BaseURL+"/get-multibody", wrapper.GetGetMultibody)
+
+ router.Get(options.BaseURL+"/object", wrapper.GetObject)
+
+ router.Post(options.BaseURL+"/post-multibody", wrapper.PostPostMultibody)
+
+ router.Post(options.BaseURL+"/post-object", wrapper.PostPostObject)
+
+}
+
+type GetGetMultibodyRequestObject struct {
+}
+
+type GetGetMultibodyResponseObject interface {
+ VisitGetGetMultibodyResponse(ctx *fiber.Ctx) error
+}
+
+type GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse string
+
+func (response GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse) VisitGetGetMultibodyResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ ctx.Status(200)
+
+ return ctx.JSON(&response)
+}
+
+type GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Response string
+
+func (response GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Response) VisitGetGetMultibodyResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"")
+ ctx.Status(200)
+
+ return ctx.JSON(&response)
+}
+
+type GetObjectRequestObject struct {
+}
+
+type GetObjectResponseObject interface {
+ VisitGetObjectResponse(ctx *fiber.Ctx) error
+}
+
+type GetObject200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse string
+
+func (response GetObject200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse) VisitGetObjectResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ ctx.Status(200)
+
+ return ctx.JSON(&response)
+}
+
+type PostPostMultibodyRequestObject struct {
+ ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody *PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body *PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody
+}
+
+type PostPostMultibodyResponseObject interface {
+ VisitPostPostMultibodyResponse(ctx *fiber.Ctx) error
+}
+
+type PostPostObjectRequestObject struct {
+ Body *PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+}
+
+type PostPostObjectResponseObject interface {
+ VisitPostPostObjectResponse(ctx *fiber.Ctx) error
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /get-multibody)
+ GetGetMultibody(ctx context.Context, request GetGetMultibodyRequestObject) (GetGetMultibodyResponseObject, error)
+
+ // (GET /object)
+ GetObject(ctx context.Context, request GetObjectRequestObject) (GetObjectResponseObject, error)
+
+ // (POST /post-multibody)
+ PostPostMultibody(ctx context.Context, request PostPostMultibodyRequestObject) (PostPostMultibodyResponseObject, error)
+
+ // (POST /post-object)
+ PostPostObject(ctx context.Context, request PostPostObjectRequestObject) (PostPostObjectResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx *fiber.Ctx, args any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+}
+
+// GetGetMultibody operation middleware
+func (sh *strictHandler) GetGetMultibody(ctx *fiber.Ctx) error {
+ var request GetGetMultibodyRequestObject
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.GetGetMultibody(ctx.UserContext(), request.(GetGetMultibodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetGetMultibody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(GetGetMultibodyResponseObject); ok {
+ if err := validResponse.VisitGetGetMultibodyResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// GetObject operation middleware
+func (sh *strictHandler) GetObject(ctx *fiber.Ctx) error {
+ var request GetObjectRequestObject
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.GetObject(ctx.UserContext(), request.(GetObjectRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetObject")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(GetObjectResponseObject); ok {
+ if err := validResponse.VisitGetObjectResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// PostPostMultibody operation middleware
+func (sh *strictHandler) PostPostMultibody(ctx *fiber.Ctx) error {
+ var request PostPostMultibodyRequestObject
+
+ if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") {
+
+ var body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ if err := ctx.BodyParser(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else {
+ request.ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = &body
+ }
+ }
+ if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"") {
+
+ var body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody
+ if err := ctx.BodyParser(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else {
+ request.ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = &body
+ }
+ }
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.PostPostMultibody(ctx.UserContext(), request.(PostPostMultibodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostPostMultibody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(PostPostMultibodyResponseObject); ok {
+ if err := validResponse.VisitPostPostMultibodyResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// PostPostObject operation middleware
+func (sh *strictHandler) PostPostObject(ctx *fiber.Ctx) error {
+ var request PostPostObjectRequestObject
+
+ var body PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ if err := ctx.BodyParser(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else {
+ request.Body = &body
+ }
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.PostPostObject(ctx.UserContext(), request.(PostPostObjectRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostPostObject")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(PostPostObjectResponseObject); ok {
+ if err := validResponse.VisitPostPostObjectResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
diff --git a/internal/test/issues/issue1799/generate.go b/internal/test/issues/issue1799/generate.go
new file mode 100644
index 0000000000..e1143bb5af
--- /dev/null
+++ b/internal/test/issues/issue1799/generate.go
@@ -0,0 +1,10 @@
+package issue1799
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config-iris-server.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config-chi-server.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config-fiber-server.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config-echo-server.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config-gin-server.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config-gorilla-server.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config-std-http-server.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config-client.yaml spec.yaml
diff --git a/internal/test/issues/issue1799/gin/out.gen.go b/internal/test/issues/issue1799/gin/out.gen.go
new file mode 100644
index 0000000000..38c818b9d9
--- /dev/null
+++ b/internal/test/issues/issue1799/gin/out.gen.go
@@ -0,0 +1,422 @@
+// Package gin provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package gin
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+
+ "github.com/gin-gonic/gin"
+)
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = string
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostObject.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams2" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostObject for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /get-multibody)
+ GetGetMultibody(c *gin.Context)
+
+ // (GET /object)
+ GetObject(c *gin.Context)
+
+ // (POST /post-multibody)
+ PostPostMultibody(c *gin.Context)
+
+ // (POST /post-object)
+ PostPostObject(c *gin.Context)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandler func(*gin.Context, error, int)
+}
+
+type MiddlewareFunc func(c *gin.Context)
+
+// GetGetMultibody operation middleware
+func (siw *ServerInterfaceWrapper) GetGetMultibody(c *gin.Context) {
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetGetMultibody(c)
+}
+
+// GetObject operation middleware
+func (siw *ServerInterfaceWrapper) GetObject(c *gin.Context) {
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetObject(c)
+}
+
+// PostPostMultibody operation middleware
+func (siw *ServerInterfaceWrapper) PostPostMultibody(c *gin.Context) {
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.PostPostMultibody(c)
+}
+
+// PostPostObject operation middleware
+func (siw *ServerInterfaceWrapper) PostPostObject(c *gin.Context) {
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.PostPostObject(c)
+}
+
+// GinServerOptions provides options for the Gin server.
+type GinServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ ErrorHandler func(*gin.Context, error, int)
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router gin.IRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, GinServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) {
+ errorHandler := options.ErrorHandler
+ if errorHandler == nil {
+ errorHandler = func(c *gin.Context, err error, statusCode int) {
+ c.JSON(statusCode, gin.H{"msg": err.Error()})
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandler: errorHandler,
+ }
+
+ router.GET(options.BaseURL+"/get-multibody", wrapper.GetGetMultibody)
+ router.GET(options.BaseURL+"/object", wrapper.GetObject)
+ router.POST(options.BaseURL+"/post-multibody", wrapper.PostPostMultibody)
+ router.POST(options.BaseURL+"/post-object", wrapper.PostPostObject)
+}
+
+type GetGetMultibodyRequestObject struct {
+}
+
+type GetGetMultibodyResponseObject interface {
+ VisitGetGetMultibodyResponse(w http.ResponseWriter) error
+}
+
+type GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse string
+
+func (response GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse) VisitGetGetMultibodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Response string
+
+func (response GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Response) VisitGetGetMultibodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type GetObjectRequestObject struct {
+}
+
+type GetObjectResponseObject interface {
+ VisitGetObjectResponse(w http.ResponseWriter) error
+}
+
+type GetObject200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse string
+
+func (response GetObject200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse) VisitGetObjectResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type PostPostMultibodyRequestObject struct {
+ ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody *PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body *PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody
+}
+
+type PostPostMultibodyResponseObject interface {
+ VisitPostPostMultibodyResponse(w http.ResponseWriter) error
+}
+
+type PostPostObjectRequestObject struct {
+ Body *PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+}
+
+type PostPostObjectResponseObject interface {
+ VisitPostPostObjectResponse(w http.ResponseWriter) error
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /get-multibody)
+ GetGetMultibody(ctx context.Context, request GetGetMultibodyRequestObject) (GetGetMultibodyResponseObject, error)
+
+ // (GET /object)
+ GetObject(ctx context.Context, request GetObjectRequestObject) (GetObjectResponseObject, error)
+
+ // (POST /post-multibody)
+ PostPostMultibody(ctx context.Context, request PostPostMultibodyRequestObject) (PostPostMultibodyResponseObject, error)
+
+ // (POST /post-object)
+ PostPostObject(ctx context.Context, request PostPostObjectRequestObject) (PostPostObjectResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx *gin.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictGinServerOptions struct {
+ // RequestErrorHandlerFunc is called when a request cannot be parsed or
+ // decoded. It is invoked for JSON bind failures, form parse/bind errors,
+ // multipart reader errors, media type parse errors, missing multipart
+ // boundaries, and request body read errors. The default returns 400.
+ RequestErrorHandlerFunc func(ctx *gin.Context, err error)
+ // HandlerErrorFunc is called when the application handler (or any
+ // middleware wrapping it) returns a non-nil error. The default returns 500.
+ HandlerErrorFunc func(ctx *gin.Context, err error)
+ // ResponseErrorHandlerFunc is called when the response object fails to
+ // serialize (Visit*Response returns an error) or when the handler returns
+ // an unexpected response type. The default returns 500.
+ ResponseErrorHandlerFunc func(ctx *gin.Context, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictGinServerOptions{
+ RequestErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ },
+ HandlerErrorFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ ResponseErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictGinServerOptions) ServerInterface {
+ if options.RequestErrorHandlerFunc == nil {
+ options.RequestErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.HandlerErrorFunc == nil {
+ options.HandlerErrorFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.ResponseErrorHandlerFunc == nil {
+ options.ResponseErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictGinServerOptions
+}
+
+// GetGetMultibody operation middleware
+func (sh *strictHandler) GetGetMultibody(ctx *gin.Context) {
+ var request GetGetMultibodyRequestObject
+
+ handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.GetGetMultibody(ctx, request.(GetGetMultibodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetGetMultibody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ sh.options.HandlerErrorFunc(ctx, err)
+ } else if validResponse, ok := response.(GetGetMultibodyResponseObject); ok {
+ if err := validResponse.VisitGetGetMultibodyResponse(ctx.Writer); err != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// GetObject operation middleware
+func (sh *strictHandler) GetObject(ctx *gin.Context) {
+ var request GetObjectRequestObject
+
+ handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.GetObject(ctx, request.(GetObjectRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetObject")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ sh.options.HandlerErrorFunc(ctx, err)
+ } else if validResponse, ok := response.(GetObjectResponseObject); ok {
+ if err := validResponse.VisitGetObjectResponse(ctx.Writer); err != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// PostPostMultibody operation middleware
+func (sh *strictHandler) PostPostMultibody(ctx *gin.Context) {
+ var request PostPostMultibodyRequestObject
+
+ if strings.HasPrefix(ctx.GetHeader("Content-Type"), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") {
+
+ var body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ if err := ctx.ShouldBindJSON(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
+ }
+ } else {
+ request.ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = &body
+ }
+ }
+ if strings.HasPrefix(ctx.GetHeader("Content-Type"), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"") {
+
+ var body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody
+ if err := ctx.ShouldBindJSON(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
+ }
+ } else {
+ request.ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = &body
+ }
+ }
+
+ handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.PostPostMultibody(ctx, request.(PostPostMultibodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostPostMultibody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ sh.options.HandlerErrorFunc(ctx, err)
+ } else if validResponse, ok := response.(PostPostMultibodyResponseObject); ok {
+ if err := validResponse.VisitPostPostMultibodyResponse(ctx.Writer); err != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// PostPostObject operation middleware
+func (sh *strictHandler) PostPostObject(ctx *gin.Context) {
+ var request PostPostObjectRequestObject
+
+ var body PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ if err := ctx.ShouldBindJSON(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
+ }
+ } else {
+ request.Body = &body
+ }
+
+ handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.PostPostObject(ctx, request.(PostPostObjectRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostPostObject")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ sh.options.HandlerErrorFunc(ctx, err)
+ } else if validResponse, ok := response.(PostPostObjectResponseObject); ok {
+ if err := validResponse.VisitPostPostObjectResponse(ctx.Writer); err != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/internal/test/issues/issue1799/gorilla/out.gen.go b/internal/test/issues/issue1799/gorilla/out.gen.go
new file mode 100644
index 0000000000..254b183a01
--- /dev/null
+++ b/internal/test/issues/issue1799/gorilla/out.gen.go
@@ -0,0 +1,489 @@
+// Package gorilla provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package gorilla
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+
+ "github.com/gorilla/mux"
+)
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = string
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostObject.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams2" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostObject for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /get-multibody)
+ GetGetMultibody(w http.ResponseWriter, r *http.Request)
+
+ // (GET /object)
+ GetObject(w http.ResponseWriter, r *http.Request)
+
+ // (POST /post-multibody)
+ PostPostMultibody(w http.ResponseWriter, r *http.Request)
+
+ // (POST /post-object)
+ PostPostObject(w http.ResponseWriter, r *http.Request)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetGetMultibody operation middleware
+func (siw *ServerInterfaceWrapper) GetGetMultibody(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetGetMultibody(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetObject operation middleware
+func (siw *ServerInterfaceWrapper) GetObject(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetObject(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// PostPostMultibody operation middleware
+func (siw *ServerInterfaceWrapper) PostPostMultibody(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.PostPostMultibody(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// PostPostObject operation middleware
+func (siw *ServerInterfaceWrapper) PostPostObject(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.PostPostObject(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+ BaseURL string
+ BaseRouter *mux.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = mux.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.HandleFunc(options.BaseURL+"/get-multibody", wrapper.GetGetMultibody).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/object", wrapper.GetObject).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/post-multibody", wrapper.PostPostMultibody).Methods(http.MethodPost)
+
+ r.HandleFunc(options.BaseURL+"/post-object", wrapper.PostPostObject).Methods(http.MethodPost)
+
+ return r
+}
+
+type GetGetMultibodyRequestObject struct {
+}
+
+type GetGetMultibodyResponseObject interface {
+ VisitGetGetMultibodyResponse(w http.ResponseWriter) error
+}
+
+type GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse string
+
+func (response GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse) VisitGetGetMultibodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Response string
+
+func (response GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Response) VisitGetGetMultibodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type GetObjectRequestObject struct {
+}
+
+type GetObjectResponseObject interface {
+ VisitGetObjectResponse(w http.ResponseWriter) error
+}
+
+type GetObject200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse string
+
+func (response GetObject200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse) VisitGetObjectResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type PostPostMultibodyRequestObject struct {
+ ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody *PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body *PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody
+}
+
+type PostPostMultibodyResponseObject interface {
+ VisitPostPostMultibodyResponse(w http.ResponseWriter) error
+}
+
+type PostPostObjectRequestObject struct {
+ Body *PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+}
+
+type PostPostObjectResponseObject interface {
+ VisitPostPostObjectResponse(w http.ResponseWriter) error
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /get-multibody)
+ GetGetMultibody(ctx context.Context, request GetGetMultibodyRequestObject) (GetGetMultibodyResponseObject, error)
+
+ // (GET /object)
+ GetObject(ctx context.Context, request GetObjectRequestObject) (GetObjectResponseObject, error)
+
+ // (POST /post-multibody)
+ PostPostMultibody(ctx context.Context, request PostPostMultibodyRequestObject) (PostPostMultibodyResponseObject, error)
+
+ // (POST /post-object)
+ PostPostObject(ctx context.Context, request PostPostObjectRequestObject) (PostPostObjectResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// GetGetMultibody operation middleware
+func (sh *strictHandler) GetGetMultibody(w http.ResponseWriter, r *http.Request) {
+ var request GetGetMultibodyRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetGetMultibody(ctx, request.(GetGetMultibodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetGetMultibody")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetGetMultibodyResponseObject); ok {
+ if err := validResponse.VisitGetGetMultibodyResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// GetObject operation middleware
+func (sh *strictHandler) GetObject(w http.ResponseWriter, r *http.Request) {
+ var request GetObjectRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetObject(ctx, request.(GetObjectRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetObject")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetObjectResponseObject); ok {
+ if err := validResponse.VisitGetObjectResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// PostPostMultibody operation middleware
+func (sh *strictHandler) PostPostMultibody(w http.ResponseWriter, r *http.Request) {
+ var request PostPostMultibodyRequestObject
+
+ if strings.HasPrefix(r.Header.Get("Content-Type"), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") {
+
+ var body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = &body
+ }
+ }
+ if strings.HasPrefix(r.Header.Get("Content-Type"), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"") {
+
+ var body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = &body
+ }
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.PostPostMultibody(ctx, request.(PostPostMultibodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostPostMultibody")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(PostPostMultibodyResponseObject); ok {
+ if err := validResponse.VisitPostPostMultibodyResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// PostPostObject operation middleware
+func (sh *strictHandler) PostPostObject(w http.ResponseWriter, r *http.Request) {
+ var request PostPostObjectRequestObject
+
+ var body PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.PostPostObject(ctx, request.(PostPostObjectRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostPostObject")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(PostPostObjectResponseObject); ok {
+ if err := validResponse.VisitPostPostObjectResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/internal/test/issues/issue1799/iris/out.gen.go b/internal/test/issues/issue1799/iris/out.gen.go
new file mode 100644
index 0000000000..d57447cbae
--- /dev/null
+++ b/internal/test/issues/issue1799/iris/out.gen.go
@@ -0,0 +1,338 @@
+// Package iris provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package iris
+
+import (
+ "context"
+ "errors"
+ "io"
+ "net/http"
+ "strings"
+
+ "github.com/kataras/iris/v12"
+)
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = string
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostObject.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams2" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostObject for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /get-multibody)
+ GetGetMultibody(ctx iris.Context)
+
+ // (GET /object)
+ GetObject(ctx iris.Context)
+
+ // (POST /post-multibody)
+ PostPostMultibody(ctx iris.Context)
+
+ // (POST /post-object)
+ PostPostObject(ctx iris.Context)
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+type MiddlewareFunc iris.Handler
+
+// GetGetMultibody converts iris context to params.
+func (w *ServerInterfaceWrapper) GetGetMultibody(ctx iris.Context) {
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetGetMultibody(ctx)
+}
+
+// GetObject converts iris context to params.
+func (w *ServerInterfaceWrapper) GetObject(ctx iris.Context) {
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetObject(ctx)
+}
+
+// PostPostMultibody converts iris context to params.
+func (w *ServerInterfaceWrapper) PostPostMultibody(ctx iris.Context) {
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.PostPostMultibody(ctx)
+}
+
+// PostPostObject converts iris context to params.
+func (w *ServerInterfaceWrapper) PostPostObject(ctx iris.Context) {
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.PostPostObject(ctx)
+}
+
+// IrisServerOption is the option for iris server
+type IrisServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router *iris.Application, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, IrisServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router *iris.Application, si ServerInterface, options IrisServerOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.Get(options.BaseURL+"/get-multibody", wrapper.GetGetMultibody)
+ router.Get(options.BaseURL+"/object", wrapper.GetObject)
+ router.Post(options.BaseURL+"/post-multibody", wrapper.PostPostMultibody)
+ router.Post(options.BaseURL+"/post-object", wrapper.PostPostObject)
+
+ router.Build()
+}
+
+type GetGetMultibodyRequestObject struct {
+}
+
+type GetGetMultibodyResponseObject interface {
+ VisitGetGetMultibodyResponse(ctx iris.Context) error
+}
+
+type GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse string
+
+func (response GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse) VisitGetGetMultibodyResponse(ctx iris.Context) error {
+ ctx.ResponseWriter().Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ ctx.StatusCode(200)
+
+ return ctx.JSON(&response)
+}
+
+type GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Response string
+
+func (response GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Response) VisitGetGetMultibodyResponse(ctx iris.Context) error {
+ ctx.ResponseWriter().Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"")
+ ctx.StatusCode(200)
+
+ return ctx.JSON(&response)
+}
+
+type GetObjectRequestObject struct {
+}
+
+type GetObjectResponseObject interface {
+ VisitGetObjectResponse(ctx iris.Context) error
+}
+
+type GetObject200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse string
+
+func (response GetObject200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse) VisitGetObjectResponse(ctx iris.Context) error {
+ ctx.ResponseWriter().Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ ctx.StatusCode(200)
+
+ return ctx.JSON(&response)
+}
+
+type PostPostMultibodyRequestObject struct {
+ ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody *PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body *PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody
+}
+
+type PostPostMultibodyResponseObject interface {
+ VisitPostPostMultibodyResponse(ctx iris.Context) error
+}
+
+type PostPostObjectRequestObject struct {
+ Body *PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+}
+
+type PostPostObjectResponseObject interface {
+ VisitPostPostObjectResponse(ctx iris.Context) error
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /get-multibody)
+ GetGetMultibody(ctx context.Context, request GetGetMultibodyRequestObject) (GetGetMultibodyResponseObject, error)
+
+ // (GET /object)
+ GetObject(ctx context.Context, request GetObjectRequestObject) (GetObjectResponseObject, error)
+
+ // (POST /post-multibody)
+ PostPostMultibody(ctx context.Context, request PostPostMultibodyRequestObject) (PostPostMultibodyResponseObject, error)
+
+ // (POST /post-object)
+ PostPostObject(ctx context.Context, request PostPostObjectRequestObject) (PostPostObjectResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx iris.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+}
+
+// GetGetMultibody operation middleware
+func (sh *strictHandler) GetGetMultibody(ctx iris.Context) {
+ var request GetGetMultibodyRequestObject
+
+ handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.GetGetMultibody(ctx, request.(GetGetMultibodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetGetMultibody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ } else if validResponse, ok := response.(GetGetMultibodyResponseObject); ok {
+ if err := validResponse.VisitGetGetMultibodyResponse(ctx); err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else if response != nil {
+ ctx.Writef("Unexpected response type: %T", response)
+ return
+ }
+}
+
+// GetObject operation middleware
+func (sh *strictHandler) GetObject(ctx iris.Context) {
+ var request GetObjectRequestObject
+
+ handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.GetObject(ctx, request.(GetObjectRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetObject")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ } else if validResponse, ok := response.(GetObjectResponseObject); ok {
+ if err := validResponse.VisitGetObjectResponse(ctx); err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else if response != nil {
+ ctx.Writef("Unexpected response type: %T", response)
+ return
+ }
+}
+
+// PostPostMultibody operation middleware
+func (sh *strictHandler) PostPostMultibody(ctx iris.Context) {
+ var request PostPostMultibodyRequestObject
+
+ if strings.HasPrefix(ctx.GetHeader("Content-Type"), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") {
+
+ var body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ if err := ctx.ReadJSON(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else {
+ request.ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = &body
+ }
+ }
+ if strings.HasPrefix(ctx.GetHeader("Content-Type"), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"") {
+
+ var body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody
+ if err := ctx.ReadJSON(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else {
+ request.ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = &body
+ }
+ }
+
+ handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.PostPostMultibody(ctx, request.(PostPostMultibodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostPostMultibody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ } else if validResponse, ok := response.(PostPostMultibodyResponseObject); ok {
+ if err := validResponse.VisitPostPostMultibodyResponse(ctx); err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else if response != nil {
+ ctx.Writef("Unexpected response type: %T", response)
+ return
+ }
+}
+
+// PostPostObject operation middleware
+func (sh *strictHandler) PostPostObject(ctx iris.Context) {
+ var request PostPostObjectRequestObject
+
+ var body PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ if err := ctx.ReadJSON(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else {
+ request.Body = &body
+ }
+
+ handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.PostPostObject(ctx, request.(PostPostObjectRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostPostObject")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ } else if validResponse, ok := response.(PostPostObjectResponseObject); ok {
+ if err := validResponse.VisitPostPostObjectResponse(ctx); err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else if response != nil {
+ ctx.Writef("Unexpected response type: %T", response)
+ return
+ }
+}
diff --git a/internal/test/issues/issue1799/spec.yaml b/internal/test/issues/issue1799/spec.yaml
new file mode 100644
index 0000000000..1174ae0129
--- /dev/null
+++ b/internal/test/issues/issue1799/spec.yaml
@@ -0,0 +1,51 @@
+openapi: "3.0.0"
+
+info:
+ version: 0.0.1
+ title: example
+
+paths:
+ /object:
+ get:
+ responses:
+ '200':
+ description: something
+ content:
+ "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"":
+ schema:
+ type: string
+ /get-multibody:
+ get:
+ responses:
+ '200':
+ description: something
+ content:
+ "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"":
+ schema:
+ type: string
+ "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"":
+ schema:
+ type: string
+ /post-object:
+ post:
+ requestBody:
+ content:
+ "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"":
+ schema:
+ type: string
+ responses: {}
+
+ /post-multibody:
+ post:
+ requestBody:
+ content:
+ "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"":
+ schema:
+ type: string
+ "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"":
+ schema:
+ type: string
+
+ responses: {}
+
+
diff --git a/internal/test/issues/issue1799/std-http/out.gen.go b/internal/test/issues/issue1799/std-http/out.gen.go
new file mode 100644
index 0000000000..4fc5ab39c0
--- /dev/null
+++ b/internal/test/issues/issue1799/std-http/out.gen.go
@@ -0,0 +1,493 @@
+//go:build go1.22
+
+// Package stdhttp provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package stdhttp
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+)
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body defines parameters for PostPostMultibody.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = string
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody defines parameters for PostPostObject.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = string
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody defines body for PostPostMultibody for application/ld+json; profile="https://www.w3.org/ns/activitystreams2" ContentType.
+type PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody = PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body
+
+// PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody defines body for PostPostObject for application/ld+json; profile="https://www.w3.org/ns/activitystreams" ContentType.
+type PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody = PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /get-multibody)
+ GetGetMultibody(w http.ResponseWriter, r *http.Request)
+
+ // (GET /object)
+ GetObject(w http.ResponseWriter, r *http.Request)
+
+ // (POST /post-multibody)
+ PostPostMultibody(w http.ResponseWriter, r *http.Request)
+
+ // (POST /post-object)
+ PostPostObject(w http.ResponseWriter, r *http.Request)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetGetMultibody operation middleware
+func (siw *ServerInterfaceWrapper) GetGetMultibody(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetGetMultibody(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetObject operation middleware
+func (siw *ServerInterfaceWrapper) GetObject(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetObject(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// PostPostMultibody operation middleware
+func (siw *ServerInterfaceWrapper) PostPostMultibody(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.PostPostMultibody(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// PostPostObject operation middleware
+func (siw *ServerInterfaceWrapper) PostPostObject(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.PostPostObject(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{})
+}
+
+// ServeMux is an abstraction of [http.ServeMux].
+type ServeMux interface {
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+ http.Handler
+}
+
+type StdHTTPServerOptions struct {
+ BaseURL string
+ BaseRouter ServeMux
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/get-multibody", wrapper.GetGetMultibody)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/object", wrapper.GetObject)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/post-multibody", wrapper.PostPostMultibody)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/post-object", wrapper.PostPostObject)
+
+ return m
+}
+
+type GetGetMultibodyRequestObject struct {
+}
+
+type GetGetMultibodyResponseObject interface {
+ VisitGetGetMultibodyResponse(w http.ResponseWriter) error
+}
+
+type GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse string
+
+func (response GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse) VisitGetGetMultibodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Response string
+
+func (response GetGetMultibody200ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Response) VisitGetGetMultibodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type GetObjectRequestObject struct {
+}
+
+type GetObjectResponseObject interface {
+ VisitGetObjectResponse(w http.ResponseWriter) error
+}
+
+type GetObject200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse string
+
+func (response GetObject200ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsResponse) VisitGetObjectResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type PostPostMultibodyRequestObject struct {
+ ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody *PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body *PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody
+}
+
+type PostPostMultibodyResponseObject interface {
+ VisitPostPostMultibodyResponse(w http.ResponseWriter) error
+}
+
+type PostPostObjectRequestObject struct {
+ Body *PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+}
+
+type PostPostObjectResponseObject interface {
+ VisitPostPostObjectResponse(w http.ResponseWriter) error
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (GET /get-multibody)
+ GetGetMultibody(ctx context.Context, request GetGetMultibodyRequestObject) (GetGetMultibodyResponseObject, error)
+
+ // (GET /object)
+ GetObject(ctx context.Context, request GetObjectRequestObject) (GetObjectResponseObject, error)
+
+ // (POST /post-multibody)
+ PostPostMultibody(ctx context.Context, request PostPostMultibodyRequestObject) (PostPostMultibodyResponseObject, error)
+
+ // (POST /post-object)
+ PostPostObject(ctx context.Context, request PostPostObjectRequestObject) (PostPostObjectResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// GetGetMultibody operation middleware
+func (sh *strictHandler) GetGetMultibody(w http.ResponseWriter, r *http.Request) {
+ var request GetGetMultibodyRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetGetMultibody(ctx, request.(GetGetMultibodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetGetMultibody")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetGetMultibodyResponseObject); ok {
+ if err := validResponse.VisitGetGetMultibodyResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// GetObject operation middleware
+func (sh *strictHandler) GetObject(w http.ResponseWriter, r *http.Request) {
+ var request GetObjectRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.GetObject(ctx, request.(GetObjectRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "GetObject")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(GetObjectResponseObject); ok {
+ if err := validResponse.VisitGetObjectResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// PostPostMultibody operation middleware
+func (sh *strictHandler) PostPostMultibody(w http.ResponseWriter, r *http.Request) {
+ var request PostPostMultibodyRequestObject
+
+ if strings.HasPrefix(r.Header.Get("Content-Type"), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") {
+
+ var body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.ApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsBody = &body
+ }
+ }
+ if strings.HasPrefix(r.Header.Get("Content-Type"), "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams2\"") {
+
+ var body PostPostMultibodyApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2RequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.ApplicationLdPlusJSONProfilehttpswwwW3Orgnsactivitystreams2Body = &body
+ }
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.PostPostMultibody(ctx, request.(PostPostMultibodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostPostMultibody")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(PostPostMultibodyResponseObject); ok {
+ if err := validResponse.VisitPostPostMultibodyResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// PostPostObject operation middleware
+func (sh *strictHandler) PostPostObject(w http.ResponseWriter, r *http.Request) {
+ var request PostPostObjectRequestObject
+
+ var body PostPostObjectApplicationLdPlusJSONProfilehttpswwwW3OrgnsactivitystreamsRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.PostPostObject(ctx, request.(PostPostObjectRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "PostPostObject")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(PostPostObjectResponseObject); ok {
+ if err := validResponse.VisitPostPostObjectResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
diff --git a/internal/test/issues/issue1825/config.yaml b/internal/test/issues/issue1825/config.yaml
new file mode 100644
index 0000000000..2df08d4b71
--- /dev/null
+++ b/internal/test/issues/issue1825/config.yaml
@@ -0,0 +1,11 @@
+package: issue1825
+generate:
+ models: true
+ embedded-spec: true
+import-mapping:
+ ../packageA/spec.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue1825/packageA
+output: issue1825.gen.go
+output-options:
+ skip-prune: true
+ overlay:
+ path: overlay.yaml
diff --git a/internal/test/issues/issue1825/doc.go b/internal/test/issues/issue1825/doc.go
new file mode 100644
index 0000000000..664a3ae916
--- /dev/null
+++ b/internal/test/issues/issue1825/doc.go
@@ -0,0 +1,5 @@
+package issue1825
+
+// We place the spec in a subdirectory, as this requires us to initialize the resolver kin-openapi's loader
+// If this is not done, the generator would fail with an `encountered disallowed external reference` error.
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec/spec.yaml
diff --git a/internal/test/issues/issue1825/issue1825.gen.go b/internal/test/issues/issue1825/issue1825.gen.go
new file mode 100644
index 0000000000..c8c5a18a5b
--- /dev/null
+++ b/internal/test/issues/issue1825/issue1825.gen.go
@@ -0,0 +1,131 @@
+// Package issue1825 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1825
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "fmt"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue1825/packageA"
+)
+
+// Container defines model for Container.
+type Container struct {
+ ObjectA *externalRef0.ObjectA `json:"object_a,omitempty"`
+ ObjectB *map[string]interface{} `json:"object_b,omitempty"`
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "hI/RTsMwDEX/xfDYrZN469vEB8AfVF7qbYbWsRJ3Ypry78hZBwiQ9pRY1/fc6wuEOGkUEsvQXSCHI01Y",
+ "v89RDFko+aApKiVjqlLcvVGwHv3/mGgPHTy036B2obSK4R0PtO2zUuhfqmsLpbkBdvcAX3ul/HLhMLBx",
+ "FBxff1SzNFMDdlaCbln3uP97/DlLcCJ/F3+2xHLwaA9n2ccqso2uQgMnSpmjXIePVTxRGvG8QtWRabgS",
+ "5mBzouEm1uOVBJWhg6f1Zr0B72dHb1DKZwAAAP//",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ for rawPath, rawFunc := range externalRef0.PathToRawSpec(path.Join(path.Dir(pathToFile), "../packageA/spec.yaml")) {
+ if _, ok := res[rawPath]; ok {
+ // it is not possible to compare functions in golang, so always overwrite the old value
+ }
+ res[rawPath] = rawFunc
+ }
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue1825/object_b.json b/internal/test/issues/issue1825/object_b.json
new file mode 100644
index 0000000000..cdd7fc12af
--- /dev/null
+++ b/internal/test/issues/issue1825/object_b.json
@@ -0,0 +1,5 @@
+{
+ "type": "object",
+ "properties": {},
+ "additionalProperties": true
+}
diff --git a/internal/test/issues/issue1825/overlay.yaml b/internal/test/issues/issue1825/overlay.yaml
new file mode 100644
index 0000000000..55011983fe
--- /dev/null
+++ b/internal/test/issues/issue1825/overlay.yaml
@@ -0,0 +1,10 @@
+overlay: 1.0.0
+info:
+ title: Overlay example
+ version: 0.0.0
+actions:
+ - target: "$"
+ description: Add a property to the info dictionary
+ update:
+ info:
+ x-overlay-applied: structured-overlay
diff --git a/internal/test/issues/issue1825/overlay_test.go b/internal/test/issues/issue1825/overlay_test.go
new file mode 100644
index 0000000000..75cd428323
--- /dev/null
+++ b/internal/test/issues/issue1825/overlay_test.go
@@ -0,0 +1,14 @@
+package issue1825
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestOverlayApply(t *testing.T) {
+ spec, err := GetSpec()
+ require.NoError(t, err)
+
+ require.Equal(t, spec.Info.Extensions["x-overlay-applied"], "structured-overlay")
+}
diff --git a/internal/test/issues/issue1825/packageA/config.yaml b/internal/test/issues/issue1825/packageA/config.yaml
new file mode 100644
index 0000000000..e84dbfad74
--- /dev/null
+++ b/internal/test/issues/issue1825/packageA/config.yaml
@@ -0,0 +1,7 @@
+package: packagea
+generate:
+ models: true
+ embedded-spec: true
+output-options:
+ skip-prune: true
+output: externalref.gen.go
diff --git a/internal/test/issues/issue1825/packageA/doc.go b/internal/test/issues/issue1825/packageA/doc.go
new file mode 100644
index 0000000000..f05471ffbb
--- /dev/null
+++ b/internal/test/issues/issue1825/packageA/doc.go
@@ -0,0 +1,3 @@
+package packagea
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue1825/packageA/externalref.gen.go b/internal/test/issues/issue1825/packageA/externalref.gen.go
new file mode 100644
index 0000000000..d222870d82
--- /dev/null
+++ b/internal/test/issues/issue1825/packageA/externalref.gen.go
@@ -0,0 +1,121 @@
+// Package packagea provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package packagea
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "fmt"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+)
+
+// ObjectA defines model for ObjectA.
+type ObjectA struct {
+ Name *string `json:"name,omitempty"`
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "JMnBDQIxDETRXuacCnKjAmoI0cAabWwrNge02t5RlrnMl96BbsNNqRmoB6JvHO3K++PNnreVPs05U3iB",
+ "tsH1+XWiInKKvnCuFYg+DVU/+15gTm0uqECBt9ziL+cvAAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/issues/issue1825/packageA/spec.yaml b/internal/test/issues/issue1825/packageA/spec.yaml
new file mode 100644
index 0000000000..303c509938
--- /dev/null
+++ b/internal/test/issues/issue1825/packageA/spec.yaml
@@ -0,0 +1,6 @@
+components:
+ schemas:
+ ObjectA:
+ properties:
+ name:
+ type: string
diff --git a/internal/test/issues/issue1825/spec/spec.yaml b/internal/test/issues/issue1825/spec/spec.yaml
new file mode 100644
index 0000000000..3a29a23582
--- /dev/null
+++ b/internal/test/issues/issue1825/spec/spec.yaml
@@ -0,0 +1,11 @@
+openapi: "3.0.0"
+info: {}
+paths: {}
+components:
+ schemas:
+ Container:
+ properties:
+ object_a:
+ $ref: ../packageA/spec.yaml#/components/schemas/ObjectA
+ object_b:
+ $ref: ../object_b.json
diff --git a/internal/test/issues/issue193/config.yaml b/internal/test/issues/issue193/config.yaml
new file mode 100644
index 0000000000..908d772c69
--- /dev/null
+++ b/internal/test/issues/issue193/config.yaml
@@ -0,0 +1,6 @@
+package: issue52
+generate:
+ models: true
+output: issue.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue193/generate.go b/internal/test/issues/issue193/generate.go
new file mode 100644
index 0000000000..3d239ebdcf
--- /dev/null
+++ b/internal/test/issues/issue193/generate.go
@@ -0,0 +1,3 @@
+package issue52
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue193/issue.gen.go b/internal/test/issues/issue193/issue.gen.go
new file mode 100644
index 0000000000..eec8a25dfc
--- /dev/null
+++ b/internal/test/issues/issue193/issue.gen.go
@@ -0,0 +1,113 @@
+// Package issue52 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue52
+
+import (
+ "encoding/json"
+ "fmt"
+)
+
+// Person defines model for Person.
+type Person struct {
+ Age *float32 `json:"age,omitempty"`
+ Metadata string `json:"metadata"`
+ Name *string `json:"name,omitempty"`
+ AdditionalProperties map[string]interface{} `json:"-"`
+}
+
+// Getter for additional properties for Person. Returns the specified
+// element and whether it was found
+func (a Person) Get(fieldName string) (value interface{}, found bool) {
+ if a.AdditionalProperties != nil {
+ value, found = a.AdditionalProperties[fieldName]
+ }
+ return
+}
+
+// Setter for additional properties for Person
+func (a *Person) Set(fieldName string, value interface{}) {
+ if a.AdditionalProperties == nil {
+ a.AdditionalProperties = make(map[string]interface{})
+ }
+ a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for Person to handle AdditionalProperties
+func (a *Person) UnmarshalJSON(b []byte) error {
+ object := make(map[string]json.RawMessage)
+ err := json.Unmarshal(b, &object)
+ if err != nil {
+ return err
+ }
+
+ if raw, found := object["age"]; found {
+ err = json.Unmarshal(raw, &a.Age)
+ if err != nil {
+ return fmt.Errorf("error reading 'age': %w", err)
+ }
+ delete(object, "age")
+ }
+
+ if raw, found := object["metadata"]; found {
+ err = json.Unmarshal(raw, &a.Metadata)
+ if err != nil {
+ return fmt.Errorf("error reading 'metadata': %w", err)
+ }
+ delete(object, "metadata")
+ }
+
+ if raw, found := object["name"]; found {
+ err = json.Unmarshal(raw, &a.Name)
+ if err != nil {
+ return fmt.Errorf("error reading 'name': %w", err)
+ }
+ delete(object, "name")
+ }
+
+ if len(object) != 0 {
+ a.AdditionalProperties = make(map[string]interface{})
+ for fieldName, fieldBuf := range object {
+ var fieldVal interface{}
+ err := json.Unmarshal(fieldBuf, &fieldVal)
+ if err != nil {
+ return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+ }
+ a.AdditionalProperties[fieldName] = fieldVal
+ }
+ }
+ return nil
+}
+
+// Override default JSON handling for Person to handle AdditionalProperties
+func (a Person) MarshalJSON() ([]byte, error) {
+ var err error
+ object := make(map[string]json.RawMessage)
+
+ if a.Age != nil {
+ object["age"], err = json.Marshal(a.Age)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'age': %w", err)
+ }
+ }
+
+ object["metadata"], err = json.Marshal(a.Metadata)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'metadata': %w", err)
+ }
+
+ if a.Name != nil {
+ object["name"], err = json.Marshal(a.Name)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling 'name': %w", err)
+ }
+ }
+
+ for fieldName, field := range a.AdditionalProperties {
+ object[fieldName], err = json.Marshal(field)
+ if err != nil {
+ return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+ }
+ }
+ return json.Marshal(object)
+}
diff --git a/internal/test/issues/issue193/spec.yaml b/internal/test/issues/issue193/spec.yaml
new file mode 100644
index 0000000000..4002ffbca5
--- /dev/null
+++ b/internal/test/issues/issue193/spec.yaml
@@ -0,0 +1,26 @@
+openapi: 3.0.0
+info:
+ title: test schema
+
+paths:
+
+components:
+ schemas:
+ Person:
+ allOf:
+ # common fields
+ - type: object
+ additionalProperties: true
+ required:
+ - metadata
+ properties:
+ metadata:
+ type: string
+ # person specific fields
+ - type: object
+ additionalProperties: true
+ properties:
+ name:
+ type: string
+ age:
+ type: number
diff --git a/internal/test/issues/issue1957/config.yaml b/internal/test/issues/issue1957/config.yaml
new file mode 100644
index 0000000000..42b31a19f6
--- /dev/null
+++ b/internal/test/issues/issue1957/config.yaml
@@ -0,0 +1,6 @@
+package: issue1957
+generate:
+ models: true
+output: issue1957.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue1957/generate.go b/internal/test/issues/issue1957/generate.go
new file mode 100644
index 0000000000..1a7c0002be
--- /dev/null
+++ b/internal/test/issues/issue1957/generate.go
@@ -0,0 +1,3 @@
+package issue1957
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml openapi.yaml
diff --git a/internal/test/issues/issue1957/issue1957.gen.go b/internal/test/issues/issue1957/issue1957.gen.go
new file mode 100644
index 0000000000..ee2c7adb75
--- /dev/null
+++ b/internal/test/issues/issue1957/issue1957.gen.go
@@ -0,0 +1,27 @@
+// Package issue1957 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue1957
+
+import (
+ googleuuid "github.com/google/uuid"
+)
+
+// ID defines model for ID.
+type ID = googleuuid.UUID
+
+// TypeWithAllOf defines model for TypeWithAllOf.
+type TypeWithAllOf struct {
+ Id googleuuid.UUID `json:"id,omitempty"`
+}
+
+// TypeWithOptionalField defines model for TypeWithOptionalField.
+type TypeWithOptionalField struct {
+ At googleuuid.UUID `json:"at,omitempty"`
+ AtRequired googleuuid.UUID `json:"at_required"`
+}
+
+// GetRootParams defines parameters for GetRoot.
+type GetRootParams struct {
+ At googleuuid.UUID `form:"at,omitempty" json:"at,omitempty"`
+}
diff --git a/internal/test/issues/issue1957/issue1957_test.go b/internal/test/issues/issue1957/issue1957_test.go
new file mode 100644
index 0000000000..de99ccca36
--- /dev/null
+++ b/internal/test/issues/issue1957/issue1957_test.go
@@ -0,0 +1,54 @@
+package issue1957
+
+import (
+ "testing"
+
+ "github.com/google/uuid"
+ "github.com/stretchr/testify/require"
+)
+
+func TestGeneratedCode(t *testing.T) {
+ t.Run("For an object", func(t *testing.T) {
+ t.Run("A required field should be a non-pointer", func(t *testing.T) {
+ theType := TypeWithOptionalField{
+ AtRequired: uuid.New(),
+ }
+
+ require.NotZero(t, theType.AtRequired)
+ })
+
+ t.Run("An optional field with x-go-type-skip-optional-pointer should be a non-pointer", func(t *testing.T) {
+ theType := TypeWithOptionalField{
+ AtRequired: uuid.New(),
+ }
+
+ require.NotZero(t, theType.AtRequired)
+ })
+ })
+
+ t.Run("For a query parameter", func(t *testing.T) {
+ t.Run("An optional field with x-go-type-skip-optional-pointer should be a non-pointer", func(t *testing.T) {
+
+ u := uuid.New()
+
+ theType := GetRootParams{
+ At: u,
+ }
+
+ require.NotZero(t, theType.At)
+ })
+ })
+
+ t.Run("For a field with an AllOf", func(t *testing.T) {
+ t.Run("An optional field with x-go-type-skip-optional-pointer should be a non-pointer", func(t *testing.T) {
+
+ u := uuid.New()
+
+ theType := TypeWithAllOf{
+ Id: u,
+ }
+
+ require.NotZero(t, theType.Id)
+ })
+ })
+}
diff --git a/internal/test/issues/issue1957/openapi.yaml b/internal/test/issues/issue1957/openapi.yaml
new file mode 100644
index 0000000000..729c71dac9
--- /dev/null
+++ b/internal/test/issues/issue1957/openapi.yaml
@@ -0,0 +1,55 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: "x-go-type and x-go-type-skip-optional-pointer should be possible to use together"
+paths:
+ /root:
+ get:
+ operationId: getRoot
+ parameters:
+ - in: query
+ name: at
+ schema:
+ type: string
+ format: date-time
+ x-go-type-skip-optional-pointer: true
+ x-go-type: googleuuid.UUID
+ x-go-type-import:
+ path: github.com/google/uuid
+ name: googleuuid
+ responses:
+ "200":
+ description: Some data
+components:
+ schemas:
+ TypeWithOptionalField:
+ type: object
+ properties:
+ at:
+ type: string
+ x-go-type-skip-optional-pointer: true
+ x-go-type: googleuuid.UUID
+ x-go-type-import:
+ path: github.com/google/uuid
+ name: googleuuid
+ at_required:
+ type: string
+ x-go-type: googleuuid.UUID
+ x-go-type-import:
+ path: github.com/google/uuid
+ name: googleuuid
+ required:
+ - at_required
+ ID:
+ type: string
+ x-go-type: googleuuid.UUID
+ x-go-type-import:
+ path: github.com/google/uuid
+ name: googleuuid
+ TypeWithAllOf:
+ type: object
+ properties:
+ id:
+ allOf:
+ - $ref: '#/components/schemas/ID'
+ - x-go-type-skip-optional-pointer: true
diff --git a/internal/test/issues/issue240/api.yaml b/internal/test/issues/issue240/api.yaml
new file mode 100644
index 0000000000..5945b63dd7
--- /dev/null
+++ b/internal/test/issues/issue240/api.yaml
@@ -0,0 +1,47 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Generate models
+paths:
+ /client:
+ get:
+ operationId: getClient
+ responses:
+ 200:
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/ClientType"
+ put:
+ operationId: updateClient
+ responses:
+ 400:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ code:
+ type: string
+ required:
+ - code
+components:
+ schemas:
+ ClientType:
+ type: object
+ required:
+ - name
+ properties:
+ name:
+ type: string
+ # NOTE that this is not generated by default because it's not referenced. If you want it, you need to use the following YAML configuration:
+ #
+ # output-options:
+ # skip-prune: true
+ Unreferenced:
+ type: object
+ required:
+ - id
+ properties:
+ id:
+ type: int
diff --git a/internal/test/issues/issue240/cfg.yaml b/internal/test/issues/issue240/cfg.yaml
new file mode 100644
index 0000000000..e3143764a0
--- /dev/null
+++ b/internal/test/issues/issue240/cfg.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue240
+output: client.gen.go
+generate:
+ models: true
+ client: true
+output-options:
+ client-response-bytes-function: true
diff --git a/internal/test/issues/issue240/client.gen.go b/internal/test/issues/issue240/client.gen.go
new file mode 100644
index 0000000000..cf1055c485
--- /dev/null
+++ b/internal/test/issues/issue240/client.gen.go
@@ -0,0 +1,393 @@
+// Package issue240 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue240
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+// ClientType defines model for ClientType.
+type ClientType struct {
+ Name string `json:"name"`
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetClient request
+ GetClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // UpdateClient request
+ UpdateClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetClientRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) UpdateClient(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewUpdateClientRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetClientRequest generates requests for GetClient
+func NewGetClientRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/client")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewUpdateClientRequest generates requests for UpdateClient
+func NewUpdateClientRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/client")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPut, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetClientWithResponse request
+ GetClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetClientResponse, error)
+
+ // UpdateClientWithResponse request
+ UpdateClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*UpdateClientResponse, error)
+}
+
+type GetClientResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *ClientType
+}
+
+// GetJSON200 returns JSON200
+func (r GetClientResponse) GetJSON200() *ClientType {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetClientResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetClientResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetClientResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// Bytes is a convenience method to retrieve the raw bytes from the HTTP response
+func (r GetClientResponse) Bytes() []byte {
+ return r.Body
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetClientResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type UpdateClientResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON400 *struct {
+ Code string `json:"code"`
+ }
+}
+
+// GetJSON400 returns JSON400
+func (r UpdateClientResponse) GetJSON400() *struct {
+ Code string `json:"code"`
+} {
+ return r.JSON400
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r UpdateClientResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r UpdateClientResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r UpdateClientResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// Bytes is a convenience method to retrieve the raw bytes from the HTTP response
+func (r UpdateClientResponse) Bytes() []byte {
+ return r.Body
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r UpdateClientResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetClientWithResponse request returning *GetClientResponse
+func (c *ClientWithResponses) GetClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetClientResponse, error) {
+ rsp, err := c.GetClient(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetClientResponse(rsp)
+}
+
+// UpdateClientWithResponse request returning *UpdateClientResponse
+func (c *ClientWithResponses) UpdateClientWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*UpdateClientResponse, error) {
+ rsp, err := c.UpdateClient(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseUpdateClientResponse(rsp)
+}
+
+// ParseGetClientResponse parses an HTTP response from a GetClientWithResponse call
+func ParseGetClientResponse(rsp *http.Response) (*GetClientResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetClientResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest ClientType
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseUpdateClientResponse parses an HTTP response from a UpdateClientWithResponse call
+func ParseUpdateClientResponse(rsp *http.Response) (*UpdateClientResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &UpdateClientResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 400:
+ var dest struct {
+ Code string `json:"code"`
+ }
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON400 = &dest
+
+ }
+
+ return response, nil
+}
diff --git a/internal/test/issues/issue240/generate.go b/internal/test/issues/issue240/generate.go
new file mode 100644
index 0000000000..a107ac4597
--- /dev/null
+++ b/internal/test/issues/issue240/generate.go
@@ -0,0 +1,3 @@
+package issue240
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen -config cfg.yaml api.yaml
diff --git a/internal/test/issues/issue518/config.yaml b/internal/test/issues/issue518/config.yaml
new file mode 100644
index 0000000000..8fca51fa54
--- /dev/null
+++ b/internal/test/issues/issue518/config.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue518
+generate:
+ fiber-server: true
+ models: true
+output: main.gen.go
diff --git a/internal/test/issues/issue518/doc.go b/internal/test/issues/issue518/doc.go
new file mode 100644
index 0000000000..5276da3dd7
--- /dev/null
+++ b/internal/test/issues/issue518/doc.go
@@ -0,0 +1,3 @@
+package issue518
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/issues/issue518/main.gen.go b/internal/test/issues/issue518/main.gen.go
new file mode 100644
index 0000000000..a7b64d5808
--- /dev/null
+++ b/internal/test/issues/issue518/main.gen.go
@@ -0,0 +1,101 @@
+// Package issue518 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue518
+
+import (
+ "github.com/gofiber/fiber/v2"
+)
+
+const (
+ BearerAuthScopes bearerAuthContextKey = "bearerAuth.Scopes"
+)
+
+// bearerAuthContextKey is the context key for bearerAuth security scheme
+type bearerAuthContextKey string
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /auth-check)
+ AuthCheck(c *fiber.Ctx) error
+
+ // (GET /test)
+ Test(c *fiber.Ctx) error
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []HandlerMiddlewareFunc
+}
+
+type MiddlewareFunc fiber.Handler
+type HandlerMiddlewareFunc func(c *fiber.Ctx, next fiber.Handler) error
+
+// AuthCheck operation middleware
+func (siw *ServerInterfaceWrapper) AuthCheck(c *fiber.Ctx) error {
+
+ c.Context().SetUserValue((BearerAuthScopes), []string{})
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.AuthCheck(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// Test operation middleware
+func (siw *ServerInterfaceWrapper) Test(c *fiber.Ctx) error {
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.Test(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// FiberServerOptions provides options for the Fiber server.
+type FiberServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ HandlerMiddlewares []HandlerMiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router fiber.Router, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, FiberServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.HandlerMiddlewares,
+ }
+
+ for _, m := range options.Middlewares {
+ router.Use(fiber.Handler(m))
+ }
+
+ router.Get(options.BaseURL+"/auth-check", wrapper.AuthCheck)
+
+ router.Get(options.BaseURL+"/test", wrapper.Test)
+
+}
diff --git a/internal/test/issues/issue518/main_test.go b/internal/test/issues/issue518/main_test.go
new file mode 100644
index 0000000000..f1d7471c1b
--- /dev/null
+++ b/internal/test/issues/issue518/main_test.go
@@ -0,0 +1,88 @@
+package issue518
+
+import (
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/gofiber/fiber/v2"
+ "github.com/stretchr/testify/assert"
+)
+
+type impl struct{}
+
+// (GET /auth-check)
+func (i *impl) AuthCheck(c *fiber.Ctx) error {
+ return c.SendStatus(fiber.StatusOK)
+}
+
+// (GET /test)
+func (i *impl) Test(c *fiber.Ctx) error {
+ return c.SendStatus(fiber.StatusOK)
+}
+
+// hasSecurityScopes returns true if the BearerAuthScopes key was set in context,
+// even if the scopes slice is empty (an empty slice means the security scheme is
+// defined on the operation with no required scopes, which still requires auth).
+func hasSecurityScopes(c *fiber.Ctx) bool {
+ _, ok := c.Context().UserValue(BearerAuthScopes).([]string)
+ return ok
+}
+
+func TestIssue518(t *testing.T) {
+ server := &impl{}
+
+ assert.NotPanics(t, func() {
+ r := fiber.New()
+ RegisterHandlers(r, server)
+ })
+
+ assert.NotPanics(t, func() {
+ r := fiber.New()
+ RegisterHandlersWithOptions(r, server, FiberServerOptions{
+ Middlewares: []MiddlewareFunc{
+ func(c *fiber.Ctx) error {
+ return nil
+ },
+ },
+ HandlerMiddlewares: []HandlerMiddlewareFunc{
+ func(c *fiber.Ctx, next fiber.Handler) error {
+ if hasSecurityScopes(c) && c.Get(fiber.HeaderAuthorization) == "" {
+ return c.SendStatus(fiber.StatusUnauthorized)
+ }
+ return next(c)
+ },
+ },
+ })
+ })
+
+ t.Run("secured endpoint requires auth when scopes are present", func(t *testing.T) {
+ r := fiber.New()
+ RegisterHandlersWithOptions(r, server, FiberServerOptions{
+ HandlerMiddlewares: []HandlerMiddlewareFunc{
+ func(c *fiber.Ctx, next fiber.Handler) error {
+ if hasSecurityScopes(c) && c.Get(fiber.HeaderAuthorization) == "" {
+ return c.SendStatus(fiber.StatusUnauthorized)
+ }
+ return next(c)
+ },
+ },
+ })
+
+ req := httptest.NewRequest(http.MethodGet, "/auth-check", nil)
+ resp, err := r.Test(req)
+ assert.NoError(t, err)
+ assert.Equal(t, fiber.StatusUnauthorized, resp.StatusCode)
+
+ req = httptest.NewRequest(http.MethodGet, "/auth-check", nil)
+ req.Header.Set(fiber.HeaderAuthorization, "Bearer token")
+ resp, err = r.Test(req)
+ assert.NoError(t, err)
+ assert.Equal(t, fiber.StatusOK, resp.StatusCode)
+
+ req = httptest.NewRequest(http.MethodGet, "/test", nil)
+ resp, err = r.Test(req)
+ assert.NoError(t, err)
+ assert.Equal(t, fiber.StatusOK, resp.StatusCode)
+ })
+}
diff --git a/internal/test/issues/issue518/spec.yaml b/internal/test/issues/issue518/spec.yaml
new file mode 100644
index 0000000000..da011a7eee
--- /dev/null
+++ b/internal/test/issues/issue518/spec.yaml
@@ -0,0 +1,21 @@
+openapi: "3.0.1"
+components:
+ securitySchemes:
+ bearerAuth:
+ scheme: bearer
+ type: http
+paths:
+ /auth-check:
+ get:
+ operationId: authCheck
+ security:
+ - bearerAuth: []
+ responses:
+ 200:
+ description: good
+ /test:
+ get:
+ operationId: test
+ responses:
+ 200:
+ description: good
diff --git a/internal/test/issues/issue609/config.yaml b/internal/test/issues/issue609/config.yaml
new file mode 100644
index 0000000000..a9c4b93879
--- /dev/null
+++ b/internal/test/issues/issue609/config.yaml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: issue609
+generate:
+ models: true
+output: issue609.gen.go
+output-options:
+ skip-prune: true
diff --git a/internal/test/issues/issue609/generate.go b/internal/test/issues/issue609/generate.go
new file mode 100644
index 0000000000..ade5eb92fb
--- /dev/null
+++ b/internal/test/issues/issue609/generate.go
@@ -0,0 +1,3 @@
+package issue609
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml openapi.yaml
diff --git a/internal/test/issues/issue609/issue609.gen.go b/internal/test/issues/issue609/issue609.gen.go
new file mode 100644
index 0000000000..a5d76e500d
--- /dev/null
+++ b/internal/test/issues/issue609/issue609.gen.go
@@ -0,0 +1,9 @@
+// Package issue609 provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package issue609
+
+// ResponseBody defines model for ResponseBody.
+type ResponseBody struct {
+ Unknown interface{} `json:"unknown,omitempty"`
+}
diff --git a/internal/test/issues/issue609/openapi.yaml b/internal/test/issues/issue609/openapi.yaml
new file mode 100644
index 0000000000..d7dae7fdf3
--- /dev/null
+++ b/internal/test/issues/issue609/openapi.yaml
@@ -0,0 +1,11 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: "Referencing an optional field, which has no information about the type it is will generate an `interface{}`, without the 'optional pointer'"
+paths:
+components:
+ schemas:
+ ResponseBody:
+ type: object
+ properties:
+ unknown: {}
diff --git a/internal/test/name_conflict_resolution/config.yaml b/internal/test/name_conflict_resolution/config.yaml
new file mode 100644
index 0000000000..6e173b0a4e
--- /dev/null
+++ b/internal/test/name_conflict_resolution/config.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
+package: nameconflictresolution
+generate:
+ models: true
+ client: true
+output: name_conflict_resolution.gen.go
+output-options:
+ resolve-type-name-collisions: true
diff --git a/internal/test/name_conflict_resolution/doc.go b/internal/test/name_conflict_resolution/doc.go
new file mode 100644
index 0000000000..4d577571ef
--- /dev/null
+++ b/internal/test/name_conflict_resolution/doc.go
@@ -0,0 +1,3 @@
+package nameconflictresolution
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go
new file mode 100644
index 0000000000..1408a086d7
--- /dev/null
+++ b/internal/test/name_conflict_resolution/name_conflict_resolution.gen.go
@@ -0,0 +1,3335 @@
+// Package nameconflictresolution provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package nameconflictresolution
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// Bar defines model for Bar.
+type Bar struct {
+ Value *string `json:"value,omitempty"`
+}
+
+// Bar2 defines model for Bar2.
+type Bar2 struct {
+ Value *float32 `json:"value,omitempty"`
+}
+
+// CreateItemResponse defines model for CreateItemResponse.
+type CreateItemResponse struct {
+ Id *string `json:"id,omitempty"`
+ Name *string `json:"name,omitempty"`
+}
+
+// GetStatusResponse defines model for GetStatusResponse.
+type GetStatusResponse struct {
+ Status *string `json:"status,omitempty"`
+ Timestamp *string `json:"timestamp,omitempty"`
+}
+
+// JsonPatch defines model for JsonPatch.
+type JsonPatch = []struct {
+ Op *string `json:"op,omitempty"`
+ Path *string `json:"path,omitempty"`
+}
+
+// ListItemsResponse defines model for ListItemsResponse.
+type ListItemsResponse = string
+
+// Metadata defines model for Metadata.
+type Metadata = string
+
+// Order defines model for Order.
+type Order struct {
+ Id *string `json:"id,omitempty"`
+ Product *string `json:"product,omitempty"`
+}
+
+// Outcome defines model for Outcome.
+type Outcome struct {
+ Value *string `json:"value,omitempty"`
+}
+
+// Payload defines model for Payload.
+type Payload struct {
+ Content *string `json:"content,omitempty"`
+}
+
+// Pet defines model for Pet.
+type Pet struct {
+ Id *int `json:"id,omitempty"`
+ Name *string `json:"name,omitempty"`
+}
+
+// QueryResponse defines model for QueryResponse.
+type QueryResponse struct {
+ Results *[]string `json:"results,omitempty"`
+}
+
+// Qux defines model for Qux.
+type Qux = CustomQux
+
+// CustomQux defines model for .
+type CustomQux struct {
+ Label *string `json:"label,omitempty"`
+}
+
+// SpecialName defines model for Renamer.
+type SpecialName struct {
+ Label *string `json:"label,omitempty"`
+}
+
+// Resource defines model for Resource.
+type Resource struct {
+ Id *string `json:"id,omitempty"`
+ Name *string `json:"name,omitempty"`
+ Status *string `json:"status,omitempty"`
+}
+
+// ResourceMVO defines model for Resource_MVO.
+type ResourceMVO struct {
+ Name *string `json:"name,omitempty"`
+ Status *string `json:"status,omitempty"`
+}
+
+// Widget defines model for Widget.
+type Widget = string
+
+// Zap defines model for Zap.
+type Zap = string
+
+// BarParameter defines model for Bar.
+type BarParameter = string
+
+// N200ResourcePatchResponseJSONApplicationJSON defines model for 200Resource_Patch.
+type N200ResourcePatchResponseJSONApplicationJSON = Resource
+
+// N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON defines model for 200Resource_Patch.
+type N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON struct {
+ union json.RawMessage
+}
+
+// N200ResourcePatchApplicationJSONPatchPlusJSON1 defines model for .
+type N200ResourcePatchApplicationJSONPatchPlusJSON1 = []Resource
+
+// N200ResourcePatchApplicationJSONPatchPlusJSON2 defines model for .
+type N200ResourcePatchApplicationJSONPatchPlusJSON2 = string
+
+// N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON defines model for 200Resource_Patch.
+type N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON struct {
+ union json.RawMessage
+}
+
+// N200ResourcePatchApplicationJSONPatchQueryPlusJSON1 defines model for .
+type N200ResourcePatchApplicationJSONPatchQueryPlusJSON1 = []Resource
+
+// N200ResourcePatchApplicationJSONPatchQueryPlusJSON2 defines model for .
+type N200ResourcePatchApplicationJSONPatchQueryPlusJSON2 = string
+
+// N200ResourcePatchResponseJSON4ApplicationMergePatchPlusJSON defines model for 200Resource_Patch.
+type N200ResourcePatchResponseJSON4ApplicationMergePatchPlusJSON = Resource
+
+// BarResponse defines model for Bar.
+type BarResponse struct {
+ Value1 *Bar `json:"value1,omitempty"`
+ Value2 *Bar2 `json:"value2,omitempty"`
+}
+
+// OutcomeResult defines model for Outcome.
+type OutcomeResult struct {
+ Result *string `json:"result,omitempty"`
+}
+
+// QuxResponse defines model for Qux.
+type QuxResponse struct {
+ Data *string `json:"data,omitempty"`
+}
+
+// Renamer defines model for Renamer.
+type Renamer struct {
+ Data *string `json:"data,omitempty"`
+}
+
+// ZapResponse defines model for Zap.
+type ZapResponse struct {
+ Result *string `json:"result,omitempty"`
+}
+
+// BarRequestBody defines model for Bar.
+type BarRequestBody struct {
+ Value *int `json:"value,omitempty"`
+}
+
+// OrderRequestBodyJSON defines model for Order.
+type OrderRequestBodyJSON struct {
+ Id *string `json:"id,omitempty"`
+ Product *string `json:"product,omitempty"`
+}
+
+// OrderRequestBodyJSON2 defines model for Order.
+type OrderRequestBodyJSON2 = []struct {
+ Op *string `json:"op,omitempty"`
+ Path *string `json:"path,omitempty"`
+ Value *string `json:"value,omitempty"`
+}
+
+// OrderRequestBodyJSON3 defines model for Order.
+type OrderRequestBodyJSON3 struct {
+ Product *string `json:"product,omitempty"`
+}
+
+// PayloadBody defines model for Payload.
+type PayloadBody struct {
+ Data *string `json:"data,omitempty"`
+}
+
+// PetRequestBody defines model for Pet.
+type PetRequestBody struct {
+ Name *string `json:"name,omitempty"`
+ Species *string `json:"species,omitempty"`
+}
+
+// ResourceMVORequestBodyJSON defines model for Resource_MVO.
+type ResourceMVORequestBodyJSON = ResourceMVO
+
+// ResourceMVORequestBodyJSON2 defines model for Resource_MVO.
+type ResourceMVORequestBodyJSON2 = JsonPatch
+
+// ResourceMVORequestBodyJSON3 defines model for Resource_MVO.
+type ResourceMVORequestBodyJSON3 = ResourceMVO
+
+// PostFooJSONBody defines parameters for PostFoo.
+type PostFooJSONBody struct {
+ Value *int `json:"value,omitempty"`
+}
+
+// PostFooParams defines parameters for PostFoo.
+type PostFooParams struct {
+ Bar *BarParameter `form:"bar,omitempty" json:"bar,omitempty"`
+}
+
+// CreateItemJSONBody defines parameters for CreateItem.
+type CreateItemJSONBody struct {
+ Name *string `json:"name,omitempty"`
+}
+
+// CreateOrderJSONBody defines parameters for CreateOrder.
+type CreateOrderJSONBody struct {
+ Id *string `json:"id,omitempty"`
+ Product *string `json:"product,omitempty"`
+}
+
+// CreateOrderApplicationJSONPatchPlusJSONBody defines parameters for CreateOrder.
+type CreateOrderApplicationJSONPatchPlusJSONBody = []struct {
+ Op *string `json:"op,omitempty"`
+ Path *string `json:"path,omitempty"`
+ Value *string `json:"value,omitempty"`
+}
+
+// CreateOrderApplicationMergePatchPlusJSONBody defines parameters for CreateOrder.
+type CreateOrderApplicationMergePatchPlusJSONBody struct {
+ Product *string `json:"product,omitempty"`
+}
+
+// SendPayloadJSONBody defines parameters for SendPayload.
+type SendPayloadJSONBody struct {
+ Data *string `json:"data,omitempty"`
+}
+
+// CreatePetJSONBody defines parameters for CreatePet.
+type CreatePetJSONBody struct {
+ Name *string `json:"name,omitempty"`
+ Species *string `json:"species,omitempty"`
+}
+
+// QueryJSONBody defines parameters for Query.
+type QueryJSONBody struct {
+ Q *string `json:"q,omitempty"`
+}
+
+// PatchResource200ApplicationJSONPatchPlusJSONResponseBody1 defines parameters for PatchResource.
+type PatchResource200ApplicationJSONPatchPlusJSONResponseBody1 = []Resource
+
+// PatchResource200ApplicationJSONPatchPlusJSONResponseBody2 defines parameters for PatchResource.
+type PatchResource200ApplicationJSONPatchPlusJSONResponseBody2 = string
+
+// PatchResource200ApplicationJSONPatchQueryPlusJSONResponseBody1 defines parameters for PatchResource.
+type PatchResource200ApplicationJSONPatchQueryPlusJSONResponseBody1 = []Resource
+
+// PatchResource200ApplicationJSONPatchQueryPlusJSONResponseBody2 defines parameters for PatchResource.
+type PatchResource200ApplicationJSONPatchQueryPlusJSONResponseBody2 = string
+
+// PostFooJSONRequestBody defines body for PostFoo for application/json ContentType.
+type PostFooJSONRequestBody PostFooJSONBody
+
+// CreateItemJSONRequestBody defines body for CreateItem for application/json ContentType.
+type CreateItemJSONRequestBody CreateItemJSONBody
+
+// CreateOrderJSONRequestBody defines body for CreateOrder for application/json ContentType.
+type CreateOrderJSONRequestBody CreateOrderJSONBody
+
+// CreateOrderApplicationJSONPatchPlusJSONRequestBody defines body for CreateOrder for application/json-patch+json ContentType.
+type CreateOrderApplicationJSONPatchPlusJSONRequestBody = CreateOrderApplicationJSONPatchPlusJSONBody
+
+// CreateOrderApplicationMergePatchPlusJSONRequestBody defines body for CreateOrder for application/merge-patch+json ContentType.
+type CreateOrderApplicationMergePatchPlusJSONRequestBody CreateOrderApplicationMergePatchPlusJSONBody
+
+// PostOutcomeJSONRequestBody defines body for PostOutcome for application/json ContentType.
+type PostOutcomeJSONRequestBody = Outcome
+
+// SendPayloadJSONRequestBody defines body for SendPayload for application/json ContentType.
+type SendPayloadJSONRequestBody SendPayloadJSONBody
+
+// CreatePetJSONRequestBody defines body for CreatePet for application/json ContentType.
+type CreatePetJSONRequestBody CreatePetJSONBody
+
+// QueryJSONRequestBody defines body for Query for application/json ContentType.
+type QueryJSONRequestBody QueryJSONBody
+
+// PostQuxJSONRequestBody defines body for PostQux for application/json ContentType.
+type PostQuxJSONRequestBody = Qux
+
+// PostRenamedSchemaJSONRequestBody defines body for PostRenamedSchema for application/json ContentType.
+type PostRenamedSchemaJSONRequestBody = SpecialName
+
+// PatchResourceJSONRequestBody defines body for PatchResource for application/json ContentType.
+type PatchResourceJSONRequestBody = ResourceMVO
+
+// PatchResourceApplicationJSONPatchPlusJSONRequestBody defines body for PatchResource for application/json-patch+json ContentType.
+type PatchResourceApplicationJSONPatchPlusJSONRequestBody = JsonPatch
+
+// PatchResourceApplicationMergePatchPlusJSONRequestBody defines body for PatchResource for application/merge-patch+json ContentType.
+type PatchResourceApplicationMergePatchPlusJSONRequestBody = ResourceMVO
+
+// PostZapJSONRequestBody defines body for PostZap for application/json ContentType.
+type PostZapJSONRequestBody = Zap
+
+// AsResource returns the union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON as a Resource
+func (t N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) AsResource() (Resource, error) {
+ var body Resource
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromResource overwrites any union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON as the provided Resource
+func (t *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) FromResource(v Resource) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeResource performs a merge with any union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON, using the provided Resource
+func (t *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) MergeResource(v Resource) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsN200ResourcePatchApplicationJSONPatchPlusJSON1 returns the union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON as a N200ResourcePatchApplicationJSONPatchPlusJSON1
+func (t N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) AsN200ResourcePatchApplicationJSONPatchPlusJSON1() (N200ResourcePatchApplicationJSONPatchPlusJSON1, error) {
+ var body N200ResourcePatchApplicationJSONPatchPlusJSON1
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromN200ResourcePatchApplicationJSONPatchPlusJSON1 overwrites any union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON as the provided N200ResourcePatchApplicationJSONPatchPlusJSON1
+func (t *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) FromN200ResourcePatchApplicationJSONPatchPlusJSON1(v N200ResourcePatchApplicationJSONPatchPlusJSON1) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeN200ResourcePatchApplicationJSONPatchPlusJSON1 performs a merge with any union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON, using the provided N200ResourcePatchApplicationJSONPatchPlusJSON1
+func (t *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) MergeN200ResourcePatchApplicationJSONPatchPlusJSON1(v N200ResourcePatchApplicationJSONPatchPlusJSON1) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsN200ResourcePatchApplicationJSONPatchPlusJSON2 returns the union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON as a N200ResourcePatchApplicationJSONPatchPlusJSON2
+func (t N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) AsN200ResourcePatchApplicationJSONPatchPlusJSON2() (N200ResourcePatchApplicationJSONPatchPlusJSON2, error) {
+ var body N200ResourcePatchApplicationJSONPatchPlusJSON2
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromN200ResourcePatchApplicationJSONPatchPlusJSON2 overwrites any union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON as the provided N200ResourcePatchApplicationJSONPatchPlusJSON2
+func (t *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) FromN200ResourcePatchApplicationJSONPatchPlusJSON2(v N200ResourcePatchApplicationJSONPatchPlusJSON2) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeN200ResourcePatchApplicationJSONPatchPlusJSON2 performs a merge with any union data inside the N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON, using the provided N200ResourcePatchApplicationJSONPatchPlusJSON2
+func (t *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) MergeN200ResourcePatchApplicationJSONPatchPlusJSON2(v N200ResourcePatchApplicationJSONPatchPlusJSON2) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// AsResource returns the union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON as a Resource
+func (t N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) AsResource() (Resource, error) {
+ var body Resource
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromResource overwrites any union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON as the provided Resource
+func (t *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) FromResource(v Resource) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeResource performs a merge with any union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON, using the provided Resource
+func (t *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) MergeResource(v Resource) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsN200ResourcePatchApplicationJSONPatchQueryPlusJSON1 returns the union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON as a N200ResourcePatchApplicationJSONPatchQueryPlusJSON1
+func (t N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) AsN200ResourcePatchApplicationJSONPatchQueryPlusJSON1() (N200ResourcePatchApplicationJSONPatchQueryPlusJSON1, error) {
+ var body N200ResourcePatchApplicationJSONPatchQueryPlusJSON1
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromN200ResourcePatchApplicationJSONPatchQueryPlusJSON1 overwrites any union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON as the provided N200ResourcePatchApplicationJSONPatchQueryPlusJSON1
+func (t *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) FromN200ResourcePatchApplicationJSONPatchQueryPlusJSON1(v N200ResourcePatchApplicationJSONPatchQueryPlusJSON1) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeN200ResourcePatchApplicationJSONPatchQueryPlusJSON1 performs a merge with any union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON, using the provided N200ResourcePatchApplicationJSONPatchQueryPlusJSON1
+func (t *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) MergeN200ResourcePatchApplicationJSONPatchQueryPlusJSON1(v N200ResourcePatchApplicationJSONPatchQueryPlusJSON1) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsN200ResourcePatchApplicationJSONPatchQueryPlusJSON2 returns the union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON as a N200ResourcePatchApplicationJSONPatchQueryPlusJSON2
+func (t N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) AsN200ResourcePatchApplicationJSONPatchQueryPlusJSON2() (N200ResourcePatchApplicationJSONPatchQueryPlusJSON2, error) {
+ var body N200ResourcePatchApplicationJSONPatchQueryPlusJSON2
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromN200ResourcePatchApplicationJSONPatchQueryPlusJSON2 overwrites any union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON as the provided N200ResourcePatchApplicationJSONPatchQueryPlusJSON2
+func (t *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) FromN200ResourcePatchApplicationJSONPatchQueryPlusJSON2(v N200ResourcePatchApplicationJSONPatchQueryPlusJSON2) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeN200ResourcePatchApplicationJSONPatchQueryPlusJSON2 performs a merge with any union data inside the N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON, using the provided N200ResourcePatchApplicationJSONPatchQueryPlusJSON2
+func (t *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) MergeN200ResourcePatchApplicationJSONPatchQueryPlusJSON2(v N200ResourcePatchApplicationJSONPatchQueryPlusJSON2) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // ListEntities request
+ ListEntities(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // PostFooWithBody request with any body
+ PostFooWithBody(ctx context.Context, params *PostFooParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PostFoo(ctx context.Context, params *PostFooParams, body PostFooJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // ListItems request
+ ListItems(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // CreateItemWithBody request with any body
+ CreateItemWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ CreateItem(ctx context.Context, body CreateItemJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // CreateOrderWithBody request with any body
+ CreateOrderWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ CreateOrder(ctx context.Context, body CreateOrderJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ CreateOrderWithApplicationJSONPatchPlusJSONBody(ctx context.Context, body CreateOrderApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ CreateOrderWithApplicationMergePatchPlusJSONBody(ctx context.Context, body CreateOrderApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // GetOutcome request
+ GetOutcome(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // PostOutcomeWithBody request with any body
+ PostOutcomeWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PostOutcome(ctx context.Context, body PostOutcomeJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // SendPayloadWithBody request with any body
+ SendPayloadWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ SendPayload(ctx context.Context, body SendPayloadJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // CreatePetWithBody request with any body
+ CreatePetWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ CreatePet(ctx context.Context, body CreatePetJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // QueryWithBody request with any body
+ QueryWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ Query(ctx context.Context, body QueryJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // GetQux request
+ GetQux(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // PostQuxWithBody request with any body
+ PostQuxWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PostQux(ctx context.Context, body PostQuxJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // GetRenamedSchema request
+ GetRenamedSchema(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // PostRenamedSchemaWithBody request with any body
+ PostRenamedSchemaWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PostRenamedSchema(ctx context.Context, body PostRenamedSchemaJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // PatchResourceWithBody request with any body
+ PatchResourceWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PatchResource(ctx context.Context, id string, body PatchResourceJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PatchResourceWithApplicationJSONPatchPlusJSONBody(ctx context.Context, id string, body PatchResourceApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PatchResourceWithApplicationMergePatchPlusJSONBody(ctx context.Context, id string, body PatchResourceApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // GetStatus request
+ GetStatus(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // GetZap request
+ GetZap(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // PostZapWithBody request with any body
+ PostZapWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ PostZap(ctx context.Context, body PostZapJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) ListEntities(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewListEntitiesRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostFooWithBody(ctx context.Context, params *PostFooParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostFooRequestWithBody(c.Server, params, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostFoo(ctx context.Context, params *PostFooParams, body PostFooJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostFooRequest(c.Server, params, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) ListItems(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewListItemsRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) CreateItemWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewCreateItemRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) CreateItem(ctx context.Context, body CreateItemJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewCreateItemRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) CreateOrderWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewCreateOrderRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) CreateOrder(ctx context.Context, body CreateOrderJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewCreateOrderRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) CreateOrderWithApplicationJSONPatchPlusJSONBody(ctx context.Context, body CreateOrderApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewCreateOrderRequestWithApplicationJSONPatchPlusJSONBody(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) CreateOrderWithApplicationMergePatchPlusJSONBody(ctx context.Context, body CreateOrderApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewCreateOrderRequestWithApplicationMergePatchPlusJSONBody(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) GetOutcome(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetOutcomeRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostOutcomeWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostOutcomeRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostOutcome(ctx context.Context, body PostOutcomeJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostOutcomeRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) SendPayloadWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewSendPayloadRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) SendPayload(ctx context.Context, body SendPayloadJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewSendPayloadRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) CreatePetWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewCreatePetRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) CreatePet(ctx context.Context, body CreatePetJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewCreatePetRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) QueryWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewQueryRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) Query(ctx context.Context, body QueryJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewQueryRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) GetQux(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetQuxRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostQuxWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostQuxRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostQux(ctx context.Context, body PostQuxJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostQuxRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) GetRenamedSchema(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetRenamedSchemaRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostRenamedSchemaWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostRenamedSchemaRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostRenamedSchema(ctx context.Context, body PostRenamedSchemaJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostRenamedSchemaRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PatchResourceWithBody(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPatchResourceRequestWithBody(c.Server, id, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PatchResource(ctx context.Context, id string, body PatchResourceJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPatchResourceRequest(c.Server, id, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PatchResourceWithApplicationJSONPatchPlusJSONBody(ctx context.Context, id string, body PatchResourceApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPatchResourceRequestWithApplicationJSONPatchPlusJSONBody(c.Server, id, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PatchResourceWithApplicationMergePatchPlusJSONBody(ctx context.Context, id string, body PatchResourceApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPatchResourceRequestWithApplicationMergePatchPlusJSONBody(c.Server, id, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) GetStatus(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetStatusRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) GetZap(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetZapRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostZapWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostZapRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) PostZap(ctx context.Context, body PostZapJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewPostZapRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewListEntitiesRequest generates requests for ListEntities
+func NewListEntitiesRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/entities")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewPostFooRequest calls the generic PostFoo builder with application/json body
+func NewPostFooRequest(server string, params *PostFooParams, body PostFooJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPostFooRequestWithBody(server, params, "application/json", bodyReader)
+}
+
+// NewPostFooRequestWithBody generates requests for PostFoo with any type of body
+func NewPostFooRequestWithBody(server string, params *PostFooParams, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/foo")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ if params != nil {
+ // queryValues collects non-styled parameters (passthrough, JSON)
+ // that are safe to round-trip through url.Values.Encode().
+ queryValues := queryURL.Query()
+ // rawQueryFragments collects pre-encoded query fragments from
+ // styled parameters, preserving literal commas as delimiters
+ // per the OpenAPI spec (e.g. "color=blue,black,brown").
+ var rawQueryFragments []string
+
+ if params.Bar != nil {
+
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "bar", *params.Bar, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "string", Format: ""}); err != nil {
+ return nil, err
+ } else {
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
+ }
+ }
+
+ }
+
+ if encoded := queryValues.Encode(); encoded != "" {
+ rawQueryFragments = append(rawQueryFragments, encoded)
+ }
+ queryURL.RawQuery = strings.Join(rawQueryFragments, "&")
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewListItemsRequest generates requests for ListItems
+func NewListItemsRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/items")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewCreateItemRequest calls the generic CreateItem builder with application/json body
+func NewCreateItemRequest(server string, body CreateItemJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewCreateItemRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewCreateItemRequestWithBody generates requests for CreateItem with any type of body
+func NewCreateItemRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/items")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewCreateOrderRequest calls the generic CreateOrder builder with application/json body
+func NewCreateOrderRequest(server string, body CreateOrderJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewCreateOrderRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewCreateOrderRequestWithApplicationJSONPatchPlusJSONBody calls the generic CreateOrder builder with application/json-patch+json body
+func NewCreateOrderRequestWithApplicationJSONPatchPlusJSONBody(server string, body CreateOrderApplicationJSONPatchPlusJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewCreateOrderRequestWithBody(server, "application/json-patch+json", bodyReader)
+}
+
+// NewCreateOrderRequestWithApplicationMergePatchPlusJSONBody calls the generic CreateOrder builder with application/merge-patch+json body
+func NewCreateOrderRequestWithApplicationMergePatchPlusJSONBody(server string, body CreateOrderApplicationMergePatchPlusJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewCreateOrderRequestWithBody(server, "application/merge-patch+json", bodyReader)
+}
+
+// NewCreateOrderRequestWithBody generates requests for CreateOrder with any type of body
+func NewCreateOrderRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/orders")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewGetOutcomeRequest generates requests for GetOutcome
+func NewGetOutcomeRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/outcome")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewPostOutcomeRequest calls the generic PostOutcome builder with application/json body
+func NewPostOutcomeRequest(server string, body PostOutcomeJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPostOutcomeRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewPostOutcomeRequestWithBody generates requests for PostOutcome with any type of body
+func NewPostOutcomeRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/outcome")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewSendPayloadRequest calls the generic SendPayload builder with application/json body
+func NewSendPayloadRequest(server string, body SendPayloadJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewSendPayloadRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewSendPayloadRequestWithBody generates requests for SendPayload with any type of body
+func NewSendPayloadRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/payload")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewCreatePetRequest calls the generic CreatePet builder with application/json body
+func NewCreatePetRequest(server string, body CreatePetJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewCreatePetRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewCreatePetRequestWithBody generates requests for CreatePet with any type of body
+func NewCreatePetRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/pets")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewQueryRequest calls the generic Query builder with application/json body
+func NewQueryRequest(server string, body QueryJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewQueryRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewQueryRequestWithBody generates requests for Query with any type of body
+func NewQueryRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/query")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewGetQuxRequest generates requests for GetQux
+func NewGetQuxRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/qux")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewPostQuxRequest calls the generic PostQux builder with application/json body
+func NewPostQuxRequest(server string, body PostQuxJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPostQuxRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewPostQuxRequestWithBody generates requests for PostQux with any type of body
+func NewPostQuxRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/qux")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewGetRenamedSchemaRequest generates requests for GetRenamedSchema
+func NewGetRenamedSchemaRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/renamed-schema")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewPostRenamedSchemaRequest calls the generic PostRenamedSchema builder with application/json body
+func NewPostRenamedSchemaRequest(server string, body PostRenamedSchemaJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPostRenamedSchemaRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewPostRenamedSchemaRequestWithBody generates requests for PostRenamedSchema with any type of body
+func NewPostRenamedSchemaRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/renamed-schema")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewPatchResourceRequest calls the generic PatchResource builder with application/json body
+func NewPatchResourceRequest(server string, id string, body PatchResourceJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPatchResourceRequestWithBody(server, id, "application/json", bodyReader)
+}
+
+// NewPatchResourceRequestWithApplicationJSONPatchPlusJSONBody calls the generic PatchResource builder with application/json-patch+json body
+func NewPatchResourceRequestWithApplicationJSONPatchPlusJSONBody(server string, id string, body PatchResourceApplicationJSONPatchPlusJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPatchResourceRequestWithBody(server, id, "application/json-patch+json", bodyReader)
+}
+
+// NewPatchResourceRequestWithApplicationMergePatchPlusJSONBody calls the generic PatchResource builder with application/merge-patch+json body
+func NewPatchResourceRequestWithApplicationMergePatchPlusJSONBody(server string, id string, body PatchResourceApplicationMergePatchPlusJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPatchResourceRequestWithBody(server, id, "application/merge-patch+json", bodyReader)
+}
+
+// NewPatchResourceRequestWithBody generates requests for PatchResource with any type of body
+func NewPatchResourceRequestWithBody(server string, id string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "id", id, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/resources/%s", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPatch, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewGetStatusRequest generates requests for GetStatus
+func NewGetStatusRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/status")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewGetZapRequest generates requests for GetZap
+func NewGetZapRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/zap")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewPostZapRequest calls the generic PostZap builder with application/json body
+func NewPostZapRequest(server string, body PostZapJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewPostZapRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewPostZapRequestWithBody generates requests for PostZap with any type of body
+func NewPostZapRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/zap")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // ListEntitiesWithResponse request
+ ListEntitiesWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListEntitiesResponse, error)
+
+ // PostFooWithBodyWithResponse request with any body
+ PostFooWithBodyWithResponse(ctx context.Context, params *PostFooParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostFooResponse, error)
+
+ PostFooWithResponse(ctx context.Context, params *PostFooParams, body PostFooJSONRequestBody, reqEditors ...RequestEditorFn) (*PostFooResponse, error)
+
+ // ListItemsWithResponse request
+ ListItemsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListItemsResponse2, error)
+
+ // CreateItemWithBodyWithResponse request with any body
+ CreateItemWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateItemResponse2, error)
+
+ CreateItemWithResponse(ctx context.Context, body CreateItemJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateItemResponse2, error)
+
+ // CreateOrderWithBodyWithResponse request with any body
+ CreateOrderWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error)
+
+ CreateOrderWithResponse(ctx context.Context, body CreateOrderJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error)
+
+ CreateOrderWithApplicationJSONPatchPlusJSONBodyWithResponse(ctx context.Context, body CreateOrderApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error)
+
+ CreateOrderWithApplicationMergePatchPlusJSONBodyWithResponse(ctx context.Context, body CreateOrderApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error)
+
+ // GetOutcomeWithResponse request
+ GetOutcomeWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetOutcomeResponse, error)
+
+ // PostOutcomeWithBodyWithResponse request with any body
+ PostOutcomeWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostOutcomeResponse, error)
+
+ PostOutcomeWithResponse(ctx context.Context, body PostOutcomeJSONRequestBody, reqEditors ...RequestEditorFn) (*PostOutcomeResponse, error)
+
+ // SendPayloadWithBodyWithResponse request with any body
+ SendPayloadWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SendPayloadResponse, error)
+
+ SendPayloadWithResponse(ctx context.Context, body SendPayloadJSONRequestBody, reqEditors ...RequestEditorFn) (*SendPayloadResponse, error)
+
+ // CreatePetWithBodyWithResponse request with any body
+ CreatePetWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreatePetResponse, error)
+
+ CreatePetWithResponse(ctx context.Context, body CreatePetJSONRequestBody, reqEditors ...RequestEditorFn) (*CreatePetResponse, error)
+
+ // QueryWithBodyWithResponse request with any body
+ QueryWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*QueryResponse2, error)
+
+ QueryWithResponse(ctx context.Context, body QueryJSONRequestBody, reqEditors ...RequestEditorFn) (*QueryResponse2, error)
+
+ // GetQuxWithResponse request
+ GetQuxWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetQuxResponse, error)
+
+ // PostQuxWithBodyWithResponse request with any body
+ PostQuxWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostQuxResponse, error)
+
+ PostQuxWithResponse(ctx context.Context, body PostQuxJSONRequestBody, reqEditors ...RequestEditorFn) (*PostQuxResponse, error)
+
+ // GetRenamedSchemaWithResponse request
+ GetRenamedSchemaWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetRenamedSchemaResponse, error)
+
+ // PostRenamedSchemaWithBodyWithResponse request with any body
+ PostRenamedSchemaWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostRenamedSchemaResponse, error)
+
+ PostRenamedSchemaWithResponse(ctx context.Context, body PostRenamedSchemaJSONRequestBody, reqEditors ...RequestEditorFn) (*PostRenamedSchemaResponse, error)
+
+ // PatchResourceWithBodyWithResponse request with any body
+ PatchResourceWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error)
+
+ PatchResourceWithResponse(ctx context.Context, id string, body PatchResourceJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error)
+
+ PatchResourceWithApplicationJSONPatchPlusJSONBodyWithResponse(ctx context.Context, id string, body PatchResourceApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error)
+
+ PatchResourceWithApplicationMergePatchPlusJSONBodyWithResponse(ctx context.Context, id string, body PatchResourceApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error)
+
+ // GetStatusWithResponse request
+ GetStatusWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetStatusResponse2, error)
+
+ // GetZapWithResponse request
+ GetZapWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetZapResponse, error)
+
+ // PostZapWithBodyWithResponse request with any body
+ PostZapWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostZapResponse, error)
+
+ PostZapWithResponse(ctx context.Context, body PostZapJSONRequestBody, reqEditors ...RequestEditorFn) (*PostZapResponse, error)
+}
+
+type ListEntitiesResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *struct {
+ Data *[]Widget `json:"data,omitempty"`
+ Metadata *Metadata `json:"metadata,omitempty"`
+ }
+}
+
+// GetJSON200 returns JSON200
+func (r ListEntitiesResponse) GetJSON200() *struct {
+ Data *[]Widget `json:"data,omitempty"`
+ Metadata *Metadata `json:"metadata,omitempty"`
+} {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r ListEntitiesResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r ListEntitiesResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r ListEntitiesResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r ListEntitiesResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type PostFooResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *BarResponse
+}
+
+// GetJSON200 returns JSON200
+func (r PostFooResponse) GetJSON200() *BarResponse {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r PostFooResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r PostFooResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PostFooResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostFooResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type ListItemsResponse2 struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *ListItemsResponse
+}
+
+// GetJSON200 returns JSON200
+func (r ListItemsResponse2) GetJSON200() *ListItemsResponse {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r ListItemsResponse2) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r ListItemsResponse2) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r ListItemsResponse2) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r ListItemsResponse2) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type CreateItemResponse2 struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *CreateItemResponse
+}
+
+// GetJSON200 returns JSON200
+func (r CreateItemResponse2) GetJSON200() *CreateItemResponse {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r CreateItemResponse2) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r CreateItemResponse2) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r CreateItemResponse2) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r CreateItemResponse2) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type CreateOrderResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Order
+}
+
+// GetJSON200 returns JSON200
+func (r CreateOrderResponse) GetJSON200() *Order {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r CreateOrderResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r CreateOrderResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r CreateOrderResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r CreateOrderResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetOutcomeResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *OutcomeResult
+}
+
+// GetJSON200 returns JSON200
+func (r GetOutcomeResponse) GetJSON200() *OutcomeResult {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetOutcomeResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetOutcomeResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetOutcomeResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetOutcomeResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type PostOutcomeResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r PostOutcomeResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r PostOutcomeResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PostOutcomeResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostOutcomeResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type SendPayloadResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Payload
+}
+
+// GetJSON200 returns JSON200
+func (r SendPayloadResponse) GetJSON200() *Payload {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r SendPayloadResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r SendPayloadResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r SendPayloadResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r SendPayloadResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type CreatePetResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Pet
+}
+
+// GetJSON200 returns JSON200
+func (r CreatePetResponse) GetJSON200() *Pet {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r CreatePetResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r CreatePetResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r CreatePetResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r CreatePetResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type QueryResponse2 struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *QueryResponse
+}
+
+// GetJSON200 returns JSON200
+func (r QueryResponse2) GetJSON200() *QueryResponse {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r QueryResponse2) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r QueryResponse2) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r QueryResponse2) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r QueryResponse2) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetQuxResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *QuxResponse
+}
+
+// GetJSON200 returns JSON200
+func (r GetQuxResponse) GetJSON200() *QuxResponse {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetQuxResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetQuxResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetQuxResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetQuxResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type PostQuxResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r PostQuxResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r PostQuxResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PostQuxResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostQuxResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetRenamedSchemaResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Renamer
+}
+
+// GetJSON200 returns JSON200
+func (r GetRenamedSchemaResponse) GetJSON200() *Renamer {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetRenamedSchemaResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetRenamedSchemaResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetRenamedSchemaResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetRenamedSchemaResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type PostRenamedSchemaResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r PostRenamedSchemaResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r PostRenamedSchemaResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PostRenamedSchemaResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostRenamedSchemaResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type PatchResourceResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *N200ResourcePatchResponseJSONApplicationJSON
+ ApplicationjsonPatchJSON200 *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON
+ ApplicationjsonPatchQueryJSON200 *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON
+ ApplicationmergePatchJSON200 *N200ResourcePatchResponseJSON4ApplicationMergePatchPlusJSON
+}
+
+// GetJSON200 returns JSON200
+func (r PatchResourceResponse) GetJSON200() *N200ResourcePatchResponseJSONApplicationJSON {
+ return r.JSON200
+}
+
+// GetApplicationjsonPatchJSON200 returns ApplicationjsonPatchJSON200
+func (r PatchResourceResponse) GetApplicationjsonPatchJSON200() *N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON {
+ return r.ApplicationjsonPatchJSON200
+}
+
+// GetApplicationjsonPatchQueryJSON200 returns ApplicationjsonPatchQueryJSON200
+func (r PatchResourceResponse) GetApplicationjsonPatchQueryJSON200() *N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON {
+ return r.ApplicationjsonPatchQueryJSON200
+}
+
+// GetApplicationmergePatchJSON200 returns ApplicationmergePatchJSON200
+func (r PatchResourceResponse) GetApplicationmergePatchJSON200() *N200ResourcePatchResponseJSON4ApplicationMergePatchPlusJSON {
+ return r.ApplicationmergePatchJSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r PatchResourceResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r PatchResourceResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PatchResourceResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PatchResourceResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetStatusResponse2 struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *GetStatusResponse
+}
+
+// GetJSON200 returns JSON200
+func (r GetStatusResponse2) GetJSON200() *GetStatusResponse {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetStatusResponse2) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetStatusResponse2) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetStatusResponse2) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetStatusResponse2) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetZapResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *ZapResponse
+}
+
+// GetJSON200 returns JSON200
+func (r GetZapResponse) GetJSON200() *ZapResponse {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetZapResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetZapResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetZapResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetZapResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type PostZapResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r PostZapResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r PostZapResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PostZapResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r PostZapResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// ListEntitiesWithResponse request returning *ListEntitiesResponse
+func (c *ClientWithResponses) ListEntitiesWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListEntitiesResponse, error) {
+ rsp, err := c.ListEntities(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseListEntitiesResponse(rsp)
+}
+
+// PostFooWithBodyWithResponse request with arbitrary body returning *PostFooResponse
+func (c *ClientWithResponses) PostFooWithBodyWithResponse(ctx context.Context, params *PostFooParams, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostFooResponse, error) {
+ rsp, err := c.PostFooWithBody(ctx, params, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostFooResponse(rsp)
+}
+
+func (c *ClientWithResponses) PostFooWithResponse(ctx context.Context, params *PostFooParams, body PostFooJSONRequestBody, reqEditors ...RequestEditorFn) (*PostFooResponse, error) {
+ rsp, err := c.PostFoo(ctx, params, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostFooResponse(rsp)
+}
+
+// ListItemsWithResponse request returning *ListItemsResponse2
+func (c *ClientWithResponses) ListItemsWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*ListItemsResponse2, error) {
+ rsp, err := c.ListItems(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseListItemsResponse2(rsp)
+}
+
+// CreateItemWithBodyWithResponse request with arbitrary body returning *CreateItemResponse2
+func (c *ClientWithResponses) CreateItemWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateItemResponse2, error) {
+ rsp, err := c.CreateItemWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseCreateItemResponse2(rsp)
+}
+
+func (c *ClientWithResponses) CreateItemWithResponse(ctx context.Context, body CreateItemJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateItemResponse2, error) {
+ rsp, err := c.CreateItem(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseCreateItemResponse2(rsp)
+}
+
+// CreateOrderWithBodyWithResponse request with arbitrary body returning *CreateOrderResponse
+func (c *ClientWithResponses) CreateOrderWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error) {
+ rsp, err := c.CreateOrderWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseCreateOrderResponse(rsp)
+}
+
+func (c *ClientWithResponses) CreateOrderWithResponse(ctx context.Context, body CreateOrderJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error) {
+ rsp, err := c.CreateOrder(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseCreateOrderResponse(rsp)
+}
+
+func (c *ClientWithResponses) CreateOrderWithApplicationJSONPatchPlusJSONBodyWithResponse(ctx context.Context, body CreateOrderApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error) {
+ rsp, err := c.CreateOrderWithApplicationJSONPatchPlusJSONBody(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseCreateOrderResponse(rsp)
+}
+
+func (c *ClientWithResponses) CreateOrderWithApplicationMergePatchPlusJSONBodyWithResponse(ctx context.Context, body CreateOrderApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*CreateOrderResponse, error) {
+ rsp, err := c.CreateOrderWithApplicationMergePatchPlusJSONBody(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseCreateOrderResponse(rsp)
+}
+
+// GetOutcomeWithResponse request returning *GetOutcomeResponse
+func (c *ClientWithResponses) GetOutcomeWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetOutcomeResponse, error) {
+ rsp, err := c.GetOutcome(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetOutcomeResponse(rsp)
+}
+
+// PostOutcomeWithBodyWithResponse request with arbitrary body returning *PostOutcomeResponse
+func (c *ClientWithResponses) PostOutcomeWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostOutcomeResponse, error) {
+ rsp, err := c.PostOutcomeWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostOutcomeResponse(rsp)
+}
+
+func (c *ClientWithResponses) PostOutcomeWithResponse(ctx context.Context, body PostOutcomeJSONRequestBody, reqEditors ...RequestEditorFn) (*PostOutcomeResponse, error) {
+ rsp, err := c.PostOutcome(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostOutcomeResponse(rsp)
+}
+
+// SendPayloadWithBodyWithResponse request with arbitrary body returning *SendPayloadResponse
+func (c *ClientWithResponses) SendPayloadWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*SendPayloadResponse, error) {
+ rsp, err := c.SendPayloadWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseSendPayloadResponse(rsp)
+}
+
+func (c *ClientWithResponses) SendPayloadWithResponse(ctx context.Context, body SendPayloadJSONRequestBody, reqEditors ...RequestEditorFn) (*SendPayloadResponse, error) {
+ rsp, err := c.SendPayload(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseSendPayloadResponse(rsp)
+}
+
+// CreatePetWithBodyWithResponse request with arbitrary body returning *CreatePetResponse
+func (c *ClientWithResponses) CreatePetWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*CreatePetResponse, error) {
+ rsp, err := c.CreatePetWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseCreatePetResponse(rsp)
+}
+
+func (c *ClientWithResponses) CreatePetWithResponse(ctx context.Context, body CreatePetJSONRequestBody, reqEditors ...RequestEditorFn) (*CreatePetResponse, error) {
+ rsp, err := c.CreatePet(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseCreatePetResponse(rsp)
+}
+
+// QueryWithBodyWithResponse request with arbitrary body returning *QueryResponse2
+func (c *ClientWithResponses) QueryWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*QueryResponse2, error) {
+ rsp, err := c.QueryWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseQueryResponse2(rsp)
+}
+
+func (c *ClientWithResponses) QueryWithResponse(ctx context.Context, body QueryJSONRequestBody, reqEditors ...RequestEditorFn) (*QueryResponse2, error) {
+ rsp, err := c.Query(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseQueryResponse2(rsp)
+}
+
+// GetQuxWithResponse request returning *GetQuxResponse
+func (c *ClientWithResponses) GetQuxWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetQuxResponse, error) {
+ rsp, err := c.GetQux(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetQuxResponse(rsp)
+}
+
+// PostQuxWithBodyWithResponse request with arbitrary body returning *PostQuxResponse
+func (c *ClientWithResponses) PostQuxWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostQuxResponse, error) {
+ rsp, err := c.PostQuxWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostQuxResponse(rsp)
+}
+
+func (c *ClientWithResponses) PostQuxWithResponse(ctx context.Context, body PostQuxJSONRequestBody, reqEditors ...RequestEditorFn) (*PostQuxResponse, error) {
+ rsp, err := c.PostQux(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostQuxResponse(rsp)
+}
+
+// GetRenamedSchemaWithResponse request returning *GetRenamedSchemaResponse
+func (c *ClientWithResponses) GetRenamedSchemaWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetRenamedSchemaResponse, error) {
+ rsp, err := c.GetRenamedSchema(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetRenamedSchemaResponse(rsp)
+}
+
+// PostRenamedSchemaWithBodyWithResponse request with arbitrary body returning *PostRenamedSchemaResponse
+func (c *ClientWithResponses) PostRenamedSchemaWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostRenamedSchemaResponse, error) {
+ rsp, err := c.PostRenamedSchemaWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostRenamedSchemaResponse(rsp)
+}
+
+func (c *ClientWithResponses) PostRenamedSchemaWithResponse(ctx context.Context, body PostRenamedSchemaJSONRequestBody, reqEditors ...RequestEditorFn) (*PostRenamedSchemaResponse, error) {
+ rsp, err := c.PostRenamedSchema(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostRenamedSchemaResponse(rsp)
+}
+
+// PatchResourceWithBodyWithResponse request with arbitrary body returning *PatchResourceResponse
+func (c *ClientWithResponses) PatchResourceWithBodyWithResponse(ctx context.Context, id string, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error) {
+ rsp, err := c.PatchResourceWithBody(ctx, id, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePatchResourceResponse(rsp)
+}
+
+func (c *ClientWithResponses) PatchResourceWithResponse(ctx context.Context, id string, body PatchResourceJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error) {
+ rsp, err := c.PatchResource(ctx, id, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePatchResourceResponse(rsp)
+}
+
+func (c *ClientWithResponses) PatchResourceWithApplicationJSONPatchPlusJSONBodyWithResponse(ctx context.Context, id string, body PatchResourceApplicationJSONPatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error) {
+ rsp, err := c.PatchResourceWithApplicationJSONPatchPlusJSONBody(ctx, id, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePatchResourceResponse(rsp)
+}
+
+func (c *ClientWithResponses) PatchResourceWithApplicationMergePatchPlusJSONBodyWithResponse(ctx context.Context, id string, body PatchResourceApplicationMergePatchPlusJSONRequestBody, reqEditors ...RequestEditorFn) (*PatchResourceResponse, error) {
+ rsp, err := c.PatchResourceWithApplicationMergePatchPlusJSONBody(ctx, id, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePatchResourceResponse(rsp)
+}
+
+// GetStatusWithResponse request returning *GetStatusResponse2
+func (c *ClientWithResponses) GetStatusWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetStatusResponse2, error) {
+ rsp, err := c.GetStatus(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetStatusResponse2(rsp)
+}
+
+// GetZapWithResponse request returning *GetZapResponse
+func (c *ClientWithResponses) GetZapWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetZapResponse, error) {
+ rsp, err := c.GetZap(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetZapResponse(rsp)
+}
+
+// PostZapWithBodyWithResponse request with arbitrary body returning *PostZapResponse
+func (c *ClientWithResponses) PostZapWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostZapResponse, error) {
+ rsp, err := c.PostZapWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostZapResponse(rsp)
+}
+
+func (c *ClientWithResponses) PostZapWithResponse(ctx context.Context, body PostZapJSONRequestBody, reqEditors ...RequestEditorFn) (*PostZapResponse, error) {
+ rsp, err := c.PostZap(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParsePostZapResponse(rsp)
+}
+
+// ParseListEntitiesResponse parses an HTTP response from a ListEntitiesWithResponse call
+func ParseListEntitiesResponse(rsp *http.Response) (*ListEntitiesResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &ListEntitiesResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest struct {
+ Data *[]Widget `json:"data,omitempty"`
+ Metadata *Metadata `json:"metadata,omitempty"`
+ }
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParsePostFooResponse parses an HTTP response from a PostFooWithResponse call
+func ParsePostFooResponse(rsp *http.Response) (*PostFooResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &PostFooResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest BarResponse
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseListItemsResponse2 parses an HTTP response from a ListItemsWithResponse call
+func ParseListItemsResponse2(rsp *http.Response) (*ListItemsResponse2, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &ListItemsResponse2{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest ListItemsResponse
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseCreateItemResponse2 parses an HTTP response from a CreateItemWithResponse call
+func ParseCreateItemResponse2(rsp *http.Response) (*CreateItemResponse2, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &CreateItemResponse2{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest CreateItemResponse
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseCreateOrderResponse parses an HTTP response from a CreateOrderWithResponse call
+func ParseCreateOrderResponse(rsp *http.Response) (*CreateOrderResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &CreateOrderResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Order
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseGetOutcomeResponse parses an HTTP response from a GetOutcomeWithResponse call
+func ParseGetOutcomeResponse(rsp *http.Response) (*GetOutcomeResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetOutcomeResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest OutcomeResult
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParsePostOutcomeResponse parses an HTTP response from a PostOutcomeWithResponse call
+func ParsePostOutcomeResponse(rsp *http.Response) (*PostOutcomeResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &PostOutcomeResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
+// ParseSendPayloadResponse parses an HTTP response from a SendPayloadWithResponse call
+func ParseSendPayloadResponse(rsp *http.Response) (*SendPayloadResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &SendPayloadResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Payload
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseCreatePetResponse parses an HTTP response from a CreatePetWithResponse call
+func ParseCreatePetResponse(rsp *http.Response) (*CreatePetResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &CreatePetResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Pet
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseQueryResponse2 parses an HTTP response from a QueryWithResponse call
+func ParseQueryResponse2(rsp *http.Response) (*QueryResponse2, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &QueryResponse2{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest QueryResponse
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseGetQuxResponse parses an HTTP response from a GetQuxWithResponse call
+func ParseGetQuxResponse(rsp *http.Response) (*GetQuxResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetQuxResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest QuxResponse
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParsePostQuxResponse parses an HTTP response from a PostQuxWithResponse call
+func ParsePostQuxResponse(rsp *http.Response) (*PostQuxResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &PostQuxResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
+// ParseGetRenamedSchemaResponse parses an HTTP response from a GetRenamedSchemaWithResponse call
+func ParseGetRenamedSchemaResponse(rsp *http.Response) (*GetRenamedSchemaResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetRenamedSchemaResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Renamer
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParsePostRenamedSchemaResponse parses an HTTP response from a PostRenamedSchemaWithResponse call
+func ParsePostRenamedSchemaResponse(rsp *http.Response) (*PostRenamedSchemaResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &PostRenamedSchemaResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
+// ParsePatchResourceResponse parses an HTTP response from a PatchResourceWithResponse call
+func ParsePatchResourceResponse(rsp *http.Response) (*PatchResourceResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &PatchResourceResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case rsp.Header.Get("Content-Type") == "application/json-patch+json" && rsp.StatusCode == 200:
+ var dest N200ResourcePatchResponseJSON2ApplicationJSONPatchPlusJSON
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.ApplicationjsonPatchJSON200 = &dest
+
+ case rsp.Header.Get("Content-Type") == "application/json-patch-query+json" && rsp.StatusCode == 200:
+ var dest N200ResourcePatchResponseJSON3ApplicationJSONPatchQueryPlusJSON
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.ApplicationjsonPatchQueryJSON200 = &dest
+
+ case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 200:
+ var dest N200ResourcePatchResponseJSONApplicationJSON
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ case rsp.Header.Get("Content-Type") == "application/merge-patch+json" && rsp.StatusCode == 200:
+ var dest N200ResourcePatchResponseJSON4ApplicationMergePatchPlusJSON
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.ApplicationmergePatchJSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseGetStatusResponse2 parses an HTTP response from a GetStatusWithResponse call
+func ParseGetStatusResponse2(rsp *http.Response) (*GetStatusResponse2, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetStatusResponse2{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest GetStatusResponse
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseGetZapResponse parses an HTTP response from a GetZapWithResponse call
+func ParseGetZapResponse(rsp *http.Response) (*GetZapResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetZapResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest ZapResponse
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParsePostZapResponse parses an HTTP response from a PostZapWithResponse call
+func ParsePostZapResponse(rsp *http.Response) (*PostZapResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &PostZapResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
diff --git a/internal/test/name_conflict_resolution/name_conflict_resolution_test.go b/internal/test/name_conflict_resolution/name_conflict_resolution_test.go
new file mode 100644
index 0000000000..158f56f3f4
--- /dev/null
+++ b/internal/test/name_conflict_resolution/name_conflict_resolution_test.go
@@ -0,0 +1,460 @@
+package nameconflictresolution
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+// TestCrossSectionCollisions verifies Pattern A: when the same name "Bar"
+// appears in schemas, parameters, requestBodies, and responses, the resolver
+// keeps the bare name for the component schema and suffixes the others.
+//
+// Covers issues: #200, #254, #407, #1881, PR #292
+func TestCrossSectionCollisions(t *testing.T) {
+ // Schema type keeps bare name "Bar"
+ bar := Bar{Value: ptr("hello")}
+ assert.Equal(t, "hello", *bar.Value)
+
+ // No collision for Bar2
+ bar2 := Bar2{Value: ptr(float32(1.5))}
+ assert.Equal(t, float32(1.5), *bar2.Value)
+
+ // Parameter type gets "Parameter" suffix
+ param := BarParameter("query-value")
+ assert.Equal(t, "query-value", string(param))
+
+ // RequestBody type gets "RequestBody" suffix
+ reqBody := BarRequestBody{Value: ptr(42)}
+ assert.Equal(t, 42, *reqBody.Value)
+
+ // Response type gets "Response" suffix
+ resp := BarResponse{
+ Value1: &Bar{Value: ptr("v1")},
+ Value2: &Bar2{Value: ptr(float32(2.0))},
+ }
+ assert.Equal(t, "v1", *resp.Value1.Value)
+ assert.Equal(t, float32(2.0), *resp.Value2.Value)
+
+ // PostFoo wrapper does not collide (unique name PostFooResponse)
+ var wrapper PostFooResponse
+ assert.Nil(t, wrapper.JSON200)
+ // JSON200 field points to the response type BarResponse (not schema type Bar)
+ wrapper.JSON200 = &resp
+ assert.Equal(t, "v1", *wrapper.JSON200.Value1.Value)
+}
+
+// TestSchemaVsClientWrapper verifies Pattern B: schema "CreateItemResponse"
+// collides with the client wrapper for operation "createItem". The schema
+// keeps the bare name; the wrapper gets numeric fallback "CreateItemResponse2".
+//
+// Covers issues: #1474, #1713, #1450
+func TestSchemaVsClientWrapper(t *testing.T) {
+ // Schema type keeps bare name
+ schema := CreateItemResponse{
+ Id: ptr("item-1"),
+ Name: ptr("Widget"),
+ }
+ assert.Equal(t, "item-1", *schema.Id)
+ assert.Equal(t, "Widget", *schema.Name)
+
+ // Client wrapper gets numeric fallback
+ var wrapper CreateItemResponse2
+ assert.Nil(t, wrapper.Body)
+ assert.Nil(t, wrapper.HTTPResponse)
+ assert.Nil(t, wrapper.JSON200)
+
+ // JSON200 field references the schema type, not the wrapper itself
+ wrapper.JSON200 = &schema
+ assert.Equal(t, "item-1", *wrapper.JSON200.Id)
+}
+
+// TestSchemaAliasVsClientWrapper verifies Pattern C: schema "ListItemsResponse"
+// (a string alias) collides with the client wrapper for operation "listItems".
+// The schema keeps the bare name; the wrapper gets "ListItemsResponse2".
+//
+// Covers issue: #1357
+func TestSchemaAliasVsClientWrapper(t *testing.T) {
+ // Schema type is a string alias
+ var schema ListItemsResponse = "item-list"
+ assert.Equal(t, "item-list", schema)
+
+ // Client wrapper gets numeric fallback
+ var wrapper ListItemsResponse2
+ assert.Nil(t, wrapper.Body)
+ assert.Nil(t, wrapper.HTTPResponse)
+ assert.Nil(t, wrapper.JSON200)
+
+ // JSON200 field references the schema type (string alias)
+ wrapper.JSON200 = &schema
+ assert.Equal(t, "item-list", *wrapper.JSON200)
+}
+
+// TestOperationNameMatchesSchema verifies Pattern D: schema "QueryResponse"
+// collides with the client wrapper for operation "query" (which generates
+// "QueryResponse"). The schema keeps the bare name; the wrapper gets
+// "QueryResponse2".
+//
+// Covers issue: #255
+func TestOperationNameMatchesSchema(t *testing.T) {
+ // Schema type keeps bare name
+ schema := QueryResponse{
+ Results: &[]string{"result1", "result2"},
+ }
+ assert.Len(t, *schema.Results, 2)
+
+ // Client wrapper gets numeric fallback
+ var wrapper QueryResponse2
+ assert.Nil(t, wrapper.JSON200)
+
+ // JSON200 field references the schema type
+ wrapper.JSON200 = &schema
+ assert.Len(t, *wrapper.JSON200.Results, 2)
+}
+
+// TestSchemaMatchesOpResponse verifies Pattern E: schema "GetStatusResponse"
+// collides with the client wrapper for operation "getStatus" (which generates
+// "GetStatusResponse"). The schema keeps the bare name; the wrapper gets
+// "GetStatusResponse2".
+//
+// Covers issues: #2097, #899
+func TestSchemaMatchesOpResponse(t *testing.T) {
+ // Schema type keeps bare name
+ schema := GetStatusResponse{
+ Status: ptr("healthy"),
+ Timestamp: ptr("2025-01-01T00:00:00Z"),
+ }
+ assert.Equal(t, "healthy", *schema.Status)
+ assert.Equal(t, "2025-01-01T00:00:00Z", *schema.Timestamp)
+
+ // Client wrapper gets numeric fallback
+ var wrapper GetStatusResponse2
+ assert.Nil(t, wrapper.JSON200)
+
+ // JSON200 field references the schema type
+ wrapper.JSON200 = &schema
+ assert.Equal(t, "healthy", *wrapper.JSON200.Status)
+}
+
+// TestMultipleJsonContentTypes verifies Pattern H: schema "Order" collides with
+// requestBody "Order" which has 3 content types that all contain "json":
+// - application/json
+// - application/merge-patch+json
+// - application/json-patch+json
+//
+// All three map to the same "JSON" short name via contentTypeSuffix(), which
+// would trigger an infinite oscillation between context suffix ("RequestBody")
+// and content type suffix ("JSON") strategies if applied per-group. The global
+// phase approach lets numeric fallback break the cycle.
+//
+// Expected types:
+// - Order struct (schema keeps bare name)
+// - OrderRequestBodyJSON struct (application/json requestBody)
+// - OrderRequestBodyJSON2 []struct (application/json-patch+json, numeric fallback)
+// - OrderRequestBodyJSON3 struct (application/merge-patch+json, numeric fallback)
+//
+// Covers: PR #2213 (multiple JSON content types in requestBody)
+func TestMultipleJsonContentTypes(t *testing.T) {
+ // Schema type keeps bare name "Order"
+ order := Order{
+ Id: ptr("order-1"),
+ Product: ptr("Widget"),
+ }
+ assert.Equal(t, "order-1", *order.Id)
+ assert.Equal(t, "Widget", *order.Product)
+
+ // The 3 requestBody content types should each get a unique name.
+ // They all collide on "OrderRequestBodyJSON", so numeric fallback kicks in.
+ // The type names below are compile-time assertions that all 3 exist and are distinct.
+
+ // application/json requestBody
+ jsonBody := OrderRequestBodyJSON{
+ Id: ptr("order-2"),
+ Product: ptr("Gadget"),
+ }
+ assert.Equal(t, "order-2", *jsonBody.Id)
+
+ // application/json-patch+json requestBody (numeric fallback, array type alias)
+ var jsonPatch OrderRequestBodyJSON2
+ assert.Nil(t, jsonPatch)
+
+ // application/merge-patch+json requestBody (numeric fallback)
+ mergePatch := OrderRequestBodyJSON3{
+ Product: ptr("Gadget-patched"),
+ }
+ assert.Equal(t, "Gadget-patched", *mergePatch.Product)
+
+ // CreateOrder wrapper should not collide
+ var wrapper CreateOrderResponse
+ assert.Nil(t, wrapper.JSON200)
+ wrapper.JSON200 = &order
+ assert.Equal(t, "order-1", *wrapper.JSON200.Id)
+}
+
+// TestRequestBodyVsSchema verifies that "Pet" in schemas and requestBodies
+// resolves correctly: the schema keeps bare name "Pet", the requestBody
+// gets "PetRequestBody".
+//
+// Covers issues: #254, #407
+func TestRequestBodyVsSchema(t *testing.T) {
+ // Schema type keeps bare name
+ pet := Pet{
+ Id: ptr(1),
+ Name: ptr("Fluffy"),
+ }
+ assert.Equal(t, 1, *pet.Id)
+ assert.Equal(t, "Fluffy", *pet.Name)
+
+ // RequestBody type gets "RequestBody" suffix
+ petReqBody := PetRequestBody{
+ Name: ptr("Fluffy"),
+ Species: ptr("cat"),
+ }
+ assert.Equal(t, "Fluffy", *petReqBody.Name)
+ assert.Equal(t, "cat", *petReqBody.Species)
+
+ // CreatePet wrapper doesn't collide (unique name CreatePetResponse)
+ var wrapper CreatePetResponse
+ assert.Nil(t, wrapper.JSON200)
+
+ // JSON200 field references the schema type Pet
+ wrapper.JSON200 = &pet
+ assert.Equal(t, "Fluffy", *wrapper.JSON200.Name)
+}
+
+// TestRefTargetPicksUpRename verifies that when an operation references a
+// renamed component via $ref, the generated wrapper type uses the resolved
+// (renamed) type, not the original spec name.
+func TestRefTargetPicksUpRename(t *testing.T) {
+ // When postFoo references $ref: '#/components/responses/Bar',
+ // and response Bar is renamed to BarResponse, the wrapper's
+ // JSON200 field must use BarResponse (not Bar).
+ barResp := BarResponse{
+ Value1: &Bar{Value: ptr("v1")},
+ Value2: &Bar2{Value: ptr(float32(2.0))},
+ }
+ var wrapper PostFooResponse
+ wrapper.JSON200 = &barResp // compile-time: JSON200 must be *BarResponse
+ assert.Equal(t, "v1", *wrapper.JSON200.Value1.Value)
+ assert.Equal(t, float32(2.0), *wrapper.JSON200.Value2.Value)
+}
+
+// TestExtGoTypeNameWithCollisionResolver verifies that when a component schema
+// has x-go-type-name: CustomQux and collides with a response "Qux", the
+// collision resolver controls the top-level Go type names while x-go-type-name
+// controls the underlying type definition.
+//
+// Expected types:
+// - CustomQux struct (underlying type from x-go-type-name)
+// - Qux = CustomQux (schema keeps bare name, aliased)
+// - QuxResponse struct (response gets suffixed)
+func TestExtGoTypeNameWithCollisionResolver(t *testing.T) {
+ // CustomQux is the underlying struct created by x-go-type-name
+ custom := CustomQux{Label: ptr("hello")}
+ assert.Equal(t, "hello", *custom.Label)
+
+ // Qux is a type alias for CustomQux (schema keeps bare name)
+ var qux Qux = custom //nolint:staticcheck // explicit type needed to prove Qux aliases CustomQux
+ assert.Equal(t, "hello", *qux.Label)
+
+ // QuxResponse is the response type (response gets suffixed)
+ quxResp := QuxResponse{Data: ptr("response-data")}
+ assert.Equal(t, "response-data", *quxResp.Data)
+
+ // GetQuxResponse client wrapper's JSON200 field uses *QuxResponse
+ var wrapper GetQuxResponse
+ assert.Nil(t, wrapper.JSON200)
+ wrapper.JSON200 = &quxResp
+ assert.Equal(t, "response-data", *wrapper.JSON200.Data)
+}
+
+// TestExtGoTypeWithCollisionResolver verifies that when a component schema has
+// x-go-type: string and collides with a response "Zap", the collision resolver
+// controls the top-level Go type names while x-go-type controls the target type.
+//
+// Expected types:
+// - Zap = string (schema keeps bare name, x-go-type controls target)
+// - ZapResponse struct (response gets suffixed)
+func TestExtGoTypeWithCollisionResolver(t *testing.T) {
+ // Zap is a string type alias (x-go-type controls the target)
+ var zap Zap = "test-value"
+ assert.Equal(t, "test-value", string(zap))
+
+ // ZapResponse is the response type (response gets suffixed)
+ zapResp := ZapResponse{Result: ptr("response-result")}
+ assert.Equal(t, "response-result", *zapResp.Result)
+
+ // GetZapResponse client wrapper's JSON200 field uses *ZapResponse
+ var wrapper GetZapResponse
+ assert.Nil(t, wrapper.JSON200)
+ wrapper.JSON200 = &zapResp
+ assert.Equal(t, "response-result", *wrapper.JSON200.Result)
+}
+
+// TestInlineResponseWithRefProperties verifies Pattern I (oapi-codegen-exp#14):
+// when a response has an inline object whose properties contain $refs to component
+// schemas with x-go-type, the property-level refs must NOT produce duplicate type
+// declarations. The component schemas keep their type aliases (Widget = string,
+// Metadata = string), and the inline response object gets its own struct type.
+//
+// Covers: oapi-codegen-exp#14
+func TestInlineResponseWithRefProperties(t *testing.T) {
+ // Component schemas with x-go-type: string produce type aliases
+ var widget Widget = "widget-value"
+ assert.Equal(t, "widget-value", string(widget))
+
+ var metadata Metadata = "metadata-value"
+ assert.Equal(t, "metadata-value", string(metadata))
+
+ // The inline response object should have fields typed by the component aliases.
+ // The client wrapper for listEntities should exist and have a JSON200 field
+ // pointing to the inline response type.
+ var wrapper ListEntitiesResponse
+ assert.Nil(t, wrapper.JSON200)
+}
+
+// TestDuplicateOneOfMembersAcrossContentTypes verifies Pattern J:
+// when a response has multiple JSON content types (e.g., application/json-patch+json
+// and application/json-patch-query+json) that share an identical oneOf schema with
+// inline (non-$ref) members, the codegen must not emit duplicate type declarations
+// for those inline members.
+//
+// Additionally, when a requestBody shares its name with a component schema and its
+// content schemas $ref the component schema (plus one $refs a different schema),
+// the collision resolver must assign unique names.
+//
+// Expected types:
+// - ResourceMVO struct (schema keeps bare name)
+// - Resource struct (no collision)
+// - JsonPatch []struct (no collision)
+// - ResourceMVORequestBodyJSON = ResourceMVO (requestBody application/json)
+// - ResourceMVORequestBodyJSON2 = JsonPatch (requestBody application/json-patch+json)
+// - ResourceMVORequestBodyJSON3 = ResourceMVO (requestBody application/merge-patch+json)
+// - PatchResourceResponse struct (client response wrapper)
+// - inline oneOf member types (must not be duplicated)
+func TestDuplicateOneOfMembersAcrossContentTypes(t *testing.T) {
+ // Schema types keep bare names
+ resource := Resource{
+ Id: ptr("res-1"),
+ Name: ptr("MyResource"),
+ Status: ptr("active"),
+ }
+ assert.Equal(t, "res-1", *resource.Id)
+
+ resourceMVO := ResourceMVO{
+ Name: ptr("MyResource"),
+ Status: ptr("active"),
+ }
+ assert.Equal(t, "MyResource", *resourceMVO.Name)
+
+ // RequestBody collision resolution: schema "Resource_MVO" keeps bare name,
+ // requestBody content types get suffixed.
+ var reqBodyJSON ResourceMVORequestBodyJSON
+ reqBodyJSON.Name = ptr("test")
+ assert.Equal(t, "test", *reqBodyJSON.Name)
+
+ var reqBodyPatch ResourceMVORequestBodyJSON2
+ assert.Nil(t, reqBodyPatch) // JsonPatch alias (slice type)
+
+ var reqBodyMerge ResourceMVORequestBodyJSON3
+ reqBodyMerge.Name = ptr("merge")
+ assert.Equal(t, "merge", *reqBodyMerge.Name)
+
+ // Client response wrapper should exist. The primary assertion here
+ // is that the package compiles — no duplicate oneOf member types and
+ // no undefined response type names.
+ var wrapper PatchResourceResponse
+ assert.Nil(t, wrapper.Body)
+ assert.Nil(t, wrapper.HTTPResponse)
+}
+
+// TestXGoNameOnSchemaPreserved verifies Pattern K: when a component schema
+// has x-go-name, the collision resolver must use the x-go-name value as the
+// schema's type name (pinned), not the original spec name.
+//
+// Schema "Renamer" has x-go-name: "SpecialName" and shares a name with
+// response "Renamer". With correct x-go-name handling the schema becomes
+// "SpecialName", so no collision exists and the response keeps "Renamer".
+//
+// Expected types:
+// - SpecialName struct (schema "Renamer" pinned by x-go-name)
+// - Renamer struct (response "Renamer" — no collision)
+//
+// Covers: PR #2213 review finding (x-go-name not respected by resolver)
+func TestXGoNameOnSchemaPreserved(t *testing.T) {
+ // Schema "Renamer" should use its x-go-name "SpecialName"
+ schema := SpecialName{Label: ptr("test-label")}
+ assert.Equal(t, "test-label", *schema.Label)
+
+ // Response "Renamer" should keep its bare name (no collision with schema)
+ resp := Renamer{Data: ptr("response-data")}
+ assert.Equal(t, "response-data", *resp.Data)
+
+ // Client wrapper for getRenamedSchema should reference the response type
+ var wrapper GetRenamedSchemaResponse
+ assert.Nil(t, wrapper.JSON200)
+ wrapper.JSON200 = &resp
+ assert.Equal(t, "response-data", *wrapper.JSON200.Data)
+}
+
+// TestXGoNameOnResponsePreserved verifies Pattern L: when a component response
+// has x-go-name, the collision resolver must use the x-go-name value as the
+// response's type name (pinned), not the original spec name.
+//
+// Response "Outcome" has x-go-name: "OutcomeResult" and shares a name with
+// schema "Outcome". With correct x-go-name handling the response becomes
+// "OutcomeResult", so no collision exists and the schema keeps "Outcome".
+//
+// Expected types:
+// - Outcome struct (schema keeps bare name — no collision)
+// - OutcomeResult struct (response "Outcome" pinned by x-go-name)
+//
+// Covers: PR #2213 review finding (x-go-name not respected by resolver)
+func TestXGoNameOnResponsePreserved(t *testing.T) {
+ // Schema "Outcome" should keep its bare name
+ schema := Outcome{Value: ptr("some-value")}
+ assert.Equal(t, "some-value", *schema.Value)
+
+ // Response "Outcome" should use its x-go-name "OutcomeResult"
+ resp := OutcomeResult{Result: ptr("outcome-data")}
+ assert.Equal(t, "outcome-data", *resp.Result)
+
+ // Client wrapper for getOutcome should reference the response type
+ var wrapper GetOutcomeResponse
+ assert.Nil(t, wrapper.JSON200)
+ wrapper.JSON200 = &resp
+ assert.Equal(t, "outcome-data", *wrapper.JSON200.Result)
+}
+
+// TestXGoNameOnRequestBodyPreserved verifies Pattern M: when a component
+// requestBody has x-go-name, the collision resolver must use the x-go-name
+// value as the requestBody's type name (pinned), not the original spec name.
+//
+// RequestBody "Payload" has x-go-name: "PayloadBody" and shares a name with
+// schema "Payload". With correct x-go-name handling the requestBody becomes
+// "PayloadBody", so no collision exists and the schema keeps "Payload".
+//
+// Expected types:
+// - Payload struct (schema keeps bare name — no collision)
+// - PayloadBody struct (requestBody "Payload" pinned by x-go-name)
+//
+// Covers: PR #2213 review finding (x-go-name not respected by resolver)
+func TestXGoNameOnRequestBodyPreserved(t *testing.T) {
+ // Schema "Payload" should keep its bare name
+ schema := Payload{Content: ptr("payload-content")}
+ assert.Equal(t, "payload-content", *schema.Content)
+
+ // RequestBody "Payload" should use its x-go-name "PayloadBody"
+ reqBody := PayloadBody{Data: ptr("body-data")}
+ assert.Equal(t, "body-data", *reqBody.Data)
+
+ // Client wrapper for sendPayload should reference the schema type
+ var wrapper SendPayloadResponse
+ assert.Nil(t, wrapper.JSON200)
+ wrapper.JSON200 = &schema
+ assert.Equal(t, "payload-content", *wrapper.JSON200.Content)
+}
+
+func ptr[T any](v T) *T {
+ return &v
+}
diff --git a/internal/test/name_conflict_resolution/spec.yaml b/internal/test/name_conflict_resolution/spec.yaml
new file mode 100644
index 0000000000..6cebbb9668
--- /dev/null
+++ b/internal/test/name_conflict_resolution/spec.yaml
@@ -0,0 +1,607 @@
+openapi: 3.0.1
+
+info:
+ title: "Comprehensive name collision resolution test"
+ description: |
+ Exercises all documented name collision patterns across issues and PRs:
+ #200, #254, #255, #292, #407, #899, #1357, #1450, #1474, #1713, #1881, #2097, #2213
+ Also covers oapi-codegen-exp#14 (inline response object with $ref properties).
+ Patterns K/L/M cover x-go-name preservation during collision resolution (PR #2213 review).
+ version: 0.0.0
+
+paths:
+ # Pattern A: Cross-section collision (issues #200, #254, #407, #1881, PR #292)
+ # "Bar" appears in schemas, parameters, requestBodies, responses, and headers.
+ /foo:
+ post:
+ operationId: postFoo
+ parameters:
+ - $ref: '#/components/parameters/Bar'
+ requestBody:
+ $ref: '#/components/requestBodies/Bar'
+ responses:
+ 200:
+ $ref: '#/components/responses/Bar'
+
+ # Pattern B: Schema vs client wrapper (issues #1474, #1713, #1450)
+ # Schema "CreateItemResponse" collides with createItem wrapper.
+ /items:
+ post:
+ operationId: createItem
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ name:
+ type: string
+ responses:
+ 200:
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/CreateItemResponse'
+
+ # Pattern C: Schema alias vs client wrapper (issue #1357)
+ # Schema "ListItemsResponse" (string alias) collides with listItems wrapper.
+ get:
+ operationId: listItems
+ responses:
+ 200:
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/ListItemsResponse'
+
+ # Pattern D: Operation name = schema response name (issue #255)
+ # Schema "QueryResponse" collides with query wrapper.
+ /query:
+ post:
+ operationId: query
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ q:
+ type: string
+ responses:
+ 200:
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/QueryResponse'
+
+ # Pattern E: Schema matches op+Response (issues #2097, #899)
+ # Schema "GetStatusResponse" collides with getStatus wrapper.
+ /status:
+ get:
+ operationId: getStatus
+ responses:
+ 200:
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/GetStatusResponse'
+
+ # Pattern F: x-go-type-name extension + cross-section collision
+ # Schema "Qux" has x-go-type-name and collides with response "Qux".
+ /qux:
+ get:
+ operationId: getQux
+ responses:
+ '200':
+ $ref: '#/components/responses/Qux'
+ post:
+ operationId: postQux
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Qux'
+ responses:
+ '200':
+ description: OK
+
+ # Pattern G: x-go-type extension + cross-section collision
+ # Schema "Zap" has x-go-type and collides with response "Zap".
+ /zap:
+ get:
+ operationId: getZap
+ responses:
+ '200':
+ $ref: '#/components/responses/Zap'
+ post:
+ operationId: postZap
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Zap'
+ responses:
+ '200':
+ description: OK
+
+ # Pattern H: Multiple JSON content types in requestBody (PR #2213)
+ # "Order" appears in schemas and requestBodies. The requestBody has 3 content
+ # types that all contain "json" and collapse to the same "JSON" short name:
+ # application/json, application/merge-patch+json, application/json-patch+json
+ # This triggers an infinite oscillation between context suffix and content type
+ # suffix strategies unless the numeric fallback can break the cycle.
+ /orders:
+ post:
+ operationId: createOrder
+ requestBody:
+ $ref: '#/components/requestBodies/Order'
+ responses:
+ 200:
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Order'
+
+ # Pattern I: Inline response object with $ref properties to x-go-type schemas
+ # (oapi-codegen-exp#14). The response has an inline object with properties that
+ # $ref component schemas carrying x-go-type. Each property ref should use the
+ # component schema's type alias, not produce duplicate type declarations.
+ /entities:
+ get:
+ operationId: listEntities
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ data:
+ type: array
+ items:
+ $ref: '#/components/schemas/Widget'
+ metadata:
+ $ref: '#/components/schemas/Metadata'
+
+ # Pattern J: Duplicate inline oneOf members across response content types
+ # A PATCH operation returns multiple JSON content types
+ # (application/json, application/json-patch+json, application/json-patch-query+json,
+ # application/merge-patch+json). The json-patch and json-patch-query variants
+ # share an identical oneOf schema with inline (non-$ref) members. The codegen
+ # must not emit duplicate type declarations for those inline members.
+ #
+ # Additionally, the requestBody shares the same name as a component schema
+ # ("Resource_MVO") where the requestBody content schemas $ref the component
+ # schema, and one content type $refs a different schema.
+ /resources/{id}:
+ patch:
+ operationId: patchResource
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ requestBody:
+ $ref: '#/components/requestBodies/Resource_MVO'
+ responses:
+ '200':
+ $ref: '#/components/responses/200Resource_Patch'
+
+ # Pattern K: x-go-name on schema — resolver must preserve user-specified names
+ # Schema "Renamer" has x-go-name: "SpecialName". Response "Renamer" also exists.
+ # The resolver should use "SpecialName" for the schema (pinned by x-go-name)
+ # and "Renamer" for the response (no collision since the schema is "SpecialName").
+ # Covers: PR #2213 review finding (x-go-name not respected by resolver)
+ /renamed-schema:
+ get:
+ operationId: getRenamedSchema
+ responses:
+ '200':
+ $ref: '#/components/responses/Renamer'
+ post:
+ operationId: postRenamedSchema
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Renamer'
+ responses:
+ '200':
+ description: OK
+
+ # Pattern L: x-go-name on response — resolver must preserve user-specified names
+ # Response "Outcome" has x-go-name: "OutcomeResult". Schema "Outcome" also exists.
+ # The resolver should use "OutcomeResult" for the response (pinned by x-go-name)
+ # and "Outcome" for the schema (no collision since the response is "OutcomeResult").
+ # Covers: PR #2213 review finding (x-go-name not respected by resolver)
+ /outcome:
+ get:
+ operationId: getOutcome
+ responses:
+ '200':
+ $ref: '#/components/responses/Outcome'
+ post:
+ operationId: postOutcome
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Outcome'
+ responses:
+ '200':
+ description: OK
+
+ # Pattern M: x-go-name on requestBody — resolver must preserve user-specified names
+ # RequestBody "Payload" has x-go-name: "PayloadBody". Schema "Payload" also exists.
+ # The resolver should use "PayloadBody" for the requestBody (pinned by x-go-name)
+ # and "Payload" for the schema (no collision since the requestBody is "PayloadBody").
+ # Covers: PR #2213 review finding (x-go-name not respected by resolver)
+ /payload:
+ post:
+ operationId: sendPayload
+ requestBody:
+ $ref: '#/components/requestBodies/Payload'
+ responses:
+ '200':
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Payload'
+
+ # Cross-section: requestBody vs schema (issues #254, #407)
+ # "Pet" appears in both schemas and requestBodies.
+ /pets:
+ post:
+ operationId: createPet
+ requestBody:
+ $ref: '#/components/requestBodies/Pet'
+ responses:
+ 200:
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+
+components:
+ schemas:
+ Bar:
+ type: object
+ properties:
+ value:
+ type: string
+
+ Bar2:
+ type: object
+ properties:
+ value:
+ type: number
+
+ CreateItemResponse:
+ type: object
+ properties:
+ id:
+ type: string
+ name:
+ type: string
+
+ ListItemsResponse:
+ type: string
+
+ QueryResponse:
+ type: object
+ properties:
+ results:
+ type: array
+ items:
+ type: string
+
+ GetStatusResponse:
+ type: object
+ properties:
+ status:
+ type: string
+ timestamp:
+ type: string
+
+ # Pattern H: Schema "Order" collides with requestBody "Order" which has
+ # 3 content types that all map to the "JSON" short name.
+ Order:
+ type: object
+ properties:
+ id:
+ type: string
+ product:
+ type: string
+
+ Pet:
+ type: object
+ properties:
+ id:
+ type: integer
+ name:
+ type: string
+
+ # Pattern I: schemas with x-go-type used as $ref targets in inline response properties.
+ # (oapi-codegen-exp#14)
+ Widget:
+ type: object
+ x-go-type: string
+ properties:
+ id:
+ type: string
+
+ Metadata:
+ type: object
+ x-go-type: string
+ properties:
+ total:
+ type: integer
+
+ # Pattern J: schema "Resource_MVO" collides with requestBody "Resource_MVO".
+ # The requestBody's content schemas $ref the component schema, plus one
+ # content type $refs a different schema (JsonPatch). The response for the
+ # PATCH operation has multiple JSON content types, two of which share an
+ # identical oneOf schema with inline members.
+ Resource_MVO:
+ type: object
+ properties:
+ name:
+ type: string
+ status:
+ type: string
+
+ Resource:
+ type: object
+ properties:
+ id:
+ type: string
+ name:
+ type: string
+ status:
+ type: string
+
+ JsonPatch:
+ type: array
+ items:
+ type: object
+ properties:
+ op:
+ type: string
+ path:
+ type: string
+
+ # Pattern K: x-go-name on schema — should be pinned as "SpecialName"
+ Renamer:
+ x-go-name: SpecialName
+ type: object
+ properties:
+ label:
+ type: string
+
+ # Pattern L: schema "Outcome" (no x-go-name — keeps bare name)
+ Outcome:
+ type: object
+ properties:
+ value:
+ type: string
+
+ # Pattern M: schema "Payload" (no x-go-name — keeps bare name)
+ Payload:
+ type: object
+ properties:
+ content:
+ type: string
+
+ # Pattern F: x-go-type-name extension + cross-section collision
+ # Schema "Qux" has x-go-type-name: CustomQux and collides with response "Qux".
+ Qux:
+ type: object
+ x-go-type-name: CustomQux
+ properties:
+ label:
+ type: string
+
+ # Pattern G: x-go-type extension + cross-section collision
+ # Schema "Zap" has x-go-type: string and collides with response "Zap".
+ Zap:
+ type: object
+ x-go-type: string
+ properties:
+ unused:
+ type: string
+
+ parameters:
+ Bar:
+ name: bar
+ in: query
+ schema:
+ type: string
+
+ requestBodies:
+ Bar:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ value:
+ type: integer
+
+ # Pattern H: requestBody "Order" with 3 content types that all contain "json"
+ # and collapse to the same "JSON" suffix via contentTypeSuffix().
+ Order:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ id:
+ type: string
+ product:
+ type: string
+ application/merge-patch+json:
+ schema:
+ type: object
+ properties:
+ product:
+ type: string
+ application/json-patch+json:
+ schema:
+ type: array
+ items:
+ type: object
+ properties:
+ op:
+ type: string
+ path:
+ type: string
+ value:
+ type: string
+
+ Pet:
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ name:
+ type: string
+ species:
+ type: string
+
+ # Pattern M: requestBody "Payload" has x-go-name — should be pinned as "PayloadBody"
+ Payload:
+ x-go-name: PayloadBody
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ data:
+ type: string
+
+ # Pattern J: requestBody "Resource_MVO" shares name with schema "Resource_MVO".
+ # Content schemas $ref the component schema, except json-patch which $refs JsonPatch.
+ Resource_MVO:
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Resource_MVO'
+ application/merge-patch+json:
+ schema:
+ $ref: '#/components/schemas/Resource_MVO'
+ application/json-patch+json:
+ schema:
+ $ref: '#/components/schemas/JsonPatch'
+
+ headers:
+ Bar:
+ schema:
+ type: boolean
+
+ responses:
+ Bar:
+ description: Bar response
+ headers:
+ X-Bar:
+ $ref: '#/components/headers/Bar'
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ value1:
+ $ref: '#/components/schemas/Bar'
+ value2:
+ $ref: '#/components/schemas/Bar2'
+
+ # Pattern K: response "Renamer" — no x-go-name, should keep bare name "Renamer"
+ # because the schema collision is avoided by the schema's x-go-name: SpecialName.
+ Renamer:
+ description: A Renamer response
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ data:
+ type: string
+
+ # Pattern L: response "Outcome" has x-go-name — should be pinned as "OutcomeResult"
+ Outcome:
+ x-go-name: OutcomeResult
+ description: An Outcome response
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ result:
+ type: string
+
+ Qux:
+ description: A Qux response
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ data:
+ type: string
+
+ Zap:
+ description: A Zap response
+ content:
+ application/json:
+ schema:
+ type: object
+ properties:
+ result:
+ type: string
+
+ # Pattern J: response with multiple JSON content types where json-patch
+ # and json-patch-query variants share an identical oneOf schema with
+ # inline (non-$ref) members. The codegen must not emit duplicate type
+ # declarations for those inline members.
+ 200Resource_Patch:
+ description: Patch success
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Resource'
+ application/merge-patch+json:
+ schema:
+ $ref: '#/components/schemas/Resource'
+ application/json-patch+json:
+ schema:
+ oneOf:
+ - $ref: '#/components/schemas/Resource'
+ - type: array
+ items:
+ $ref: '#/components/schemas/Resource'
+ - type: string
+ nullable: true
+ application/json-patch-query+json:
+ schema:
+ oneOf:
+ - $ref: '#/components/schemas/Resource'
+ - type: array
+ items:
+ $ref: '#/components/schemas/Resource'
+ - type: string
+ nullable: true
diff --git a/internal/test/outputoptions/disabletypealiases/config.yaml b/internal/test/outputoptions/disabletypealiases/config.yaml
new file mode 100644
index 0000000000..b82daa271a
--- /dev/null
+++ b/internal/test/outputoptions/disabletypealiases/config.yaml
@@ -0,0 +1,9 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: types
+generate:
+ models: true
+output: types.gen.go
+output-options:
+ skip-prune: true
+ disable-type-aliases-for-type:
+ - array
diff --git a/internal/test/outputoptions/disabletypealiases/generate.go b/internal/test/outputoptions/disabletypealiases/generate.go
new file mode 100644
index 0000000000..8f0dd5b3e3
--- /dev/null
+++ b/internal/test/outputoptions/disabletypealiases/generate.go
@@ -0,0 +1,3 @@
+package types
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/outputoptions/disabletypealiases/spec.yaml b/internal/test/outputoptions/disabletypealiases/spec.yaml
new file mode 100644
index 0000000000..e073eb3c64
--- /dev/null
+++ b/internal/test/outputoptions/disabletypealiases/spec.yaml
@@ -0,0 +1,13 @@
+components:
+ schemas:
+ my_item:
+ type: object
+ properties:
+ name:
+ type: string
+ age:
+ type: integer
+ example:
+ type: array
+ items:
+ $ref: '#/components/schemas/my_item'
diff --git a/internal/test/outputoptions/disabletypealiases/types.gen.go b/internal/test/outputoptions/disabletypealiases/types.gen.go
new file mode 100644
index 0000000000..f2537cfba5
--- /dev/null
+++ b/internal/test/outputoptions/disabletypealiases/types.gen.go
@@ -0,0 +1,13 @@
+// Package types provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package types
+
+// Example defines model for example.
+type Example []MyItem
+
+// MyItem defines model for my_item.
+type MyItem struct {
+ Age *int `json:"age,omitempty"`
+ Name *string `json:"name,omitempty"`
+}
diff --git a/internal/test/outputoptions/disabletypealiases/types_ext.go b/internal/test/outputoptions/disabletypealiases/types_ext.go
new file mode 100644
index 0000000000..49103fd7f9
--- /dev/null
+++ b/internal/test/outputoptions/disabletypealiases/types_ext.go
@@ -0,0 +1,5 @@
+package types
+
+// MustCompile will only compile if the type it's defined on has type aliases disabled
+func (*Example) MustCompile() {
+}
diff --git a/internal/test/outputoptions/name-normalizer/spec.yaml b/internal/test/outputoptions/name-normalizer/spec.yaml
new file mode 100644
index 0000000000..524ecb70ad
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/spec.yaml
@@ -0,0 +1,64 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Example code for the `name-normalizer` output option
+paths:
+ /api/pets/{petId}:
+ get:
+ summary: Get pet given identifier.
+ operationId: getHttpPet
+ parameters:
+ - name: petId
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: valid pet
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Pet'
+components:
+ schemas:
+ Pet:
+ type: object
+ required:
+ - uuid
+ - name
+ properties:
+ uuid:
+ type: string
+ description: The pet uuid.
+ name:
+ type: string
+ description: The name of the pet.
+ Error:
+ required:
+ - code
+ - message
+ properties:
+ code:
+ type: integer
+ format: int32
+ description: Error code
+ message:
+ type: string
+ description: Error message
+ OneOf2things:
+ description: "Notice that the `things` is not capitalised"
+ oneOf:
+ - type: object
+ required:
+ - id
+ properties:
+ id:
+ type: integer
+ - type: object
+ required:
+ - id
+ properties:
+ id:
+ type: string
+ format: uuid
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/config.yaml b/internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/config.yaml
new file mode 100644
index 0000000000..1e0ffb5655
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/config.yaml
@@ -0,0 +1,13 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
+package: tocamelcasewithadditionalinitialisms
+generate:
+ gorilla-server: true
+ client: true
+ models: true
+ embedded-spec: true
+output: name_normalizer.gen.go
+output-options:
+ skip-prune: true
+ name-normalizer: ToCamelCaseWithInitialisms
+ additional-initialisms:
+ - NAME
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/generate.go b/internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/generate.go
new file mode 100644
index 0000000000..c5611adbd0
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/generate.go
@@ -0,0 +1,3 @@
+package tocamelcasewithadditionalinitialisms
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../spec.yaml
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/name_normalizer.gen.go b/internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/name_normalizer.gen.go
new file mode 100644
index 0000000000..8796ba4b3a
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/name_normalizer.gen.go
@@ -0,0 +1,629 @@
+// Package tocamelcasewithadditionalinitialisms provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package tocamelcasewithadditionalinitialisms
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gorilla/mux"
+ "github.com/oapi-codegen/runtime"
+ openapi_types "github.com/oapi-codegen/runtime/types"
+)
+
+// Error defines model for Error.
+type Error struct {
+ // Code Error code
+ Code int32 `json:"code"`
+
+ // Message Error message
+ Message string `json:"message"`
+}
+
+// OneOf2Things Notice that the `things` is not capitalised
+type OneOf2Things struct {
+ union json.RawMessage
+}
+
+// OneOf2Things0 defines model for .
+type OneOf2Things0 struct {
+ ID int `json:"id"`
+}
+
+// OneOf2Things1 defines model for .
+type OneOf2Things1 struct {
+ ID openapi_types.UUID `json:"id"`
+}
+
+// Pet defines model for Pet.
+type Pet struct {
+ // NAME The name of the pet.
+ NAME string `json:"name"`
+
+ // UUID The pet uuid.
+ UUID string `json:"uuid"`
+}
+
+// AsOneOf2Things0 returns the union data inside the OneOf2Things as a OneOf2Things0
+func (t OneOf2Things) AsOneOf2Things0() (OneOf2Things0, error) {
+ var body OneOf2Things0
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOf2Things0 overwrites any union data inside the OneOf2Things as the provided OneOf2Things0
+func (t *OneOf2Things) FromOneOf2Things0(v OneOf2Things0) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOf2Things0 performs a merge with any union data inside the OneOf2Things, using the provided OneOf2Things0
+func (t *OneOf2Things) MergeOneOf2Things0(v OneOf2Things0) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsOneOf2Things1 returns the union data inside the OneOf2Things as a OneOf2Things1
+func (t OneOf2Things) AsOneOf2Things1() (OneOf2Things1, error) {
+ var body OneOf2Things1
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOf2Things1 overwrites any union data inside the OneOf2Things as the provided OneOf2Things1
+func (t *OneOf2Things) FromOneOf2Things1(v OneOf2Things1) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOf2Things1 performs a merge with any union data inside the OneOf2Things, using the provided OneOf2Things1
+func (t *OneOf2Things) MergeOneOf2Things1(v OneOf2Things1) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t OneOf2Things) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *OneOf2Things) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetHTTPPet request
+ GetHTTPPet(ctx context.Context, petID string, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetHTTPPet(ctx context.Context, petID string, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetHTTPPetRequest(c.Server, petID)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetHTTPPetRequest generates requests for GetHTTPPet
+func NewGetHTTPPetRequest(server string, petID string) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "petId", petID, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/api/pets/%s", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetHTTPPetWithResponse request
+ GetHTTPPetWithResponse(ctx context.Context, petID string, reqEditors ...RequestEditorFn) (*GetHTTPPetResponse, error)
+}
+
+type GetHTTPPetResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Pet
+}
+
+// GetJSON200 returns JSON200
+func (r GetHTTPPetResponse) GetJSON200() *Pet {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetHTTPPetResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetHTTPPetResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetHTTPPetResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetHTTPPetResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetHTTPPetWithResponse request returning *GetHTTPPetResponse
+func (c *ClientWithResponses) GetHTTPPetWithResponse(ctx context.Context, petID string, reqEditors ...RequestEditorFn) (*GetHTTPPetResponse, error) {
+ rsp, err := c.GetHTTPPet(ctx, petID, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetHTTPPetResponse(rsp)
+}
+
+// ParseGetHTTPPetResponse parses an HTTP response from a GetHTTPPetWithResponse call
+func ParseGetHTTPPetResponse(rsp *http.Response) (*GetHTTPPetResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetHTTPPetResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Pet
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // Get pet given identifier.
+ // (GET /api/pets/{petId})
+ GetHTTPPet(w http.ResponseWriter, r *http.Request, petID string)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetHTTPPet operation middleware
+func (siw *ServerInterfaceWrapper) GetHTTPPet(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "petId" -------------
+ var petID string
+
+ err = runtime.BindStyledParameterWithOptions("simple", "petId", mux.Vars(r)["petId"], &petID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "petId", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetHTTPPet(w, r, petID)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+ BaseURL string
+ BaseRouter *mux.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = mux.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.HandleFunc(options.BaseURL+"/api/pets/{petId}", wrapper.GetHTTPPet).Methods(http.MethodGet)
+
+ return r
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "hFNNb9s8DP4rAt/3qNlZevO92HpZe8itCBDNom0WtqRJdLAu8H8fKCVZlmToJZFF6tHzIR6g9VPwDh0n",
+ "aA6Q2gEnk5ePMfooixB9wMiEebv1FuXfYmojBSbvoCnNKtc0dD5OhqEBcvywBg38HrB8Yo8RFg0TpmT6",
+ "fwKdyuejiSO5HpZFQ8QfM0W00LzC8cJT+3bR8OzwuVvzQK5Pt/DfPFOLigfDigdUu9K4U5SU86xaE4jN",
+ "SAktaPCCBc3rtQdk5fda1RU3srA98/ff37BlWPR9qLNj80z2Q9V3kUX7C/JtYM5Md3zeDKikonyXjQjI",
+ "1e3FuhC6ezogK6lWH/I9ispEbolLN7nOZ0uJR6k9/jRTGDE/KNX5WLISgE9OrBrpF8ad8jOHmZUvtDTs",
+ "MaZC8HO1qlbC3wd0JhA08JC3NATDQzamNoHqgJzqQ0B+sots9sVCMdAI6pOFBr4gf91sXsReOR/NhIwx",
+ "5ZdBcp1gnhQ2kNHg0gOOM+rjcF08nbNfW2lOwbtUMluvVmXWHKPLhEwII7WZUv2WROPhAu//iB008F/9",
+ "Z5rr4yjXwjqb/HeEezOSlRBzXGmeJhPfi9YcbU97dIosOqaOMFYCsvwOAAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/name_normalizer_test.go b/internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/name_normalizer_test.go
new file mode 100644
index 0000000000..82d3b2d478
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case-with-additional-initialisms/name_normalizer_test.go
@@ -0,0 +1,24 @@
+package tocamelcasewithadditionalinitialisms
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGenCodeHasCorrectNames(t *testing.T) {
+ pet := &Pet{}
+ assert.Equal(t, "", pet.NAME)
+ assert.Equal(t, "", pet.UUID)
+
+ uri := "https://my-api.com/some-base-url/v1/"
+ client, err := NewClient(uri)
+ assert.Nil(t, err)
+ assert.NotNil(t, client.GetHTTPPet)
+
+ server := &ServerInterfaceWrapper{}
+ assert.NotNil(t, server.GetHTTPPet)
+
+ oneOf := OneOf2Things{}
+ assert.Zero(t, oneOf)
+}
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case-with-digits/config.yaml b/internal/test/outputoptions/name-normalizer/to-camel-case-with-digits/config.yaml
new file mode 100644
index 0000000000..59b69a9de3
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case-with-digits/config.yaml
@@ -0,0 +1,11 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
+package: tocamelcasewithdigits
+generate:
+ gorilla-server: true
+ client: true
+ models: true
+ embedded-spec: true
+output: name_normalizer.gen.go
+output-options:
+ skip-prune: true
+ name-normalizer: ToCamelCaseWithDigits
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case-with-digits/generate.go b/internal/test/outputoptions/name-normalizer/to-camel-case-with-digits/generate.go
new file mode 100644
index 0000000000..4b4d2e44e6
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case-with-digits/generate.go
@@ -0,0 +1,3 @@
+package tocamelcasewithdigits
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../spec.yaml
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case-with-digits/name_normalizer.gen.go b/internal/test/outputoptions/name-normalizer/to-camel-case-with-digits/name_normalizer.gen.go
new file mode 100644
index 0000000000..071a7a7386
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case-with-digits/name_normalizer.gen.go
@@ -0,0 +1,629 @@
+// Package tocamelcasewithdigits provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package tocamelcasewithdigits
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gorilla/mux"
+ "github.com/oapi-codegen/runtime"
+ openapi_types "github.com/oapi-codegen/runtime/types"
+)
+
+// Error defines model for Error.
+type Error struct {
+ // Code Error code
+ Code int32 `json:"code"`
+
+ // Message Error message
+ Message string `json:"message"`
+}
+
+// OneOf2Things Notice that the `things` is not capitalised
+type OneOf2Things struct {
+ union json.RawMessage
+}
+
+// OneOf2Things0 defines model for .
+type OneOf2Things0 struct {
+ Id int `json:"id"`
+}
+
+// OneOf2Things1 defines model for .
+type OneOf2Things1 struct {
+ Id openapi_types.UUID `json:"id"`
+}
+
+// Pet defines model for Pet.
+type Pet struct {
+ // Name The name of the pet.
+ Name string `json:"name"`
+
+ // Uuid The pet uuid.
+ Uuid string `json:"uuid"`
+}
+
+// AsOneOf2Things0 returns the union data inside the OneOf2Things as a OneOf2Things0
+func (t OneOf2Things) AsOneOf2Things0() (OneOf2Things0, error) {
+ var body OneOf2Things0
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOf2Things0 overwrites any union data inside the OneOf2Things as the provided OneOf2Things0
+func (t *OneOf2Things) FromOneOf2Things0(v OneOf2Things0) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOf2Things0 performs a merge with any union data inside the OneOf2Things, using the provided OneOf2Things0
+func (t *OneOf2Things) MergeOneOf2Things0(v OneOf2Things0) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsOneOf2Things1 returns the union data inside the OneOf2Things as a OneOf2Things1
+func (t OneOf2Things) AsOneOf2Things1() (OneOf2Things1, error) {
+ var body OneOf2Things1
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOf2Things1 overwrites any union data inside the OneOf2Things as the provided OneOf2Things1
+func (t *OneOf2Things) FromOneOf2Things1(v OneOf2Things1) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOf2Things1 performs a merge with any union data inside the OneOf2Things, using the provided OneOf2Things1
+func (t *OneOf2Things) MergeOneOf2Things1(v OneOf2Things1) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t OneOf2Things) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *OneOf2Things) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetHttpPet request
+ GetHttpPet(ctx context.Context, petId string, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetHttpPet(ctx context.Context, petId string, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetHttpPetRequest(c.Server, petId)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetHttpPetRequest generates requests for GetHttpPet
+func NewGetHttpPetRequest(server string, petId string) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "petId", petId, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/api/pets/%s", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetHttpPetWithResponse request
+ GetHttpPetWithResponse(ctx context.Context, petId string, reqEditors ...RequestEditorFn) (*GetHttpPetResponse, error)
+}
+
+type GetHttpPetResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Pet
+}
+
+// GetJSON200 returns JSON200
+func (r GetHttpPetResponse) GetJSON200() *Pet {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetHttpPetResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetHttpPetResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetHttpPetResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetHttpPetResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetHttpPetWithResponse request returning *GetHttpPetResponse
+func (c *ClientWithResponses) GetHttpPetWithResponse(ctx context.Context, petId string, reqEditors ...RequestEditorFn) (*GetHttpPetResponse, error) {
+ rsp, err := c.GetHttpPet(ctx, petId, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetHttpPetResponse(rsp)
+}
+
+// ParseGetHttpPetResponse parses an HTTP response from a GetHttpPetWithResponse call
+func ParseGetHttpPetResponse(rsp *http.Response) (*GetHttpPetResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetHttpPetResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Pet
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // Get pet given identifier.
+ // (GET /api/pets/{petId})
+ GetHttpPet(w http.ResponseWriter, r *http.Request, petId string)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetHttpPet operation middleware
+func (siw *ServerInterfaceWrapper) GetHttpPet(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "petId" -------------
+ var petId string
+
+ err = runtime.BindStyledParameterWithOptions("simple", "petId", mux.Vars(r)["petId"], &petId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "petId", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetHttpPet(w, r, petId)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+ BaseURL string
+ BaseRouter *mux.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = mux.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.HandleFunc(options.BaseURL+"/api/pets/{petId}", wrapper.GetHttpPet).Methods(http.MethodGet)
+
+ return r
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "hFPNjtMwEH4Va+BoktK95b6CvbAcuK0q1cSTZFaJbexJxVLl3dHYbSltV720jmf8+fvx7KH1U/AOHSdo",
+ "9pDaASeTl48x+iiLEH3AyIR5u/UW5d9iaiMFJu+gKc0q1zR0Pk6GoQFy/LAGDfwWsHxijxEWDROmZPp3",
+ "gY7l09HEkVwPy6Ih4q+ZIlpoXuBw4bF9s2h4dvjcrXkg16dr+G+eqUXFg2HFA6ptadwqSsp5Vq0JxGak",
+ "hBY0eMGC5uXSA7Lye6nqghtZ2Jz4+5+v2DIs+jbUybF5JntX9U1k0f4d+TowZ6YbPv8YUElF+S4bEZCr",
+ "64t1IXTzdEBWUq3u8j2IykSuiUs3uc5nS4lHqT3+NlMYMT8o1flYshKAT06sGukPxq3yM4eZlS+0NOww",
+ "pkLwc7WqVsLfB3QmEDTwkLc0BMNDNqY2geqAnOp9QH6yi2z2xUIx0Ajqk4UGviB/ZQ5ir5yPZkLGmPLL",
+ "ILlOMI8KG8hocO4Bxxn1YbjOns7Jr400p+BdKpmtV6sya47RZUImhJHaTKl+TaJxf4b3MWIHDXyo/01z",
+ "fRjlWlhnk/+PcGdGshJijivN02TiW9Gao+1ph06RRcfUEcZKQJa/AQAA//8=",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case-with-digits/name_normalizer_test.go b/internal/test/outputoptions/name-normalizer/to-camel-case-with-digits/name_normalizer_test.go
new file mode 100644
index 0000000000..32a01436e9
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case-with-digits/name_normalizer_test.go
@@ -0,0 +1,24 @@
+package tocamelcasewithdigits
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGenCodeHasCorrectNames(t *testing.T) {
+ pet := &Pet{}
+ assert.Equal(t, "", pet.Name)
+ assert.Equal(t, "", pet.Uuid)
+
+ uri := "https://my-api.com/some-base-url/v1/"
+ client, err := NewClient(uri)
+ assert.Nil(t, err)
+ assert.NotNil(t, client.GetHttpPet)
+
+ server := &ServerInterfaceWrapper{}
+ assert.NotNil(t, server.GetHttpPet)
+
+ oneOf := OneOf2Things{}
+ assert.Zero(t, oneOf)
+}
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case-with-initialisms/config.yaml b/internal/test/outputoptions/name-normalizer/to-camel-case-with-initialisms/config.yaml
new file mode 100644
index 0000000000..63e903aeaf
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case-with-initialisms/config.yaml
@@ -0,0 +1,11 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
+package: tocamelcasewithinitialisms
+generate:
+ gorilla-server: true
+ client: true
+ models: true
+ embedded-spec: true
+output: name_normalizer.gen.go
+output-options:
+ skip-prune: true
+ name-normalizer: ToCamelCaseWithInitialisms
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case-with-initialisms/generate.go b/internal/test/outputoptions/name-normalizer/to-camel-case-with-initialisms/generate.go
new file mode 100644
index 0000000000..5f65491318
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case-with-initialisms/generate.go
@@ -0,0 +1,3 @@
+package tocamelcasewithinitialisms
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../spec.yaml
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case-with-initialisms/name_normalizer.gen.go b/internal/test/outputoptions/name-normalizer/to-camel-case-with-initialisms/name_normalizer.gen.go
new file mode 100644
index 0000000000..5ed20a5756
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case-with-initialisms/name_normalizer.gen.go
@@ -0,0 +1,629 @@
+// Package tocamelcasewithinitialisms provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package tocamelcasewithinitialisms
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gorilla/mux"
+ "github.com/oapi-codegen/runtime"
+ openapi_types "github.com/oapi-codegen/runtime/types"
+)
+
+// Error defines model for Error.
+type Error struct {
+ // Code Error code
+ Code int32 `json:"code"`
+
+ // Message Error message
+ Message string `json:"message"`
+}
+
+// OneOf2Things Notice that the `things` is not capitalised
+type OneOf2Things struct {
+ union json.RawMessage
+}
+
+// OneOf2Things0 defines model for .
+type OneOf2Things0 struct {
+ ID int `json:"id"`
+}
+
+// OneOf2Things1 defines model for .
+type OneOf2Things1 struct {
+ ID openapi_types.UUID `json:"id"`
+}
+
+// Pet defines model for Pet.
+type Pet struct {
+ // Name The name of the pet.
+ Name string `json:"name"`
+
+ // UUID The pet uuid.
+ UUID string `json:"uuid"`
+}
+
+// AsOneOf2Things0 returns the union data inside the OneOf2Things as a OneOf2Things0
+func (t OneOf2Things) AsOneOf2Things0() (OneOf2Things0, error) {
+ var body OneOf2Things0
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOf2Things0 overwrites any union data inside the OneOf2Things as the provided OneOf2Things0
+func (t *OneOf2Things) FromOneOf2Things0(v OneOf2Things0) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOf2Things0 performs a merge with any union data inside the OneOf2Things, using the provided OneOf2Things0
+func (t *OneOf2Things) MergeOneOf2Things0(v OneOf2Things0) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsOneOf2Things1 returns the union data inside the OneOf2Things as a OneOf2Things1
+func (t OneOf2Things) AsOneOf2Things1() (OneOf2Things1, error) {
+ var body OneOf2Things1
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOf2Things1 overwrites any union data inside the OneOf2Things as the provided OneOf2Things1
+func (t *OneOf2Things) FromOneOf2Things1(v OneOf2Things1) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOf2Things1 performs a merge with any union data inside the OneOf2Things, using the provided OneOf2Things1
+func (t *OneOf2Things) MergeOneOf2Things1(v OneOf2Things1) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t OneOf2Things) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *OneOf2Things) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetHTTPPet request
+ GetHTTPPet(ctx context.Context, petID string, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetHTTPPet(ctx context.Context, petID string, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetHTTPPetRequest(c.Server, petID)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetHTTPPetRequest generates requests for GetHTTPPet
+func NewGetHTTPPetRequest(server string, petID string) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "petId", petID, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/api/pets/%s", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetHTTPPetWithResponse request
+ GetHTTPPetWithResponse(ctx context.Context, petID string, reqEditors ...RequestEditorFn) (*GetHTTPPetResponse, error)
+}
+
+type GetHTTPPetResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Pet
+}
+
+// GetJSON200 returns JSON200
+func (r GetHTTPPetResponse) GetJSON200() *Pet {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetHTTPPetResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetHTTPPetResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetHTTPPetResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetHTTPPetResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetHTTPPetWithResponse request returning *GetHTTPPetResponse
+func (c *ClientWithResponses) GetHTTPPetWithResponse(ctx context.Context, petID string, reqEditors ...RequestEditorFn) (*GetHTTPPetResponse, error) {
+ rsp, err := c.GetHTTPPet(ctx, petID, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetHTTPPetResponse(rsp)
+}
+
+// ParseGetHTTPPetResponse parses an HTTP response from a GetHTTPPetWithResponse call
+func ParseGetHTTPPetResponse(rsp *http.Response) (*GetHTTPPetResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetHTTPPetResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Pet
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // Get pet given identifier.
+ // (GET /api/pets/{petId})
+ GetHTTPPet(w http.ResponseWriter, r *http.Request, petID string)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetHTTPPet operation middleware
+func (siw *ServerInterfaceWrapper) GetHTTPPet(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "petId" -------------
+ var petID string
+
+ err = runtime.BindStyledParameterWithOptions("simple", "petId", mux.Vars(r)["petId"], &petID, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "petId", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetHTTPPet(w, r, petID)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+ BaseURL string
+ BaseRouter *mux.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = mux.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.HandleFunc(options.BaseURL+"/api/pets/{petId}", wrapper.GetHTTPPet).Methods(http.MethodGet)
+
+ return r
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "hFNNb9s8DP4rAt/3qNlZevO92HpZe8itCBDNom0WtqRJdLAu8H8fKCVZlmToJZFF6tHzIR6g9VPwDh0n",
+ "aA6Q2gEnk5ePMfooixB9wMiEebv1FuXfYmojBSbvoCnNKtc0dD5OhqEBcvywBg38HrB8Yo8RFg0TpmT6",
+ "fwKdyuejiSO5HpZFQ8QfM0W00LzC8cJT+3bR8OzwuVvzQK5Pt/DfPFOLigfDigdUu9K4U5SU86xaE4jN",
+ "SAktaPCCBc3rtQdk5fda1RU3srA98/ff37BlWPR9qLNj80z2Q9V3kUX7C/JtYM5Md3zeDKikonyXjQjI",
+ "1e3FuhC6ezogK6lWH/I9ispEbolLN7nOZ0uJR6k9/jRTGDE/KNX5WLISgE9OrBrpF8ad8jOHmZUvtDTs",
+ "MaZC8HO1qlbC3wd0JhA08JC3NATDQzamNoHqgJzqQ0B+sots9sVCMdAI6pOFBr4gf91sXsReOR/NhIwx",
+ "5ZdBcp1gnhQ2kNHg0gOOM+rjcF08nbNfW2lOwbtUMluvVmXWHKPLhEwII7WZUv2WROPhAu//iB008F/9",
+ "Z5rr4yjXwjqb/HeEezOSlRBzXGmeJhPfi9YcbU97dIosOqaOMFYCsvwOAAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case-with-initialisms/name_normalizer_test.go b/internal/test/outputoptions/name-normalizer/to-camel-case-with-initialisms/name_normalizer_test.go
new file mode 100644
index 0000000000..fea7b84dc5
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case-with-initialisms/name_normalizer_test.go
@@ -0,0 +1,24 @@
+package tocamelcasewithinitialisms
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGenCodeHasCorrectNames(t *testing.T) {
+ pet := &Pet{}
+ assert.Equal(t, "", pet.Name)
+ assert.Equal(t, "", pet.UUID)
+
+ uri := "https://my-api.com/some-base-url/v1/"
+ client, err := NewClient(uri)
+ assert.Nil(t, err)
+ assert.NotNil(t, client.GetHTTPPet)
+
+ server := &ServerInterfaceWrapper{}
+ assert.NotNil(t, server.GetHTTPPet)
+
+ oneOf := OneOf2Things{}
+ assert.Zero(t, oneOf)
+}
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case/config.yaml b/internal/test/outputoptions/name-normalizer/to-camel-case/config.yaml
new file mode 100644
index 0000000000..b80cdda8eb
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case/config.yaml
@@ -0,0 +1,11 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
+package: tocamelcase
+generate:
+ gorilla-server: true
+ client: true
+ models: true
+ embedded-spec: true
+output: name_normalizer.gen.go
+output-options:
+ skip-prune: true
+ name-normalizer: ToCamelCase
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case/generate.go b/internal/test/outputoptions/name-normalizer/to-camel-case/generate.go
new file mode 100644
index 0000000000..a6c179b79d
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case/generate.go
@@ -0,0 +1,3 @@
+package tocamelcase
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../spec.yaml
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case/name_normalizer.gen.go b/internal/test/outputoptions/name-normalizer/to-camel-case/name_normalizer.gen.go
new file mode 100644
index 0000000000..08c90baded
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case/name_normalizer.gen.go
@@ -0,0 +1,629 @@
+// Package tocamelcase provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package tocamelcase
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gorilla/mux"
+ "github.com/oapi-codegen/runtime"
+ openapi_types "github.com/oapi-codegen/runtime/types"
+)
+
+// Error defines model for Error.
+type Error struct {
+ // Code Error code
+ Code int32 `json:"code"`
+
+ // Message Error message
+ Message string `json:"message"`
+}
+
+// OneOf2things Notice that the `things` is not capitalised
+type OneOf2things struct {
+ union json.RawMessage
+}
+
+// OneOf2things0 defines model for .
+type OneOf2things0 struct {
+ Id int `json:"id"`
+}
+
+// OneOf2things1 defines model for .
+type OneOf2things1 struct {
+ Id openapi_types.UUID `json:"id"`
+}
+
+// Pet defines model for Pet.
+type Pet struct {
+ // Name The name of the pet.
+ Name string `json:"name"`
+
+ // Uuid The pet uuid.
+ Uuid string `json:"uuid"`
+}
+
+// AsOneOf2things0 returns the union data inside the OneOf2things as a OneOf2things0
+func (t OneOf2things) AsOneOf2things0() (OneOf2things0, error) {
+ var body OneOf2things0
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOf2things0 overwrites any union data inside the OneOf2things as the provided OneOf2things0
+func (t *OneOf2things) FromOneOf2things0(v OneOf2things0) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOf2things0 performs a merge with any union data inside the OneOf2things, using the provided OneOf2things0
+func (t *OneOf2things) MergeOneOf2things0(v OneOf2things0) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsOneOf2things1 returns the union data inside the OneOf2things as a OneOf2things1
+func (t OneOf2things) AsOneOf2things1() (OneOf2things1, error) {
+ var body OneOf2things1
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOf2things1 overwrites any union data inside the OneOf2things as the provided OneOf2things1
+func (t *OneOf2things) FromOneOf2things1(v OneOf2things1) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOf2things1 performs a merge with any union data inside the OneOf2things, using the provided OneOf2things1
+func (t *OneOf2things) MergeOneOf2things1(v OneOf2things1) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t OneOf2things) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *OneOf2things) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetHttpPet request
+ GetHttpPet(ctx context.Context, petId string, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetHttpPet(ctx context.Context, petId string, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetHttpPetRequest(c.Server, petId)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetHttpPetRequest generates requests for GetHttpPet
+func NewGetHttpPetRequest(server string, petId string) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "petId", petId, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/api/pets/%s", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetHttpPetWithResponse request
+ GetHttpPetWithResponse(ctx context.Context, petId string, reqEditors ...RequestEditorFn) (*GetHttpPetResponse, error)
+}
+
+type GetHttpPetResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Pet
+}
+
+// GetJSON200 returns JSON200
+func (r GetHttpPetResponse) GetJSON200() *Pet {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetHttpPetResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetHttpPetResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetHttpPetResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetHttpPetResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetHttpPetWithResponse request returning *GetHttpPetResponse
+func (c *ClientWithResponses) GetHttpPetWithResponse(ctx context.Context, petId string, reqEditors ...RequestEditorFn) (*GetHttpPetResponse, error) {
+ rsp, err := c.GetHttpPet(ctx, petId, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetHttpPetResponse(rsp)
+}
+
+// ParseGetHttpPetResponse parses an HTTP response from a GetHttpPetWithResponse call
+func ParseGetHttpPetResponse(rsp *http.Response) (*GetHttpPetResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetHttpPetResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Pet
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // Get pet given identifier.
+ // (GET /api/pets/{petId})
+ GetHttpPet(w http.ResponseWriter, r *http.Request, petId string)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetHttpPet operation middleware
+func (siw *ServerInterfaceWrapper) GetHttpPet(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "petId" -------------
+ var petId string
+
+ err = runtime.BindStyledParameterWithOptions("simple", "petId", mux.Vars(r)["petId"], &petId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "petId", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetHttpPet(w, r, petId)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+ BaseURL string
+ BaseRouter *mux.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = mux.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.HandleFunc(options.BaseURL+"/api/pets/{petId}", wrapper.GetHttpPet).Methods(http.MethodGet)
+
+ return r
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "hFPNjtMwEH4Va+BoktK95b6CvbAcuK0q1cSTZFaJbexJxVLl3dHYbSltV720jmf8+fvx7KH1U/AOHSdo",
+ "9pDaASeTl48x+iiLEH3AyIR5u/UW5d9iaiMFJu+gKc0q1zR0Pk6GoQFy/LAGDfwWsHxijxEWDROmZPp3",
+ "gY7l09HEkVwPy6Ih4q+ZIlpoXuBw4bF9s2h4dvjcrXkg16dr+G+eqUXFg2HFA6ptadwqSsp5Vq0JxGak",
+ "hBY0eMGC5uXSA7Lye6nqghtZ2Jz4+5+v2DIs+jbUybF5JntX9U1k0f4d+TowZ6YbPv8YUElF+S4bEZCr",
+ "64t1IXTzdEBWUq3u8j2IykSuiUs3uc5nS4lHqT3+NlMYMT8o1flYshKAT06sGukPxq3yM4eZlS+0NOww",
+ "pkLwc7WqVsLfB3QmEDTwkLc0BMNDNqY2geqAnOp9QH6yi2z2xUIx0Ajqk4UGviB/ZQ5ir5yPZkLGmPLL",
+ "ILlOMI8KG8hocO4Bxxn1YbjOns7Jr400p+BdKpmtV6sya47RZUImhJHaTKl+TaJxf4b3MWIHDXyo/01z",
+ "fRjlWlhnk/+PcGdGshJijivN02TiW9Gao+1ph06RRcfUEcZKQJa/AQAA//8=",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/outputoptions/name-normalizer/to-camel-case/name_normalizer_test.go b/internal/test/outputoptions/name-normalizer/to-camel-case/name_normalizer_test.go
new file mode 100644
index 0000000000..3e0d83fa86
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/to-camel-case/name_normalizer_test.go
@@ -0,0 +1,24 @@
+package tocamelcase
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGenCodeHasCorrectNames(t *testing.T) {
+ pet := &Pet{}
+ assert.Equal(t, "", pet.Name)
+ assert.Equal(t, "", pet.Uuid)
+
+ uri := "https://my-api.com/some-base-url/v1/"
+ client, err := NewClient(uri)
+ assert.Nil(t, err)
+ assert.NotNil(t, client.GetHttpPet)
+
+ server := &ServerInterfaceWrapper{}
+ assert.NotNil(t, server.GetHttpPet)
+
+ oneOf := OneOf2things{}
+ assert.Zero(t, oneOf)
+}
diff --git a/internal/test/outputoptions/name-normalizer/unset/config.yaml b/internal/test/outputoptions/name-normalizer/unset/config.yaml
new file mode 100644
index 0000000000..bd2918ed51
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/unset/config.yaml
@@ -0,0 +1,11 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
+package: unset
+generate:
+ gorilla-server: true
+ client: true
+ models: true
+ embedded-spec: true
+output: name_normalizer.gen.go
+output-options:
+ skip-prune: true
+ # When `name-normalizer` is unset
diff --git a/internal/test/outputoptions/name-normalizer/unset/generate.go b/internal/test/outputoptions/name-normalizer/unset/generate.go
new file mode 100644
index 0000000000..84fac60cba
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/unset/generate.go
@@ -0,0 +1,3 @@
+package unset
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../spec.yaml
diff --git a/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go b/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go
new file mode 100644
index 0000000000..cbdde2a4ef
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go
@@ -0,0 +1,629 @@
+// Package unset provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package unset
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gorilla/mux"
+ "github.com/oapi-codegen/runtime"
+ openapi_types "github.com/oapi-codegen/runtime/types"
+)
+
+// Error defines model for Error.
+type Error struct {
+ // Code Error code
+ Code int32 `json:"code"`
+
+ // Message Error message
+ Message string `json:"message"`
+}
+
+// OneOf2things Notice that the `things` is not capitalised
+type OneOf2things struct {
+ union json.RawMessage
+}
+
+// OneOf2things0 defines model for .
+type OneOf2things0 struct {
+ Id int `json:"id"`
+}
+
+// OneOf2things1 defines model for .
+type OneOf2things1 struct {
+ Id openapi_types.UUID `json:"id"`
+}
+
+// Pet defines model for Pet.
+type Pet struct {
+ // Name The name of the pet.
+ Name string `json:"name"`
+
+ // Uuid The pet uuid.
+ Uuid string `json:"uuid"`
+}
+
+// AsOneOf2things0 returns the union data inside the OneOf2things as a OneOf2things0
+func (t OneOf2things) AsOneOf2things0() (OneOf2things0, error) {
+ var body OneOf2things0
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOf2things0 overwrites any union data inside the OneOf2things as the provided OneOf2things0
+func (t *OneOf2things) FromOneOf2things0(v OneOf2things0) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOf2things0 performs a merge with any union data inside the OneOf2things, using the provided OneOf2things0
+func (t *OneOf2things) MergeOneOf2things0(v OneOf2things0) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsOneOf2things1 returns the union data inside the OneOf2things as a OneOf2things1
+func (t OneOf2things) AsOneOf2things1() (OneOf2things1, error) {
+ var body OneOf2things1
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromOneOf2things1 overwrites any union data inside the OneOf2things as the provided OneOf2things1
+func (t *OneOf2things) FromOneOf2things1(v OneOf2things1) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeOneOf2things1 performs a merge with any union data inside the OneOf2things, using the provided OneOf2things1
+func (t *OneOf2things) MergeOneOf2things1(v OneOf2things1) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t OneOf2things) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *OneOf2things) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetHttpPet request
+ GetHttpPet(ctx context.Context, petId string, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetHttpPet(ctx context.Context, petId string, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetHttpPetRequest(c.Server, petId)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetHttpPetRequest generates requests for GetHttpPet
+func NewGetHttpPetRequest(server string, petId string) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "petId", petId, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/api/pets/%s", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetHttpPetWithResponse request
+ GetHttpPetWithResponse(ctx context.Context, petId string, reqEditors ...RequestEditorFn) (*GetHttpPetResponse, error)
+}
+
+type GetHttpPetResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Pet
+}
+
+// GetJSON200 returns JSON200
+func (r GetHttpPetResponse) GetJSON200() *Pet {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetHttpPetResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetHttpPetResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetHttpPetResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetHttpPetResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetHttpPetWithResponse request returning *GetHttpPetResponse
+func (c *ClientWithResponses) GetHttpPetWithResponse(ctx context.Context, petId string, reqEditors ...RequestEditorFn) (*GetHttpPetResponse, error) {
+ rsp, err := c.GetHttpPet(ctx, petId, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetHttpPetResponse(rsp)
+}
+
+// ParseGetHttpPetResponse parses an HTTP response from a GetHttpPetWithResponse call
+func ParseGetHttpPetResponse(rsp *http.Response) (*GetHttpPetResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetHttpPetResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Pet
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // Get pet given identifier.
+ // (GET /api/pets/{petId})
+ GetHttpPet(w http.ResponseWriter, r *http.Request, petId string)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetHttpPet operation middleware
+func (siw *ServerInterfaceWrapper) GetHttpPet(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "petId" -------------
+ var petId string
+
+ err = runtime.BindStyledParameterWithOptions("simple", "petId", mux.Vars(r)["petId"], &petId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "petId", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetHttpPet(w, r, petId)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+ BaseURL string
+ BaseRouter *mux.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = mux.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.HandleFunc(options.BaseURL+"/api/pets/{petId}", wrapper.GetHttpPet).Methods(http.MethodGet)
+
+ return r
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "hFPNjtMwEH4Va+BoktK95b6CvbAcuK0q1cSTZFaJbexJxVLl3dHYbSltV720jmf8+fvx7KH1U/AOHSdo",
+ "9pDaASeTl48x+iiLEH3AyIR5u/UW5d9iaiMFJu+gKc0q1zR0Pk6GoQFy/LAGDfwWsHxijxEWDROmZPp3",
+ "gY7l09HEkVwPy6Ih4q+ZIlpoXuBw4bF9s2h4dvjcrXkg16dr+G+eqUXFg2HFA6ptadwqSsp5Vq0JxGak",
+ "hBY0eMGC5uXSA7Lye6nqghtZ2Jz4+5+v2DIs+jbUybF5JntX9U1k0f4d+TowZ6YbPv8YUElF+S4bEZCr",
+ "64t1IXTzdEBWUq3u8j2IykSuiUs3uc5nS4lHqT3+NlMYMT8o1flYshKAT06sGukPxq3yM4eZlS+0NOww",
+ "pkLwc7WqVsLfB3QmEDTwkLc0BMNDNqY2geqAnOp9QH6yi2z2xUIx0Ajqk4UGviB/ZQ5ir5yPZkLGmPLL",
+ "ILlOMI8KG8hocO4Bxxn1YbjOns7Jr400p+BdKpmtV6sya47RZUImhJHaTKl+TaJxf4b3MWIHDXyo/01z",
+ "fRjlWlhnk/+PcGdGshJijivN02TiW9Gao+1ph06RRcfUEcZKQJa/AQAA//8=",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/outputoptions/name-normalizer/unset/name_normalizer_test.go b/internal/test/outputoptions/name-normalizer/unset/name_normalizer_test.go
new file mode 100644
index 0000000000..9702a59c40
--- /dev/null
+++ b/internal/test/outputoptions/name-normalizer/unset/name_normalizer_test.go
@@ -0,0 +1,24 @@
+package unset
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestGenCodeHasCorrectNames(t *testing.T) {
+ pet := &Pet{}
+ assert.Equal(t, "", pet.Name)
+ assert.Equal(t, "", pet.Uuid)
+
+ uri := "https://my-api.com/some-base-url/v1/"
+ client, err := NewClient(uri)
+ assert.Nil(t, err)
+ assert.NotNil(t, client.GetHttpPet)
+
+ server := &ServerInterfaceWrapper{}
+ assert.NotNil(t, server.GetHttpPet)
+
+ oneOf := OneOf2things{}
+ assert.Zero(t, oneOf)
+}
diff --git a/internal/test/outputoptions/response-body-getters/enabled/config.yaml b/internal/test/outputoptions/response-body-getters/enabled/config.yaml
new file mode 100644
index 0000000000..a6cf561aef
--- /dev/null
+++ b/internal/test/outputoptions/response-body-getters/enabled/config.yaml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
+package: enabled
+generate:
+ client: true
+ models: true
+output: response_body_getters.gen.go
+# `skip-response-body-getters` is left unset — getters should be generated by default.
diff --git a/internal/test/outputoptions/response-body-getters/enabled/generate.go b/internal/test/outputoptions/response-body-getters/enabled/generate.go
new file mode 100644
index 0000000000..65f76d2547
--- /dev/null
+++ b/internal/test/outputoptions/response-body-getters/enabled/generate.go
@@ -0,0 +1,3 @@
+package enabled
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../spec.yaml
diff --git a/internal/test/outputoptions/response-body-getters/enabled/response_body_getters.gen.go b/internal/test/outputoptions/response-body-getters/enabled/response_body_getters.gen.go
new file mode 100644
index 0000000000..28f7addd07
--- /dev/null
+++ b/internal/test/outputoptions/response-body-getters/enabled/response_body_getters.gen.go
@@ -0,0 +1,286 @@
+// Package enabled provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package enabled
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// Error defines model for Error.
+type Error struct {
+ Code int32 `json:"code"`
+ Message string `json:"message"`
+}
+
+// Thing defines model for Thing.
+type Thing struct {
+ Id string `json:"id"`
+ Name string `json:"name"`
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetThing request
+ GetThing(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetThing(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetThingRequest(c.Server, id)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetThingRequest generates requests for GetThing
+func NewGetThingRequest(server string, id string) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "id", id, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/things/%s", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetThingWithResponse request
+ GetThingWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetThingResponse, error)
+}
+
+type GetThingResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Thing
+ JSONDefault *Error
+}
+
+// GetJSON200 returns JSON200
+func (r GetThingResponse) GetJSON200() *Thing {
+ return r.JSON200
+}
+
+// GetJSONDefault returns JSONDefault
+func (r GetThingResponse) GetJSONDefault() *Error {
+ return r.JSONDefault
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetThingResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetThingResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetThingResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetThingResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetThingWithResponse request returning *GetThingResponse
+func (c *ClientWithResponses) GetThingWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetThingResponse, error) {
+ rsp, err := c.GetThing(ctx, id, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetThingResponse(rsp)
+}
+
+// ParseGetThingResponse parses an HTTP response from a GetThingWithResponse call
+func ParseGetThingResponse(rsp *http.Response) (*GetThingResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetThingResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Thing
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && true:
+ var dest Error
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSONDefault = &dest
+
+ }
+
+ return response, nil
+}
diff --git a/internal/test/outputoptions/response-body-getters/enabled/response_body_getters_test.go b/internal/test/outputoptions/response-body-getters/enabled/response_body_getters_test.go
new file mode 100644
index 0000000000..e8ae57a20a
--- /dev/null
+++ b/internal/test/outputoptions/response-body-getters/enabled/response_body_getters_test.go
@@ -0,0 +1,50 @@
+package enabled
+
+import (
+ "net/http"
+ "reflect"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+// When `skip-response-body-getters` is unset (default), the generated response
+// type must expose `GetBody()` and a typed getter for each response field.
+func TestResponseBodyGettersGenerated(t *testing.T) {
+ respType := reflect.TypeOf(GetThingResponse{})
+
+ t.Run("GetBody returns the raw body", func(t *testing.T) {
+ m, ok := respType.MethodByName("GetBody")
+ require.True(t, ok, "GetBody method should be generated")
+
+ // signature: func (r GetThingResponse) GetBody() []byte
+ require.Equal(t, 1, m.Type.NumOut())
+ assert.Equal(t, reflect.TypeOf([]byte(nil)), m.Type.Out(0))
+
+ body := []byte("hello")
+ r := GetThingResponse{Body: body, HTTPResponse: &http.Response{}}
+ assert.Equal(t, body, r.GetBody())
+ })
+
+ t.Run("typed JSON200 getter returns the decoded payload", func(t *testing.T) {
+ m, ok := respType.MethodByName("GetJSON200")
+ require.True(t, ok, "GetJSON200 method should be generated")
+
+ // signature: func (r GetThingResponse) GetJSON200() *Thing
+ require.Equal(t, 1, m.Type.NumOut())
+ assert.Equal(t, reflect.TypeOf(&Thing{}), m.Type.Out(0))
+
+ thing := &Thing{Id: "1", Name: "rock"}
+ r := GetThingResponse{JSON200: thing}
+ assert.Same(t, thing, r.GetJSON200())
+ })
+
+ t.Run("typed JSONDefault getter returns the decoded error payload", func(t *testing.T) {
+ m, ok := respType.MethodByName("GetJSONDefault")
+ require.True(t, ok, "GetJSONDefault method should be generated")
+
+ require.Equal(t, 1, m.Type.NumOut())
+ assert.Equal(t, reflect.TypeOf(&Error{}), m.Type.Out(0))
+ })
+}
diff --git a/internal/test/outputoptions/response-body-getters/skipped/config.yaml b/internal/test/outputoptions/response-body-getters/skipped/config.yaml
new file mode 100644
index 0000000000..e637348f02
--- /dev/null
+++ b/internal/test/outputoptions/response-body-getters/skipped/config.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../../../configuration-schema.json
+package: skipped
+generate:
+ client: true
+ models: true
+output: response_body_getters.gen.go
+output-options:
+ skip-response-body-getters: true
diff --git a/internal/test/outputoptions/response-body-getters/skipped/generate.go b/internal/test/outputoptions/response-body-getters/skipped/generate.go
new file mode 100644
index 0000000000..5ecbce0b91
--- /dev/null
+++ b/internal/test/outputoptions/response-body-getters/skipped/generate.go
@@ -0,0 +1,3 @@
+package skipped
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../spec.yaml
diff --git a/internal/test/outputoptions/response-body-getters/skipped/response_body_getters.gen.go b/internal/test/outputoptions/response-body-getters/skipped/response_body_getters.gen.go
new file mode 100644
index 0000000000..e071efe847
--- /dev/null
+++ b/internal/test/outputoptions/response-body-getters/skipped/response_body_getters.gen.go
@@ -0,0 +1,271 @@
+// Package skipped provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package skipped
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// Error defines model for Error.
+type Error struct {
+ Code int32 `json:"code"`
+ Message string `json:"message"`
+}
+
+// Thing defines model for Thing.
+type Thing struct {
+ Id string `json:"id"`
+ Name string `json:"name"`
+}
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetThing request
+ GetThing(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetThing(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetThingRequest(c.Server, id)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetThingRequest generates requests for GetThing
+func NewGetThingRequest(server string, id string) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "id", id, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/things/%s", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetThingWithResponse request
+ GetThingWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetThingResponse, error)
+}
+
+type GetThingResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Thing
+ JSONDefault *Error
+}
+
+// Status returns HTTPResponse.Status
+func (r GetThingResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetThingResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetThingResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetThingWithResponse request returning *GetThingResponse
+func (c *ClientWithResponses) GetThingWithResponse(ctx context.Context, id string, reqEditors ...RequestEditorFn) (*GetThingResponse, error) {
+ rsp, err := c.GetThing(ctx, id, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetThingResponse(rsp)
+}
+
+// ParseGetThingResponse parses an HTTP response from a GetThingWithResponse call
+func ParseGetThingResponse(rsp *http.Response) (*GetThingResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetThingResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Thing
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && true:
+ var dest Error
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSONDefault = &dest
+
+ }
+
+ return response, nil
+}
diff --git a/internal/test/outputoptions/response-body-getters/skipped/response_body_getters_test.go b/internal/test/outputoptions/response-body-getters/skipped/response_body_getters_test.go
new file mode 100644
index 0000000000..e852ee45b8
--- /dev/null
+++ b/internal/test/outputoptions/response-body-getters/skipped/response_body_getters_test.go
@@ -0,0 +1,24 @@
+package skipped
+
+import (
+ "reflect"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+// When `skip-response-body-getters: true`, the response type must NOT expose
+// `GetBody()` or any of the typed getters that the default template emits.
+func TestResponseBodyGettersSkipped(t *testing.T) {
+ respType := reflect.TypeOf(GetThingResponse{})
+
+ for _, name := range []string{"GetBody", "GetJSON200", "GetJSONDefault"} {
+ _, ok := respType.MethodByName(name)
+ assert.Falsef(t, ok, "method %s should not be generated when skip-response-body-getters is true", name)
+ }
+
+ // Sanity check that the response type itself is still generated — only the
+ // getters are skipped, not the struct.
+ _, ok := respType.FieldByName("Body")
+ assert.True(t, ok, "Body field should still be present on the response struct")
+}
diff --git a/internal/test/outputoptions/response-body-getters/spec.yaml b/internal/test/outputoptions/response-body-getters/spec.yaml
new file mode 100644
index 0000000000..3ad817ffe0
--- /dev/null
+++ b/internal/test/outputoptions/response-body-getters/spec.yaml
@@ -0,0 +1,51 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Example code for the `skip-response-body-getters` output option
+paths:
+ /things/{id}:
+ get:
+ summary: Get a thing by id
+ operationId: getThing
+ parameters:
+ - name: id
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: a thing
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Thing'
+ default:
+ description: error
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/Error'
+components:
+ schemas:
+ Thing:
+ type: object
+ required:
+ - id
+ - name
+ properties:
+ id:
+ type: string
+ name:
+ type: string
+ Error:
+ type: object
+ required:
+ - code
+ - message
+ properties:
+ code:
+ type: integer
+ format: int32
+ message:
+ type: string
diff --git a/internal/test/outputoptions/yaml-tags/config.yaml b/internal/test/outputoptions/yaml-tags/config.yaml
new file mode 100644
index 0000000000..6f1e3eef12
--- /dev/null
+++ b/internal/test/outputoptions/yaml-tags/config.yaml
@@ -0,0 +1,8 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: yamltags
+generate:
+ models: true
+output-options:
+ skip-prune: true
+ yaml-tags: true
+output: yamltags.go
diff --git a/internal/test/outputoptions/yaml-tags/generate.go b/internal/test/outputoptions/yaml-tags/generate.go
new file mode 100644
index 0000000000..1da2444608
--- /dev/null
+++ b/internal/test/outputoptions/yaml-tags/generate.go
@@ -0,0 +1,3 @@
+package yamltags
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml spec.yaml
diff --git a/internal/test/outputoptions/yaml-tags/spec.yaml b/internal/test/outputoptions/yaml-tags/spec.yaml
new file mode 100644
index 0000000000..f30596224f
--- /dev/null
+++ b/internal/test/outputoptions/yaml-tags/spec.yaml
@@ -0,0 +1,24 @@
+openapi: "3.0.1"
+info:
+ version: 1.0.0
+ title: Cookie parameters
+paths:
+ /cookies:
+ get:
+ operationId: cookieParams
+ parameters:
+ - name: authId
+ description: Cookie parameter
+ in: cookie
+ required: false
+ schema:
+ type: string
+ - name: serverId
+ description: Another cookie parameter
+ in: cookie
+ required: false
+ schema:
+ type: string
+ responses:
+ 204:
+ description: no content
diff --git a/internal/test/outputoptions/yaml-tags/yamltags.go b/internal/test/outputoptions/yaml-tags/yamltags.go
new file mode 100644
index 0000000000..6422e7391e
--- /dev/null
+++ b/internal/test/outputoptions/yaml-tags/yamltags.go
@@ -0,0 +1,13 @@
+// Package yamltags provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package yamltags
+
+// CookieParamsParams defines parameters for CookieParams.
+type CookieParamsParams struct {
+ // AuthId Cookie parameter
+ AuthId *string `form:"authId,omitempty" json:"authId,omitempty" yaml:"authId,omitempty"`
+
+ // ServerId Another cookie parameter
+ ServerId *string `form:"serverId,omitempty" json:"serverId,omitempty" yaml:"serverId,omitempty"`
+}
diff --git a/internal/test/parameters/chi/gen/server.gen.go b/internal/test/parameters/chi/gen/server.gen.go
new file mode 100644
index 0000000000..a32748c70d
--- /dev/null
+++ b/internal/test/parameters/chi/gen/server.gen.go
@@ -0,0 +1,1684 @@
+// Package chiparamsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package chiparamsgen
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/go-chi/chi/v5"
+ "github.com/oapi-codegen/runtime"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /contentObject/{param})
+ GetContentObject(w http.ResponseWriter, r *http.Request, param ComplexObject)
+
+ // (GET /cookie)
+ GetCookie(w http.ResponseWriter, r *http.Request, params GetCookieParams)
+
+ // (GET /enums)
+ EnumParams(w http.ResponseWriter, r *http.Request, params EnumParamsParams)
+
+ // (GET /header)
+ GetHeader(w http.ResponseWriter, r *http.Request, params GetHeaderParams)
+
+ // (GET /labelExplodeArray/{.param*})
+ GetLabelExplodeArray(w http.ResponseWriter, r *http.Request, param []int32)
+
+ // (GET /labelExplodeObject/{.param*})
+ GetLabelExplodeObject(w http.ResponseWriter, r *http.Request, param Object)
+
+ // (GET /labelExplodePrimitive/{.param*})
+ GetLabelExplodePrimitive(w http.ResponseWriter, r *http.Request, param int32)
+
+ // (GET /labelNoExplodeArray/{.param})
+ GetLabelNoExplodeArray(w http.ResponseWriter, r *http.Request, param []int32)
+
+ // (GET /labelNoExplodeObject/{.param})
+ GetLabelNoExplodeObject(w http.ResponseWriter, r *http.Request, param Object)
+
+ // (GET /labelPrimitive/{.param})
+ GetLabelPrimitive(w http.ResponseWriter, r *http.Request, param int32)
+
+ // (GET /matrixExplodeArray/{.id*})
+ GetMatrixExplodeArray(w http.ResponseWriter, r *http.Request, id []int32)
+
+ // (GET /matrixExplodeObject/{.id*})
+ GetMatrixExplodeObject(w http.ResponseWriter, r *http.Request, id Object)
+
+ // (GET /matrixExplodePrimitive/{;id*})
+ GetMatrixExplodePrimitive(w http.ResponseWriter, r *http.Request, id int32)
+
+ // (GET /matrixNoExplodeArray/{.id})
+ GetMatrixNoExplodeArray(w http.ResponseWriter, r *http.Request, id []int32)
+
+ // (GET /matrixNoExplodeObject/{.id})
+ GetMatrixNoExplodeObject(w http.ResponseWriter, r *http.Request, id Object)
+
+ // (GET /matrixPrimitive/{;id})
+ GetMatrixPrimitive(w http.ResponseWriter, r *http.Request, id int32)
+
+ // (GET /passThrough/{param})
+ GetPassThrough(w http.ResponseWriter, r *http.Request, param string)
+
+ // (GET /queryDeepObject)
+ GetDeepObject(w http.ResponseWriter, r *http.Request, params GetDeepObjectParams)
+
+ // (GET /queryDelimited)
+ GetQueryDelimited(w http.ResponseWriter, r *http.Request, params GetQueryDelimitedParams)
+
+ // (GET /queryForm)
+ GetQueryForm(w http.ResponseWriter, r *http.Request, params GetQueryFormParams)
+
+ // (GET /simpleExplodeArray/{param*})
+ GetSimpleExplodeArray(w http.ResponseWriter, r *http.Request, param []int32)
+
+ // (GET /simpleExplodeObject/{param*})
+ GetSimpleExplodeObject(w http.ResponseWriter, r *http.Request, param Object)
+
+ // (GET /simpleExplodePrimitive/{param})
+ GetSimpleExplodePrimitive(w http.ResponseWriter, r *http.Request, param int32)
+
+ // (GET /simpleNoExplodeArray/{param})
+ GetSimpleNoExplodeArray(w http.ResponseWriter, r *http.Request, param []int32)
+
+ // (GET /simpleNoExplodeObject/{param})
+ GetSimpleNoExplodeObject(w http.ResponseWriter, r *http.Request, param Object)
+
+ // (GET /simplePrimitive/{param})
+ GetSimplePrimitive(w http.ResponseWriter, r *http.Request, param int32)
+
+ // (GET /startingWithNumber/{1param})
+ GetStartingWithNumber(w http.ResponseWriter, r *http.Request, n1param string)
+}
+
+// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
+
+type Unimplemented struct{}
+
+// (GET /contentObject/{param})
+func (_ Unimplemented) GetContentObject(w http.ResponseWriter, r *http.Request, param ComplexObject) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /cookie)
+func (_ Unimplemented) GetCookie(w http.ResponseWriter, r *http.Request, params GetCookieParams) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /enums)
+func (_ Unimplemented) EnumParams(w http.ResponseWriter, r *http.Request, params EnumParamsParams) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /header)
+func (_ Unimplemented) GetHeader(w http.ResponseWriter, r *http.Request, params GetHeaderParams) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /labelExplodeArray/{.param*})
+func (_ Unimplemented) GetLabelExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /labelExplodeObject/{.param*})
+func (_ Unimplemented) GetLabelExplodeObject(w http.ResponseWriter, r *http.Request, param Object) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /labelExplodePrimitive/{.param*})
+func (_ Unimplemented) GetLabelExplodePrimitive(w http.ResponseWriter, r *http.Request, param int32) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /labelNoExplodeArray/{.param})
+func (_ Unimplemented) GetLabelNoExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /labelNoExplodeObject/{.param})
+func (_ Unimplemented) GetLabelNoExplodeObject(w http.ResponseWriter, r *http.Request, param Object) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /labelPrimitive/{.param})
+func (_ Unimplemented) GetLabelPrimitive(w http.ResponseWriter, r *http.Request, param int32) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /matrixExplodeArray/{.id*})
+func (_ Unimplemented) GetMatrixExplodeArray(w http.ResponseWriter, r *http.Request, id []int32) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /matrixExplodeObject/{.id*})
+func (_ Unimplemented) GetMatrixExplodeObject(w http.ResponseWriter, r *http.Request, id Object) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /matrixExplodePrimitive/{;id*})
+func (_ Unimplemented) GetMatrixExplodePrimitive(w http.ResponseWriter, r *http.Request, id int32) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /matrixNoExplodeArray/{.id})
+func (_ Unimplemented) GetMatrixNoExplodeArray(w http.ResponseWriter, r *http.Request, id []int32) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /matrixNoExplodeObject/{.id})
+func (_ Unimplemented) GetMatrixNoExplodeObject(w http.ResponseWriter, r *http.Request, id Object) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /matrixPrimitive/{;id})
+func (_ Unimplemented) GetMatrixPrimitive(w http.ResponseWriter, r *http.Request, id int32) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /passThrough/{param})
+func (_ Unimplemented) GetPassThrough(w http.ResponseWriter, r *http.Request, param string) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /queryDeepObject)
+func (_ Unimplemented) GetDeepObject(w http.ResponseWriter, r *http.Request, params GetDeepObjectParams) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /queryDelimited)
+func (_ Unimplemented) GetQueryDelimited(w http.ResponseWriter, r *http.Request, params GetQueryDelimitedParams) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /queryForm)
+func (_ Unimplemented) GetQueryForm(w http.ResponseWriter, r *http.Request, params GetQueryFormParams) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /simpleExplodeArray/{param*})
+func (_ Unimplemented) GetSimpleExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /simpleExplodeObject/{param*})
+func (_ Unimplemented) GetSimpleExplodeObject(w http.ResponseWriter, r *http.Request, param Object) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /simpleExplodePrimitive/{param})
+func (_ Unimplemented) GetSimpleExplodePrimitive(w http.ResponseWriter, r *http.Request, param int32) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /simpleNoExplodeArray/{param})
+func (_ Unimplemented) GetSimpleNoExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /simpleNoExplodeObject/{param})
+func (_ Unimplemented) GetSimpleNoExplodeObject(w http.ResponseWriter, r *http.Request, param Object) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /simplePrimitive/{param})
+func (_ Unimplemented) GetSimplePrimitive(w http.ResponseWriter, r *http.Request, param int32) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (GET /startingWithNumber/{1param})
+func (_ Unimplemented) GetStartingWithNumber(w http.ResponseWriter, r *http.Request, n1param string) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetContentObject operation middleware
+func (siw *ServerInterfaceWrapper) GetContentObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param ComplexObject
+
+ err = json.Unmarshal([]byte(chi.URLParam(r, "param")), ¶m)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetContentObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetCookie operation middleware
+func (siw *ServerInterfaceWrapper) GetCookie(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetCookieParams
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("p"); err == nil {
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "p", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "p", Err: err})
+ return
+ }
+ params.P = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("ep"); err == nil {
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ep", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ep", Err: err})
+ return
+ }
+ params.Ep = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("ea"); err == nil {
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ea", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ea", Err: err})
+ return
+ }
+ params.Ea = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("a"); err == nil {
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "a", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "a", Err: err})
+ return
+ }
+ params.A = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("eo"); err == nil {
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "eo", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "eo", Err: err})
+ return
+ }
+ params.Eo = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("o"); err == nil {
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "o", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "o", Err: err})
+ return
+ }
+ params.O = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("co"); err == nil {
+ var value ComplexObject
+ var decoded string
+ decoded, err := url.QueryUnescape(cookie.Value)
+ if err != nil {
+ err = fmt.Errorf("Error unescaping cookie parameter 'co'")
+ siw.ErrorHandlerFunc(w, r, &UnescapedCookieParamError{ParamName: "co", Err: err})
+ return
+ }
+
+ err = json.Unmarshal([]byte(decoded), &value)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "co", Err: err})
+ return
+ }
+
+ params.Co = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("1s"); err == nil {
+ var value string
+ err = runtime.BindStyledParameterWithOptions("simple", "1s", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "1s", Err: err})
+ return
+ }
+ params.N1s = &value
+
+ }
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetCookie(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// EnumParams operation middleware
+func (siw *ServerInterfaceWrapper) EnumParams(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params EnumParamsParams
+
+ // ------------- Optional query parameter "enumPathParam" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "enumPathParam", r.URL.Query(), ¶ms.EnumPathParam, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "enumPathParam"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "enumPathParam", Err: err})
+ }
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.EnumParams(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetHeader operation middleware
+func (siw *ServerInterfaceWrapper) GetHeader(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetHeaderParams
+
+ headers := r.Header
+
+ // ------------- Optional header parameter "X-Primitive" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive")]; found {
+ var XPrimitive int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Primitive", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive", valueList[0], &XPrimitive, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Primitive", Err: err})
+ return
+ }
+
+ params.XPrimitive = &XPrimitive
+
+ }
+
+ // ------------- Optional header parameter "X-Primitive-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive-Exploded")]; found {
+ var XPrimitiveExploded int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Primitive-Exploded", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive-Exploded", valueList[0], &XPrimitiveExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Primitive-Exploded", Err: err})
+ return
+ }
+
+ params.XPrimitiveExploded = &XPrimitiveExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Array-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array-Exploded")]; found {
+ var XArrayExploded []int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Array-Exploded", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array-Exploded", valueList[0], &XArrayExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Array-Exploded", Err: err})
+ return
+ }
+
+ params.XArrayExploded = &XArrayExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Array" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array")]; found {
+ var XArray []int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Array", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array", valueList[0], &XArray, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Array", Err: err})
+ return
+ }
+
+ params.XArray = &XArray
+
+ }
+
+ // ------------- Optional header parameter "X-Object-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object-Exploded")]; found {
+ var XObjectExploded Object
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Object-Exploded", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object-Exploded", valueList[0], &XObjectExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Object-Exploded", Err: err})
+ return
+ }
+
+ params.XObjectExploded = &XObjectExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object")]; found {
+ var XObject Object
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Object", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object", valueList[0], &XObject, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Object", Err: err})
+ return
+ }
+
+ params.XObject = &XObject
+
+ }
+
+ // ------------- Optional header parameter "X-Complex-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Complex-Object")]; found {
+ var XComplexObject ComplexObject
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Complex-Object", Count: n})
+ return
+ }
+
+ err = json.Unmarshal([]byte(valueList[0]), &XComplexObject)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "X-Complex-Object", Err: err})
+ return
+ }
+
+ params.XComplexObject = &XComplexObject
+
+ }
+
+ // ------------- Optional header parameter "1-Starting-With-Number" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("1-Starting-With-Number")]; found {
+ var N1StartingWithNumber string
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "1-Starting-With-Number", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "1-Starting-With-Number", valueList[0], &N1StartingWithNumber, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "1-Starting-With-Number", Err: err})
+ return
+ }
+
+ params.N1StartingWithNumber = &N1StartingWithNumber
+
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetHeader(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", chi.URLParam(r, "param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelExplodeArray(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", chi.URLParam(r, "param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelExplodeObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodePrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", chi.URLParam(r, "param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelExplodePrimitive(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelNoExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", chi.URLParam(r, "param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelNoExplodeArray(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelNoExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", chi.URLParam(r, "param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelNoExplodeObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelPrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelPrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", chi.URLParam(r, "param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelPrimitive(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixExplodeArray(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixExplodeObject(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodePrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixExplodePrimitive(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixNoExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixNoExplodeArray(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixNoExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixNoExplodeObject(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixPrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixPrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixPrimitive(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetPassThrough operation middleware
+func (siw *ServerInterfaceWrapper) GetPassThrough(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param string
+
+ param = chi.URLParam(r, "param")
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetPassThrough(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetDeepObject operation middleware
+func (siw *ServerInterfaceWrapper) GetDeepObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetDeepObjectParams
+
+ // ------------- Required query parameter "deepObj" -------------
+
+ err = runtime.BindQueryParameterWithOptions("deepObject", true, true, "deepObj", r.URL.Query(), ¶ms.DeepObj, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "deepObj"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "deepObj", Err: err})
+ }
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetDeepObject(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetQueryDelimited operation middleware
+func (siw *ServerInterfaceWrapper) GetQueryDelimited(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryDelimitedParams
+
+ // ------------- Optional query parameter "sa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("spaceDelimited", false, false, "sa", r.URL.Query(), ¶ms.Sa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "sa"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "sa", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "pa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("pipeDelimited", false, false, "pa", r.URL.Query(), ¶ms.Pa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "pa"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "pa", Err: err})
+ }
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetQueryDelimited(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetQueryForm operation middleware
+func (siw *ServerInterfaceWrapper) GetQueryForm(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryFormParams
+
+ // ------------- Optional query parameter "ea" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ea", r.URL.Query(), ¶ms.Ea, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "ea"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ea", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "a" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "a", r.URL.Query(), ¶ms.A, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "a"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "a", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "eo" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "eo", r.URL.Query(), ¶ms.Eo, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "eo"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "eo", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "o" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "o", r.URL.Query(), ¶ms.O, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "o"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "o", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "ep" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ep", r.URL.Query(), ¶ms.Ep, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "ep"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ep", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "p" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "p", r.URL.Query(), ¶ms.P, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "p"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "p", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "ps" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ps", r.URL.Query(), ¶ms.Ps, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "ps"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ps", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "co" -------------
+
+ if paramValue := r.URL.Query().Get("co"); paramValue != "" {
+
+ var value ComplexObject
+ err = json.Unmarshal([]byte(paramValue), &value)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "co", Err: err})
+ return
+ }
+
+ params.Co = &value
+
+ }
+
+ // ------------- Optional query parameter "1s" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "1s", r.URL.Query(), ¶ms.N1s, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "1s"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "1s", Err: err})
+ }
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetQueryForm(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", chi.URLParam(r, "param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleExplodeArray(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", chi.URLParam(r, "param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleExplodeObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodePrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", chi.URLParam(r, "param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleExplodePrimitive(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleNoExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", chi.URLParam(r, "param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleNoExplodeArray(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleNoExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", chi.URLParam(r, "param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleNoExplodeObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimplePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetSimplePrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", chi.URLParam(r, "param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimplePrimitive(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetStartingWithNumber operation middleware
+func (siw *ServerInterfaceWrapper) GetStartingWithNumber(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "1param" -------------
+ var n1param string
+
+ n1param = chi.URLParam(r, "1param")
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetStartingWithNumber(w, r, n1param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{})
+}
+
+type ChiServerOptions struct {
+ BaseURL string
+ BaseRouter chi.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = chi.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/contentObject/{param}", wrapper.GetContentObject)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/cookie", wrapper.GetCookie)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/enums", wrapper.EnumParams)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/header", wrapper.GetHeader)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/labelExplodeArray/{param}", wrapper.GetLabelExplodeArray)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/labelExplodeObject/{param}", wrapper.GetLabelExplodeObject)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/labelExplodePrimitive/{param}", wrapper.GetLabelExplodePrimitive)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/labelNoExplodeArray/{param}", wrapper.GetLabelNoExplodeArray)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/labelNoExplodeObject/{param}", wrapper.GetLabelNoExplodeObject)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/labelPrimitive/{param}", wrapper.GetLabelPrimitive)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/matrixExplodeArray/{id}", wrapper.GetMatrixExplodeArray)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/matrixExplodeObject/{id}", wrapper.GetMatrixExplodeObject)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/matrixExplodePrimitive/{id}", wrapper.GetMatrixExplodePrimitive)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/matrixNoExplodeArray/{id}", wrapper.GetMatrixNoExplodeArray)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/matrixNoExplodeObject/{id}", wrapper.GetMatrixNoExplodeObject)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/matrixPrimitive/{id}", wrapper.GetMatrixPrimitive)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/passThrough/{param}", wrapper.GetPassThrough)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/queryDeepObject", wrapper.GetDeepObject)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/queryDelimited", wrapper.GetQueryDelimited)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/queryForm", wrapper.GetQueryForm)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/simpleExplodeArray/{param}", wrapper.GetSimpleExplodeArray)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/simpleExplodeObject/{param}", wrapper.GetSimpleExplodeObject)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/simpleExplodePrimitive/{param}", wrapper.GetSimpleExplodePrimitive)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/simpleNoExplodeArray/{param}", wrapper.GetSimpleNoExplodeArray)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/simpleNoExplodeObject/{param}", wrapper.GetSimpleNoExplodeObject)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/simplePrimitive/{param}", wrapper.GetSimplePrimitive)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/startingWithNumber/{1param}", wrapper.GetStartingWithNumber)
+ })
+
+ return r
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "3FpLb+M2F/0rwv2+VaFYdqYrdRVMp22ATiatA0yBIAtGuo44lUQOSacJDP33gpRkPa2HLeXRXWJd3sch",
+ "z6F4qR14LOIsxlhJcHcgUHIWSzT/rGnEQ/wz+0n/4rFYYaz0nwqflMNDQmP9n/QCjIj5/ZkjuCCVoPED",
+ "JElig4/SE5QrymJw4cKSxq+Vx7LY/Tf0FGjT1I+J/pFpq6cv6UN3B1wwjkLRNLlLvxSNxgofUEBiw6W8",
+ "8KM0qezhPWMhklg/LJz9X+AGXPifU9TvZMGdL0U+Ar9vqUAf3Nt8sK1DF3HuKm6rOW6okOqKRNgCjA2C",
+ "hW0PalGNlV1ydWcwpfGG6cEh9TCbnNgEgs+XN9q7okq7hxuUylqjeEQBNjyikOk0rBbLxVIbMo4x4RRc",
+ "+LBYLlZgAycqMPk72Xyn9Tk7TgSJEv3kAU25ulii51XPBvyK6mN5gHElSIQKhQT3trJ+COch9cxg55tk",
+ "tVXUNT3VhZGhAa5JG+wcBhMZylgqscXkzq6u8fPl8lC8vZ1TI0JiYjoeY39T7EbDWDRgqBKCCxpRRR+1",
+ "IT7xkPkI7oaEErPCvNxNXhrYJag2TEREpST4cA52gxOJPSiihudAQDw5YhbFt4gQ5HloWFIJSxVGclD8",
+ "/S9ptJZ8Gml04T1fGntYWE6YQbiwSkLDpKweuhmxC4LjIs5F92olXmpQYNhagcegCYJ+ZklFhKLxg/UP",
+ "VYEVb6N7I5WtXlayAkRduuvq4uOGbEN1rMJgvE2XWqvAfIq30bUWFtmnMNf5w7RE7dZ6JOEWZV7n9y2K",
+ "59IKM65VcJ2JaFGxfgLu7Wq5tM+Xyzt7gBg0JffHFJvKTDArXy1Z8QESH0WXvP6WWpwqr0HuJiv+r7Pr",
+ "0pBZhbYj9NmnTBteRHqbiVxo6/YkXkyID2T1ynLczCrVpnaw5lDnQxm8O5FuFpI5ygs6QrLrPldn68z6",
+ "7CtVwdlVbv1iMh6SewyzxWEWsLNbGMn6ofNd+vf6sKbStS3PIa/B0xDIBqmezSHDVAhTvlyXMcuPH2NB",
+ "O3QKmQK1Iex6KXz2e8Z4iMo73QwoDVhSM0N0xdqI149PdVwHOmVd/g9Rb19/lXwjgOtl3ynIvQn6NXjX",
+ "j84Qvp2Cy6sSLiJK0Kca36jfrUafG4OOkSLqz060tLr5ANsTbRRix+9xPZCNY9jc4JSo9tMofE7a4Hog",
+ "GkG22fBp7G/UHwDOBLvbe2Zcc3Mbh9oJW9v7YF2VbgOgOW1fe9M840TKm0Cw7UMw5AbkujDvvP8YcX/2",
+ "KrcbpiP4MyIvLrcOlVyy6unF+Yi8u7lSa0T6qeujOVPrSxQLxS9ynvq4nyEXakag3wXcH1XLHvAkJx5a",
+ "fm5udbbOajjKqe4wCgRNOkXyLc1Pyo9Nl0+frs6mlO3UTPmFiah3qo1RzywPatfW2/XTw6WHwsh2bS2r",
+ "F0tqWNu2jtn8l2i1iFME3Jfad7NQr3aeO+MuCk8W0Mr2wgNxum/kXrnBXUv2uEvImpORd5AnKFv6oU71",
+ "gDGgwbhuDHu7neu0RJgNtcqnMyNgezu967kRKp01+t+u160jX715PRtG9eP9UITeTft6fuSGf7y2bhv4",
+ "JhrYs6F0BPk6WPceaZbtu1+pCtKbYWe3GgBFY9iMh/3VzKd9jbD5QDTNeytCcCFQiruOk30dqlCqhT4z",
+ "R4QvCIXkLvk3AAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/parameters/chi/gen/types.gen.go b/internal/test/parameters/chi/gen/types.gen.go
new file mode 100644
index 0000000000..cf9e959422
--- /dev/null
+++ b/internal/test/parameters/chi/gen/types.gen.go
@@ -0,0 +1,143 @@
+// Package chiparamsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package chiparamsgen
+
+// Defines values for EnumParamsParamsEnumPathParam.
+const (
+ N100 EnumParamsParamsEnumPathParam = 100
+ N200 EnumParamsParamsEnumPathParam = 200
+)
+
+// Valid indicates whether the value is a known member of the EnumParamsParamsEnumPathParam enum.
+func (e EnumParamsParamsEnumPathParam) Valid() bool {
+ switch e {
+ case N100:
+ return true
+ case N200:
+ return true
+ default:
+ return false
+ }
+}
+
+// ComplexObject defines model for ComplexObject.
+type ComplexObject struct {
+ Id int `json:"Id"`
+ IsAdmin bool `json:"IsAdmin"`
+ Object Object `json:"Object"`
+}
+
+// Object defines model for Object.
+type Object struct {
+ FirstName string `json:"firstName"`
+ Role string `json:"role"`
+}
+
+// GetCookieParams defines parameters for GetCookie.
+type GetCookieParams struct {
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ep primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
+
+// EnumParamsParams defines parameters for EnumParams.
+type EnumParamsParams struct {
+ // EnumPathParam Parameter with enum values
+ EnumPathParam *EnumParamsParamsEnumPathParam `form:"enumPathParam,omitempty" json:"enumPathParam,omitempty"`
+}
+
+// EnumParamsParamsEnumPathParam defines parameters for EnumParams.
+type EnumParamsParamsEnumPathParam int32
+
+// GetHeaderParams defines parameters for GetHeader.
+type GetHeaderParams struct {
+ // XPrimitive primitive
+ XPrimitive *int32 `json:"X-Primitive,omitempty"`
+
+ // XPrimitiveExploded primitive
+ XPrimitiveExploded *int32 `json:"X-Primitive-Exploded,omitempty"`
+
+ // XArrayExploded exploded array
+ XArrayExploded *[]int32 `json:"X-Array-Exploded,omitempty"`
+
+ // XArray array
+ XArray *[]int32 `json:"X-Array,omitempty"`
+
+ // XObjectExploded exploded object
+ XObjectExploded *Object `json:"X-Object-Exploded,omitempty"`
+
+ // XObject object
+ XObject *Object `json:"X-Object,omitempty"`
+
+ // XComplexObject complex object
+ XComplexObject *ComplexObject `json:"X-Complex-Object,omitempty"`
+
+ // N1StartingWithNumber name starting with number
+ N1StartingWithNumber *string `json:"1-Starting-With-Number,omitempty"`
+}
+
+// GetDeepObjectParams defines parameters for GetDeepObject.
+type GetDeepObjectParams struct {
+ // DeepObj deep object
+ DeepObj ComplexObject `json:"deepObj"`
+}
+
+// GetQueryDelimitedParams defines parameters for GetQueryDelimited.
+type GetQueryDelimitedParams struct {
+ // Sa space delimited array
+ Sa *[]int32 `json:"sa,omitempty"`
+
+ // Pa pipe delimited array
+ Pa *[]int32 `json:"pa,omitempty"`
+}
+
+// GetQueryFormParams defines parameters for GetQueryForm.
+type GetQueryFormParams struct {
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Ep exploded primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ps primitive string
+ Ps *string `form:"ps,omitempty" json:"ps,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
diff --git a/internal/test/parameters/chi/server.cfg.yaml b/internal/test/parameters/chi/server.cfg.yaml
new file mode 100644
index 0000000000..8347eb6a63
--- /dev/null
+++ b/internal/test/parameters/chi/server.cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: chiparamsgen
+generate:
+ chi-server: true
+ embedded-spec: true
+output: gen/server.gen.go
diff --git a/internal/test/parameters/chi/server.go b/internal/test/parameters/chi/server.go
new file mode 100644
index 0000000000..407710288c
--- /dev/null
+++ b/internal/test/parameters/chi/server.go
@@ -0,0 +1,48 @@
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../parameters.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../parameters.yaml
+
+package chiparams
+
+import (
+ "encoding/json"
+ "net/http"
+
+ gen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/chi/gen"
+)
+
+type Server struct{}
+
+var _ gen.ServerInterface = (*Server)(nil)
+
+func writeJSON(w http.ResponseWriter, v interface{}) {
+ w.Header().Set("Content-Type", "application/json")
+ _ = json.NewEncoder(w).Encode(v)
+}
+
+func (s *Server) GetContentObject(w http.ResponseWriter, r *http.Request, param gen.ComplexObject) { writeJSON(w, param) }
+func (s *Server) GetCookie(w http.ResponseWriter, r *http.Request, params gen.GetCookieParams) { writeJSON(w, params) }
+func (s *Server) EnumParams(w http.ResponseWriter, r *http.Request, params gen.EnumParamsParams) { w.WriteHeader(http.StatusNoContent) }
+func (s *Server) GetHeader(w http.ResponseWriter, r *http.Request, params gen.GetHeaderParams) { writeJSON(w, params) }
+func (s *Server) GetLabelExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) { writeJSON(w, param) }
+func (s *Server) GetLabelExplodeObject(w http.ResponseWriter, r *http.Request, param gen.Object) { writeJSON(w, param) }
+func (s *Server) GetLabelExplodePrimitive(w http.ResponseWriter, r *http.Request, param int32) { writeJSON(w, param) }
+func (s *Server) GetLabelNoExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) { writeJSON(w, param) }
+func (s *Server) GetLabelNoExplodeObject(w http.ResponseWriter, r *http.Request, param gen.Object) { writeJSON(w, param) }
+func (s *Server) GetLabelPrimitive(w http.ResponseWriter, r *http.Request, param int32) { writeJSON(w, param) }
+func (s *Server) GetMatrixExplodeArray(w http.ResponseWriter, r *http.Request, id []int32) { writeJSON(w, id) }
+func (s *Server) GetMatrixExplodeObject(w http.ResponseWriter, r *http.Request, id gen.Object) { writeJSON(w, id) }
+func (s *Server) GetMatrixExplodePrimitive(w http.ResponseWriter, r *http.Request, id int32) { writeJSON(w, id) }
+func (s *Server) GetMatrixNoExplodeArray(w http.ResponseWriter, r *http.Request, id []int32) { writeJSON(w, id) }
+func (s *Server) GetMatrixNoExplodeObject(w http.ResponseWriter, r *http.Request, id gen.Object) { writeJSON(w, id) }
+func (s *Server) GetMatrixPrimitive(w http.ResponseWriter, r *http.Request, id int32) { writeJSON(w, id) }
+func (s *Server) GetPassThrough(w http.ResponseWriter, r *http.Request, param string) { writeJSON(w, param) }
+func (s *Server) GetDeepObject(w http.ResponseWriter, r *http.Request, params gen.GetDeepObjectParams) { writeJSON(w, params) }
+func (s *Server) GetQueryDelimited(w http.ResponseWriter, r *http.Request, params gen.GetQueryDelimitedParams) { writeJSON(w, params) }
+func (s *Server) GetQueryForm(w http.ResponseWriter, r *http.Request, params gen.GetQueryFormParams) { writeJSON(w, params) }
+func (s *Server) GetSimpleExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) { writeJSON(w, param) }
+func (s *Server) GetSimpleExplodeObject(w http.ResponseWriter, r *http.Request, param gen.Object) { writeJSON(w, param) }
+func (s *Server) GetSimpleExplodePrimitive(w http.ResponseWriter, r *http.Request, param int32) { writeJSON(w, param) }
+func (s *Server) GetSimpleNoExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) { writeJSON(w, param) }
+func (s *Server) GetSimpleNoExplodeObject(w http.ResponseWriter, r *http.Request, param gen.Object) { writeJSON(w, param) }
+func (s *Server) GetSimplePrimitive(w http.ResponseWriter, r *http.Request, param int32) { writeJSON(w, param) }
+func (s *Server) GetStartingWithNumber(w http.ResponseWriter, r *http.Request, n1param string) { writeJSON(w, n1param) }
diff --git a/internal/test/parameters/chi/types.cfg.yaml b/internal/test/parameters/chi/types.cfg.yaml
new file mode 100644
index 0000000000..c95e41dd59
--- /dev/null
+++ b/internal/test/parameters/chi/types.cfg.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: chiparamsgen
+generate:
+ models: true
+output: gen/types.gen.go
diff --git a/internal/test/parameters/client/client.cfg.yaml b/internal/test/parameters/client/client.cfg.yaml
new file mode 100644
index 0000000000..7ec6902198
--- /dev/null
+++ b/internal/test/parameters/client/client.cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: paramclientgen
+generate:
+ client: true
+ models: true
+output: gen/client.gen.go
diff --git a/internal/test/parameters/client/client.go b/internal/test/parameters/client/client.go
new file mode 100644
index 0000000000..b23b4dc07c
--- /dev/null
+++ b/internal/test/parameters/client/client.go
@@ -0,0 +1,3 @@
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=client.cfg.yaml ../parameters.yaml
+
+package paramclient
diff --git a/internal/test/parameters/parameters.gen.go b/internal/test/parameters/client/gen/client.gen.go
similarity index 62%
rename from internal/test/parameters/parameters.gen.go
rename to internal/test/parameters/client/gen/client.gen.go
index c0e6fee11c..0baa386b1f 100644
--- a/internal/test/parameters/parameters.gen.go
+++ b/internal/test/parameters/client/gen/client.gen.go
@@ -1,23 +1,17 @@
-// Package parameters provides primitives to interact with the openapi HTTP API.
+// Package paramclientgen provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
-package parameters
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package paramclientgen
import (
- "bytes"
- "compress/gzip"
"context"
- "encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
- "path"
"strings"
- "github.com/getkin/kin-openapi/openapi3"
- "github.com/labstack/echo/v4"
"github.com/oapi-codegen/runtime"
)
@@ -27,6 +21,18 @@ const (
N200 EnumParamsParamsEnumPathParam = 200
)
+// Valid indicates whether the value is a known member of the EnumParamsParamsEnumPathParam enum.
+func (e EnumParamsParamsEnumPathParam) Valid() bool {
+ switch e {
+ case N100:
+ return true
+ case N200:
+ return true
+ default:
+ return false
+ }
+}
+
// ComplexObject defines model for ComplexObject.
type ComplexObject struct {
Id int `json:"Id"`
@@ -109,6 +115,15 @@ type GetDeepObjectParams struct {
DeepObj ComplexObject `json:"deepObj"`
}
+// GetQueryDelimitedParams defines parameters for GetQueryDelimited.
+type GetQueryDelimitedParams struct {
+ // Sa space delimited array
+ Sa *[]int32 `json:"sa,omitempty"`
+
+ // Pa pipe delimited array
+ Pa *[]int32 `json:"pa,omitempty"`
+}
+
// GetQueryFormParams defines parameters for GetQueryForm.
type GetQueryFormParams struct {
// Ea exploded array
@@ -230,30 +245,45 @@ type ClientInterface interface {
// GetLabelExplodeObject request
GetLabelExplodeObject(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // GetLabelExplodePrimitive request
+ GetLabelExplodePrimitive(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*http.Response, error)
+
// GetLabelNoExplodeArray request
GetLabelNoExplodeArray(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*http.Response, error)
// GetLabelNoExplodeObject request
GetLabelNoExplodeObject(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // GetLabelPrimitive request
+ GetLabelPrimitive(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*http.Response, error)
+
// GetMatrixExplodeArray request
GetMatrixExplodeArray(ctx context.Context, id []int32, reqEditors ...RequestEditorFn) (*http.Response, error)
// GetMatrixExplodeObject request
GetMatrixExplodeObject(ctx context.Context, id Object, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // GetMatrixExplodePrimitive request
+ GetMatrixExplodePrimitive(ctx context.Context, id int32, reqEditors ...RequestEditorFn) (*http.Response, error)
+
// GetMatrixNoExplodeArray request
GetMatrixNoExplodeArray(ctx context.Context, id []int32, reqEditors ...RequestEditorFn) (*http.Response, error)
// GetMatrixNoExplodeObject request
GetMatrixNoExplodeObject(ctx context.Context, id Object, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // GetMatrixPrimitive request
+ GetMatrixPrimitive(ctx context.Context, id int32, reqEditors ...RequestEditorFn) (*http.Response, error)
+
// GetPassThrough request
GetPassThrough(ctx context.Context, param string, reqEditors ...RequestEditorFn) (*http.Response, error)
// GetDeepObject request
GetDeepObject(ctx context.Context, params *GetDeepObjectParams, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // GetQueryDelimited request
+ GetQueryDelimited(ctx context.Context, params *GetQueryDelimitedParams, reqEditors ...RequestEditorFn) (*http.Response, error)
+
// GetQueryForm request
GetQueryForm(ctx context.Context, params *GetQueryFormParams, reqEditors ...RequestEditorFn) (*http.Response, error)
@@ -263,6 +293,9 @@ type ClientInterface interface {
// GetSimpleExplodeObject request
GetSimpleExplodeObject(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // GetSimpleExplodePrimitive request
+ GetSimpleExplodePrimitive(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*http.Response, error)
+
// GetSimpleNoExplodeArray request
GetSimpleNoExplodeArray(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*http.Response, error)
@@ -348,6 +381,18 @@ func (c *Client) GetLabelExplodeObject(ctx context.Context, param Object, reqEdi
return c.Client.Do(req)
}
+func (c *Client) GetLabelExplodePrimitive(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetLabelExplodePrimitiveRequest(c.Server, param)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
func (c *Client) GetLabelNoExplodeArray(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewGetLabelNoExplodeArrayRequest(c.Server, param)
if err != nil {
@@ -372,6 +417,18 @@ func (c *Client) GetLabelNoExplodeObject(ctx context.Context, param Object, reqE
return c.Client.Do(req)
}
+func (c *Client) GetLabelPrimitive(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetLabelPrimitiveRequest(c.Server, param)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
func (c *Client) GetMatrixExplodeArray(ctx context.Context, id []int32, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewGetMatrixExplodeArrayRequest(c.Server, id)
if err != nil {
@@ -396,6 +453,18 @@ func (c *Client) GetMatrixExplodeObject(ctx context.Context, id Object, reqEdito
return c.Client.Do(req)
}
+func (c *Client) GetMatrixExplodePrimitive(ctx context.Context, id int32, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetMatrixExplodePrimitiveRequest(c.Server, id)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
func (c *Client) GetMatrixNoExplodeArray(ctx context.Context, id []int32, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewGetMatrixNoExplodeArrayRequest(c.Server, id)
if err != nil {
@@ -420,6 +489,18 @@ func (c *Client) GetMatrixNoExplodeObject(ctx context.Context, id Object, reqEdi
return c.Client.Do(req)
}
+func (c *Client) GetMatrixPrimitive(ctx context.Context, id int32, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetMatrixPrimitiveRequest(c.Server, id)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
func (c *Client) GetPassThrough(ctx context.Context, param string, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewGetPassThroughRequest(c.Server, param)
if err != nil {
@@ -444,6 +525,18 @@ func (c *Client) GetDeepObject(ctx context.Context, params *GetDeepObjectParams,
return c.Client.Do(req)
}
+func (c *Client) GetQueryDelimited(ctx context.Context, params *GetQueryDelimitedParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetQueryDelimitedRequest(c.Server, params)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
func (c *Client) GetQueryForm(ctx context.Context, params *GetQueryFormParams, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewGetQueryFormRequest(c.Server, params)
if err != nil {
@@ -480,6 +573,18 @@ func (c *Client) GetSimpleExplodeObject(ctx context.Context, param Object, reqEd
return c.Client.Do(req)
}
+func (c *Client) GetSimpleExplodePrimitive(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetSimpleExplodePrimitiveRequest(c.Server, param)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
func (c *Client) GetSimpleNoExplodeArray(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewGetSimpleNoExplodeArrayRequest(c.Server, param)
if err != nil {
@@ -556,7 +661,7 @@ func NewGetContentObjectRequest(server string, param ComplexObject) (*http.Reque
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -583,7 +688,7 @@ func NewGetCookieRequest(server string, params *GetCookieParams) (*http.Request,
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -593,7 +698,7 @@ func NewGetCookieRequest(server string, params *GetCookieParams) (*http.Request,
if params.P != nil {
var cookieParam0 string
- cookieParam0, err = runtime.StyleParamWithLocation("simple", false, "p", runtime.ParamLocationCookie, *params.P)
+ cookieParam0, err = runtime.StyleParamWithOptions("simple", false, "p", *params.P, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "integer", Format: "int32"})
if err != nil {
return nil, err
}
@@ -608,7 +713,7 @@ func NewGetCookieRequest(server string, params *GetCookieParams) (*http.Request,
if params.Ep != nil {
var cookieParam1 string
- cookieParam1, err = runtime.StyleParamWithLocation("simple", true, "ep", runtime.ParamLocationCookie, *params.Ep)
+ cookieParam1, err = runtime.StyleParamWithOptions("simple", true, "ep", *params.Ep, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "integer", Format: "int32"})
if err != nil {
return nil, err
}
@@ -623,7 +728,7 @@ func NewGetCookieRequest(server string, params *GetCookieParams) (*http.Request,
if params.Ea != nil {
var cookieParam2 string
- cookieParam2, err = runtime.StyleParamWithLocation("simple", true, "ea", runtime.ParamLocationCookie, *params.Ea)
+ cookieParam2, err = runtime.StyleParamWithOptions("simple", true, "ea", *params.Ea, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "array", Format: ""})
if err != nil {
return nil, err
}
@@ -638,7 +743,7 @@ func NewGetCookieRequest(server string, params *GetCookieParams) (*http.Request,
if params.A != nil {
var cookieParam3 string
- cookieParam3, err = runtime.StyleParamWithLocation("simple", false, "a", runtime.ParamLocationCookie, *params.A)
+ cookieParam3, err = runtime.StyleParamWithOptions("simple", false, "a", *params.A, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "array", Format: ""})
if err != nil {
return nil, err
}
@@ -653,7 +758,7 @@ func NewGetCookieRequest(server string, params *GetCookieParams) (*http.Request,
if params.Eo != nil {
var cookieParam4 string
- cookieParam4, err = runtime.StyleParamWithLocation("simple", true, "eo", runtime.ParamLocationCookie, *params.Eo)
+ cookieParam4, err = runtime.StyleParamWithOptions("simple", true, "eo", *params.Eo, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "", Format: ""})
if err != nil {
return nil, err
}
@@ -668,7 +773,7 @@ func NewGetCookieRequest(server string, params *GetCookieParams) (*http.Request,
if params.O != nil {
var cookieParam5 string
- cookieParam5, err = runtime.StyleParamWithLocation("simple", false, "o", runtime.ParamLocationCookie, *params.O)
+ cookieParam5, err = runtime.StyleParamWithOptions("simple", false, "o", *params.O, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "", Format: ""})
if err != nil {
return nil, err
}
@@ -700,7 +805,7 @@ func NewGetCookieRequest(server string, params *GetCookieParams) (*http.Request,
if params.N1s != nil {
var cookieParam7 string
- cookieParam7, err = runtime.StyleParamWithLocation("simple", true, "1s", runtime.ParamLocationCookie, *params.N1s)
+ cookieParam7, err = runtime.StyleParamWithOptions("simple", true, "1s", *params.N1s, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "string", Format: ""})
if err != nil {
return nil, err
}
@@ -735,28 +840,33 @@ func NewEnumParamsRequest(server string, params *EnumParamsParams) (*http.Reques
}
if params != nil {
+ // queryValues collects non-styled parameters (passthrough, JSON)
+ // that are safe to round-trip through url.Values.Encode().
queryValues := queryURL.Query()
+ // rawQueryFragments collects pre-encoded query fragments from
+ // styled parameters, preserving literal commas as delimiters
+ // per the OpenAPI spec (e.g. "color=blue,black,brown").
+ var rawQueryFragments []string
if params.EnumPathParam != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "enumPathParam", runtime.ParamLocationQuery, *params.EnumPathParam); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "enumPathParam", *params.EnumPathParam, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "integer", Format: "int32"}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
}
- queryURL.RawQuery = queryValues.Encode()
+ if encoded := queryValues.Encode(); encoded != "" {
+ rawQueryFragments = append(rawQueryFragments, encoded)
+ }
+ queryURL.RawQuery = strings.Join(rawQueryFragments, "&")
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -783,7 +893,7 @@ func NewGetHeaderRequest(server string, params *GetHeaderParams) (*http.Request,
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -793,7 +903,7 @@ func NewGetHeaderRequest(server string, params *GetHeaderParams) (*http.Request,
if params.XPrimitive != nil {
var headerParam0 string
- headerParam0, err = runtime.StyleParamWithLocation("simple", false, "X-Primitive", runtime.ParamLocationHeader, *params.XPrimitive)
+ headerParam0, err = runtime.StyleParamWithOptions("simple", false, "X-Primitive", *params.XPrimitive, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "integer", Format: "int32"})
if err != nil {
return nil, err
}
@@ -804,7 +914,7 @@ func NewGetHeaderRequest(server string, params *GetHeaderParams) (*http.Request,
if params.XPrimitiveExploded != nil {
var headerParam1 string
- headerParam1, err = runtime.StyleParamWithLocation("simple", true, "X-Primitive-Exploded", runtime.ParamLocationHeader, *params.XPrimitiveExploded)
+ headerParam1, err = runtime.StyleParamWithOptions("simple", true, "X-Primitive-Exploded", *params.XPrimitiveExploded, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "integer", Format: "int32"})
if err != nil {
return nil, err
}
@@ -815,7 +925,7 @@ func NewGetHeaderRequest(server string, params *GetHeaderParams) (*http.Request,
if params.XArrayExploded != nil {
var headerParam2 string
- headerParam2, err = runtime.StyleParamWithLocation("simple", true, "X-Array-Exploded", runtime.ParamLocationHeader, *params.XArrayExploded)
+ headerParam2, err = runtime.StyleParamWithOptions("simple", true, "X-Array-Exploded", *params.XArrayExploded, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "array", Format: ""})
if err != nil {
return nil, err
}
@@ -826,7 +936,7 @@ func NewGetHeaderRequest(server string, params *GetHeaderParams) (*http.Request,
if params.XArray != nil {
var headerParam3 string
- headerParam3, err = runtime.StyleParamWithLocation("simple", false, "X-Array", runtime.ParamLocationHeader, *params.XArray)
+ headerParam3, err = runtime.StyleParamWithOptions("simple", false, "X-Array", *params.XArray, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "array", Format: ""})
if err != nil {
return nil, err
}
@@ -837,7 +947,7 @@ func NewGetHeaderRequest(server string, params *GetHeaderParams) (*http.Request,
if params.XObjectExploded != nil {
var headerParam4 string
- headerParam4, err = runtime.StyleParamWithLocation("simple", true, "X-Object-Exploded", runtime.ParamLocationHeader, *params.XObjectExploded)
+ headerParam4, err = runtime.StyleParamWithOptions("simple", true, "X-Object-Exploded", *params.XObjectExploded, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "", Format: ""})
if err != nil {
return nil, err
}
@@ -848,7 +958,7 @@ func NewGetHeaderRequest(server string, params *GetHeaderParams) (*http.Request,
if params.XObject != nil {
var headerParam5 string
- headerParam5, err = runtime.StyleParamWithLocation("simple", false, "X-Object", runtime.ParamLocationHeader, *params.XObject)
+ headerParam5, err = runtime.StyleParamWithOptions("simple", false, "X-Object", *params.XObject, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "", Format: ""})
if err != nil {
return nil, err
}
@@ -872,7 +982,7 @@ func NewGetHeaderRequest(server string, params *GetHeaderParams) (*http.Request,
if params.N1StartingWithNumber != nil {
var headerParam7 string
- headerParam7, err = runtime.StyleParamWithLocation("simple", false, "1-Starting-With-Number", runtime.ParamLocationHeader, *params.N1StartingWithNumber)
+ headerParam7, err = runtime.StyleParamWithOptions("simple", false, "1-Starting-With-Number", *params.N1StartingWithNumber, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "string", Format: ""})
if err != nil {
return nil, err
}
@@ -891,7 +1001,7 @@ func NewGetLabelExplodeArrayRequest(server string, param []int32) (*http.Request
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("label", true, "param", runtime.ParamLocationPath, param)
+ pathParam0, err = runtime.StyleParamWithOptions("label", true, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "array", Format: ""})
if err != nil {
return nil, err
}
@@ -911,7 +1021,7 @@ func NewGetLabelExplodeArrayRequest(server string, param []int32) (*http.Request
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -925,7 +1035,7 @@ func NewGetLabelExplodeObjectRequest(server string, param Object) (*http.Request
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("label", true, "param", runtime.ParamLocationPath, param)
+ pathParam0, err = runtime.StyleParamWithOptions("label", true, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "", Format: ""})
if err != nil {
return nil, err
}
@@ -945,7 +1055,41 @@ func NewGetLabelExplodeObjectRequest(server string, param Object) (*http.Request
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewGetLabelExplodePrimitiveRequest generates requests for GetLabelExplodePrimitive
+func NewGetLabelExplodePrimitiveRequest(server string, param int32) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("label", true, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "integer", Format: "int32"})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/labelExplodePrimitive/%s", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -959,7 +1103,7 @@ func NewGetLabelNoExplodeArrayRequest(server string, param []int32) (*http.Reque
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("label", false, "param", runtime.ParamLocationPath, param)
+ pathParam0, err = runtime.StyleParamWithOptions("label", false, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "array", Format: ""})
if err != nil {
return nil, err
}
@@ -979,7 +1123,7 @@ func NewGetLabelNoExplodeArrayRequest(server string, param []int32) (*http.Reque
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -993,7 +1137,7 @@ func NewGetLabelNoExplodeObjectRequest(server string, param Object) (*http.Reque
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("label", false, "param", runtime.ParamLocationPath, param)
+ pathParam0, err = runtime.StyleParamWithOptions("label", false, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "", Format: ""})
if err != nil {
return nil, err
}
@@ -1013,7 +1157,41 @@ func NewGetLabelNoExplodeObjectRequest(server string, param Object) (*http.Reque
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewGetLabelPrimitiveRequest generates requests for GetLabelPrimitive
+func NewGetLabelPrimitiveRequest(server string, param int32) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("label", false, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "integer", Format: "int32"})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/labelPrimitive/%s", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -1027,7 +1205,7 @@ func NewGetMatrixExplodeArrayRequest(server string, id []int32) (*http.Request,
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("matrix", true, "id", runtime.ParamLocationPath, id)
+ pathParam0, err = runtime.StyleParamWithOptions("matrix", true, "id", id, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "array", Format: ""})
if err != nil {
return nil, err
}
@@ -1047,7 +1225,7 @@ func NewGetMatrixExplodeArrayRequest(server string, id []int32) (*http.Request,
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -1061,7 +1239,7 @@ func NewGetMatrixExplodeObjectRequest(server string, id Object) (*http.Request,
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("matrix", true, "id", runtime.ParamLocationPath, id)
+ pathParam0, err = runtime.StyleParamWithOptions("matrix", true, "id", id, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "", Format: ""})
if err != nil {
return nil, err
}
@@ -1081,7 +1259,41 @@ func NewGetMatrixExplodeObjectRequest(server string, id Object) (*http.Request,
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewGetMatrixExplodePrimitiveRequest generates requests for GetMatrixExplodePrimitive
+func NewGetMatrixExplodePrimitiveRequest(server string, id int32) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("matrix", true, "id", id, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "integer", Format: "int32"})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/matrixExplodePrimitive/%s", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -1095,7 +1307,7 @@ func NewGetMatrixNoExplodeArrayRequest(server string, id []int32) (*http.Request
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("matrix", false, "id", runtime.ParamLocationPath, id)
+ pathParam0, err = runtime.StyleParamWithOptions("matrix", false, "id", id, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "array", Format: ""})
if err != nil {
return nil, err
}
@@ -1115,7 +1327,7 @@ func NewGetMatrixNoExplodeArrayRequest(server string, id []int32) (*http.Request
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -1129,7 +1341,7 @@ func NewGetMatrixNoExplodeObjectRequest(server string, id Object) (*http.Request
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("matrix", false, "id", runtime.ParamLocationPath, id)
+ pathParam0, err = runtime.StyleParamWithOptions("matrix", false, "id", id, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "", Format: ""})
if err != nil {
return nil, err
}
@@ -1149,7 +1361,41 @@ func NewGetMatrixNoExplodeObjectRequest(server string, id Object) (*http.Request
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewGetMatrixPrimitiveRequest generates requests for GetMatrixPrimitive
+func NewGetMatrixPrimitiveRequest(server string, id int32) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("matrix", false, "id", id, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "integer", Format: "int32"})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/matrixPrimitive/%s", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -1180,7 +1426,7 @@ func NewGetPassThroughRequest(server string, param string) (*http.Request, error
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -1208,24 +1454,95 @@ func NewGetDeepObjectRequest(server string, params *GetDeepObjectParams) (*http.
}
if params != nil {
+ // queryValues collects non-styled parameters (passthrough, JSON)
+ // that are safe to round-trip through url.Values.Encode().
queryValues := queryURL.Query()
+ // rawQueryFragments collects pre-encoded query fragments from
+ // styled parameters, preserving literal commas as delimiters
+ // per the OpenAPI spec (e.g. "color=blue,black,brown").
+ var rawQueryFragments []string
- if queryFrag, err := runtime.StyleParamWithLocation("deepObject", true, "deepObj", runtime.ParamLocationQuery, params.DeepObj); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("deepObject", true, "deepObj", params.DeepObj, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "", Format: ""}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
+ }
+ }
+
+ if encoded := queryValues.Encode(); encoded != "" {
+ rawQueryFragments = append(rawQueryFragments, encoded)
+ }
+ queryURL.RawQuery = strings.Join(rawQueryFragments, "&")
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewGetQueryDelimitedRequest generates requests for GetQueryDelimited
+func NewGetQueryDelimitedRequest(server string, params *GetQueryDelimitedParams) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/queryDelimited")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ if params != nil {
+ // queryValues collects non-styled parameters (passthrough, JSON)
+ // that are safe to round-trip through url.Values.Encode().
+ queryValues := queryURL.Query()
+ // rawQueryFragments collects pre-encoded query fragments from
+ // styled parameters, preserving literal commas as delimiters
+ // per the OpenAPI spec (e.g. "color=blue,black,brown").
+ var rawQueryFragments []string
+
+ if params.Sa != nil {
+
+ if queryFrag, err := runtime.StyleParamWithOptions("spaceDelimited", false, "sa", *params.Sa, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "array", Format: ""}); err != nil {
+ return nil, err
+ } else {
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
+ }
+ }
+
+ }
+
+ if params.Pa != nil {
+
+ if queryFrag, err := runtime.StyleParamWithOptions("pipeDelimited", false, "pa", *params.Pa, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "array", Format: ""}); err != nil {
+ return nil, err
+ } else {
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
+
}
- queryURL.RawQuery = queryValues.Encode()
+ if encoded := queryValues.Encode(); encoded != "" {
+ rawQueryFragments = append(rawQueryFragments, encoded)
+ }
+ queryURL.RawQuery = strings.Join(rawQueryFragments, "&")
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -1253,19 +1570,21 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re
}
if params != nil {
+ // queryValues collects non-styled parameters (passthrough, JSON)
+ // that are safe to round-trip through url.Values.Encode().
queryValues := queryURL.Query()
+ // rawQueryFragments collects pre-encoded query fragments from
+ // styled parameters, preserving literal commas as delimiters
+ // per the OpenAPI spec (e.g. "color=blue,black,brown").
+ var rawQueryFragments []string
if params.Ea != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ea", runtime.ParamLocationQuery, *params.Ea); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "ea", *params.Ea, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "array", Format: ""}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
@@ -1273,15 +1592,11 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re
if params.A != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", false, "a", runtime.ParamLocationQuery, *params.A); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("form", false, "a", *params.A, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "array", Format: ""}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
@@ -1289,15 +1604,11 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re
if params.Eo != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "eo", runtime.ParamLocationQuery, *params.Eo); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "eo", *params.Eo, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "", Format: ""}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
@@ -1305,15 +1616,11 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re
if params.O != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", false, "o", runtime.ParamLocationQuery, *params.O); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("form", false, "o", *params.O, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "", Format: ""}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
@@ -1321,15 +1628,11 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re
if params.Ep != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ep", runtime.ParamLocationQuery, *params.Ep); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "ep", *params.Ep, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "integer", Format: "int32"}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
@@ -1337,15 +1640,11 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re
if params.P != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", false, "p", runtime.ParamLocationQuery, *params.P); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("form", false, "p", *params.P, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "integer", Format: "int32"}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
@@ -1353,15 +1652,11 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re
if params.Ps != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "ps", runtime.ParamLocationQuery, *params.Ps); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "ps", *params.Ps, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "string", Format: ""}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
@@ -1379,24 +1674,23 @@ func NewGetQueryFormRequest(server string, params *GetQueryFormParams) (*http.Re
if params.N1s != nil {
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "1s", runtime.ParamLocationQuery, *params.N1s); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "1s", *params.N1s, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "string", Format: ""}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
}
- queryURL.RawQuery = queryValues.Encode()
+ if encoded := queryValues.Encode(); encoded != "" {
+ rawQueryFragments = append(rawQueryFragments, encoded)
+ }
+ queryURL.RawQuery = strings.Join(rawQueryFragments, "&")
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -1410,7 +1704,7 @@ func NewGetSimpleExplodeArrayRequest(server string, param []int32) (*http.Reques
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("simple", true, "param", runtime.ParamLocationPath, param)
+ pathParam0, err = runtime.StyleParamWithOptions("simple", true, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "array", Format: ""})
if err != nil {
return nil, err
}
@@ -1430,7 +1724,7 @@ func NewGetSimpleExplodeArrayRequest(server string, param []int32) (*http.Reques
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -1444,7 +1738,7 @@ func NewGetSimpleExplodeObjectRequest(server string, param Object) (*http.Reques
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("simple", true, "param", runtime.ParamLocationPath, param)
+ pathParam0, err = runtime.StyleParamWithOptions("simple", true, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "", Format: ""})
if err != nil {
return nil, err
}
@@ -1464,7 +1758,7 @@ func NewGetSimpleExplodeObjectRequest(server string, param Object) (*http.Reques
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -1472,13 +1766,13 @@ func NewGetSimpleExplodeObjectRequest(server string, param Object) (*http.Reques
return req, nil
}
-// NewGetSimpleNoExplodeArrayRequest generates requests for GetSimpleNoExplodeArray
-func NewGetSimpleNoExplodeArrayRequest(server string, param []int32) (*http.Request, error) {
+// NewGetSimpleExplodePrimitiveRequest generates requests for GetSimpleExplodePrimitive
+func NewGetSimpleExplodePrimitiveRequest(server string, param int32) (*http.Request, error) {
var err error
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("simple", false, "param", runtime.ParamLocationPath, param)
+ pathParam0, err = runtime.StyleParamWithOptions("simple", true, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "integer", Format: "int32"})
if err != nil {
return nil, err
}
@@ -1488,7 +1782,7 @@ func NewGetSimpleNoExplodeArrayRequest(server string, param []int32) (*http.Requ
return nil, err
}
- operationPath := fmt.Sprintf("/simpleNoExplodeArray/%s", pathParam0)
+ operationPath := fmt.Sprintf("/simpleExplodePrimitive/%s", pathParam0)
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
@@ -1498,7 +1792,7 @@ func NewGetSimpleNoExplodeArrayRequest(server string, param []int32) (*http.Requ
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -1506,13 +1800,13 @@ func NewGetSimpleNoExplodeArrayRequest(server string, param []int32) (*http.Requ
return req, nil
}
-// NewGetSimpleNoExplodeObjectRequest generates requests for GetSimpleNoExplodeObject
-func NewGetSimpleNoExplodeObjectRequest(server string, param Object) (*http.Request, error) {
+// NewGetSimpleNoExplodeArrayRequest generates requests for GetSimpleNoExplodeArray
+func NewGetSimpleNoExplodeArrayRequest(server string, param []int32) (*http.Request, error) {
var err error
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("simple", false, "param", runtime.ParamLocationPath, param)
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "array", Format: ""})
if err != nil {
return nil, err
}
@@ -1522,7 +1816,7 @@ func NewGetSimpleNoExplodeObjectRequest(server string, param Object) (*http.Requ
return nil, err
}
- operationPath := fmt.Sprintf("/simpleNoExplodeObject/%s", pathParam0)
+ operationPath := fmt.Sprintf("/simpleNoExplodeArray/%s", pathParam0)
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
@@ -1532,7 +1826,7 @@ func NewGetSimpleNoExplodeObjectRequest(server string, param Object) (*http.Requ
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -1540,13 +1834,47 @@ func NewGetSimpleNoExplodeObjectRequest(server string, param Object) (*http.Requ
return req, nil
}
-// NewGetSimplePrimitiveRequest generates requests for GetSimplePrimitive
-func NewGetSimplePrimitiveRequest(server string, param int32) (*http.Request, error) {
+// NewGetSimpleNoExplodeObjectRequest generates requests for GetSimpleNoExplodeObject
+func NewGetSimpleNoExplodeObjectRequest(server string, param Object) (*http.Request, error) {
+ var err error
+
+ var pathParam0 string
+
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "", Format: ""})
+ if err != nil {
+ return nil, err
+ }
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/simpleNoExplodeObject/%s", pathParam0)
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewGetSimplePrimitiveRequest generates requests for GetSimplePrimitive
+func NewGetSimplePrimitiveRequest(server string, param int32) (*http.Request, error) {
var err error
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("simple", false, "param", runtime.ParamLocationPath, param)
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "param", param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "integer", Format: "int32"})
if err != nil {
return nil, err
}
@@ -1566,7 +1894,7 @@ func NewGetSimplePrimitiveRequest(server string, param int32) (*http.Request, er
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -1597,7 +1925,7 @@ func NewGetStartingWithNumberRequest(server string, n1param string) (*http.Reque
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -1666,30 +1994,45 @@ type ClientWithResponsesInterface interface {
// GetLabelExplodeObjectWithResponse request
GetLabelExplodeObjectWithResponse(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*GetLabelExplodeObjectResponse, error)
+ // GetLabelExplodePrimitiveWithResponse request
+ GetLabelExplodePrimitiveWithResponse(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*GetLabelExplodePrimitiveResponse, error)
+
// GetLabelNoExplodeArrayWithResponse request
GetLabelNoExplodeArrayWithResponse(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*GetLabelNoExplodeArrayResponse, error)
// GetLabelNoExplodeObjectWithResponse request
GetLabelNoExplodeObjectWithResponse(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*GetLabelNoExplodeObjectResponse, error)
+ // GetLabelPrimitiveWithResponse request
+ GetLabelPrimitiveWithResponse(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*GetLabelPrimitiveResponse, error)
+
// GetMatrixExplodeArrayWithResponse request
GetMatrixExplodeArrayWithResponse(ctx context.Context, id []int32, reqEditors ...RequestEditorFn) (*GetMatrixExplodeArrayResponse, error)
// GetMatrixExplodeObjectWithResponse request
GetMatrixExplodeObjectWithResponse(ctx context.Context, id Object, reqEditors ...RequestEditorFn) (*GetMatrixExplodeObjectResponse, error)
+ // GetMatrixExplodePrimitiveWithResponse request
+ GetMatrixExplodePrimitiveWithResponse(ctx context.Context, id int32, reqEditors ...RequestEditorFn) (*GetMatrixExplodePrimitiveResponse, error)
+
// GetMatrixNoExplodeArrayWithResponse request
GetMatrixNoExplodeArrayWithResponse(ctx context.Context, id []int32, reqEditors ...RequestEditorFn) (*GetMatrixNoExplodeArrayResponse, error)
// GetMatrixNoExplodeObjectWithResponse request
GetMatrixNoExplodeObjectWithResponse(ctx context.Context, id Object, reqEditors ...RequestEditorFn) (*GetMatrixNoExplodeObjectResponse, error)
+ // GetMatrixPrimitiveWithResponse request
+ GetMatrixPrimitiveWithResponse(ctx context.Context, id int32, reqEditors ...RequestEditorFn) (*GetMatrixPrimitiveResponse, error)
+
// GetPassThroughWithResponse request
GetPassThroughWithResponse(ctx context.Context, param string, reqEditors ...RequestEditorFn) (*GetPassThroughResponse, error)
// GetDeepObjectWithResponse request
GetDeepObjectWithResponse(ctx context.Context, params *GetDeepObjectParams, reqEditors ...RequestEditorFn) (*GetDeepObjectResponse, error)
+ // GetQueryDelimitedWithResponse request
+ GetQueryDelimitedWithResponse(ctx context.Context, params *GetQueryDelimitedParams, reqEditors ...RequestEditorFn) (*GetQueryDelimitedResponse, error)
+
// GetQueryFormWithResponse request
GetQueryFormWithResponse(ctx context.Context, params *GetQueryFormParams, reqEditors ...RequestEditorFn) (*GetQueryFormResponse, error)
@@ -1699,6 +2042,9 @@ type ClientWithResponsesInterface interface {
// GetSimpleExplodeObjectWithResponse request
GetSimpleExplodeObjectWithResponse(ctx context.Context, param Object, reqEditors ...RequestEditorFn) (*GetSimpleExplodeObjectResponse, error)
+ // GetSimpleExplodePrimitiveWithResponse request
+ GetSimpleExplodePrimitiveWithResponse(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*GetSimpleExplodePrimitiveResponse, error)
+
// GetSimpleNoExplodeArrayWithResponse request
GetSimpleNoExplodeArrayWithResponse(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*GetSimpleNoExplodeArrayResponse, error)
@@ -1717,6 +2063,11 @@ type GetContentObjectResponse struct {
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetContentObjectResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetContentObjectResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1733,11 +2084,24 @@ func (r GetContentObjectResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetContentObjectResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type GetCookieResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetCookieResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetCookieResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1754,11 +2118,24 @@ func (r GetCookieResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetCookieResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type EnumParamsResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r EnumParamsResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r EnumParamsResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1775,11 +2152,24 @@ func (r EnumParamsResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r EnumParamsResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type GetHeaderResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetHeaderResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetHeaderResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1796,11 +2186,24 @@ func (r GetHeaderResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetHeaderResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type GetLabelExplodeArrayResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetLabelExplodeArrayResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetLabelExplodeArrayResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1817,11 +2220,24 @@ func (r GetLabelExplodeArrayResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetLabelExplodeArrayResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type GetLabelExplodeObjectResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetLabelExplodeObjectResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetLabelExplodeObjectResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1838,11 +2254,58 @@ func (r GetLabelExplodeObjectResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetLabelExplodeObjectResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetLabelExplodePrimitiveResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetLabelExplodePrimitiveResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetLabelExplodePrimitiveResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetLabelExplodePrimitiveResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetLabelExplodePrimitiveResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type GetLabelNoExplodeArrayResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetLabelNoExplodeArrayResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetLabelNoExplodeArrayResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1859,11 +2322,24 @@ func (r GetLabelNoExplodeArrayResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetLabelNoExplodeArrayResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type GetLabelNoExplodeObjectResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetLabelNoExplodeObjectResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetLabelNoExplodeObjectResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1880,13 +2356,26 @@ func (r GetLabelNoExplodeObjectResponse) StatusCode() int {
return 0
}
-type GetMatrixExplodeArrayResponse struct {
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetLabelNoExplodeObjectResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetLabelPrimitiveResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetLabelPrimitiveResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
-func (r GetMatrixExplodeArrayResponse) Status() string {
+func (r GetLabelPrimitiveResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -1894,20 +2383,33 @@ func (r GetMatrixExplodeArrayResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetMatrixExplodeArrayResponse) StatusCode() int {
+func (r GetLabelPrimitiveResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type GetMatrixExplodeObjectResponse struct {
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetLabelPrimitiveResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetMatrixExplodeArrayResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetMatrixExplodeArrayResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
-func (r GetMatrixExplodeObjectResponse) Status() string {
+func (r GetMatrixExplodeArrayResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -1915,20 +2417,33 @@ func (r GetMatrixExplodeObjectResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetMatrixExplodeObjectResponse) StatusCode() int {
+func (r GetMatrixExplodeArrayResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type GetMatrixNoExplodeArrayResponse struct {
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetMatrixExplodeArrayResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetMatrixExplodeObjectResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetMatrixExplodeObjectResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
-func (r GetMatrixNoExplodeArrayResponse) Status() string {
+func (r GetMatrixExplodeObjectResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -1936,20 +2451,33 @@ func (r GetMatrixNoExplodeArrayResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetMatrixNoExplodeArrayResponse) StatusCode() int {
+func (r GetMatrixExplodeObjectResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type GetMatrixNoExplodeObjectResponse struct {
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetMatrixExplodeObjectResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetMatrixExplodePrimitiveResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetMatrixExplodePrimitiveResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
-func (r GetMatrixNoExplodeObjectResponse) Status() string {
+func (r GetMatrixExplodePrimitiveResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -1957,20 +2485,33 @@ func (r GetMatrixNoExplodeObjectResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetMatrixNoExplodeObjectResponse) StatusCode() int {
+func (r GetMatrixExplodePrimitiveResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type GetPassThroughResponse struct {
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetMatrixExplodePrimitiveResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetMatrixNoExplodeArrayResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetMatrixNoExplodeArrayResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
-func (r GetPassThroughResponse) Status() string {
+func (r GetMatrixNoExplodeArrayResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -1978,20 +2519,33 @@ func (r GetPassThroughResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetPassThroughResponse) StatusCode() int {
+func (r GetMatrixNoExplodeArrayResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type GetDeepObjectResponse struct {
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetMatrixNoExplodeArrayResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetMatrixNoExplodeObjectResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetMatrixNoExplodeObjectResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
-func (r GetDeepObjectResponse) Status() string {
+func (r GetMatrixNoExplodeObjectResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -1999,20 +2553,33 @@ func (r GetDeepObjectResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetDeepObjectResponse) StatusCode() int {
+func (r GetMatrixNoExplodeObjectResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type GetQueryFormResponse struct {
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetMatrixNoExplodeObjectResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetMatrixPrimitiveResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetMatrixPrimitiveResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
-func (r GetQueryFormResponse) Status() string {
+func (r GetMatrixPrimitiveResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -2020,20 +2587,33 @@ func (r GetQueryFormResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetQueryFormResponse) StatusCode() int {
+func (r GetMatrixPrimitiveResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type GetSimpleExplodeArrayResponse struct {
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetMatrixPrimitiveResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetPassThroughResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetPassThroughResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
-func (r GetSimpleExplodeArrayResponse) Status() string {
+func (r GetPassThroughResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -2041,20 +2621,33 @@ func (r GetSimpleExplodeArrayResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetSimpleExplodeArrayResponse) StatusCode() int {
+func (r GetPassThroughResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type GetSimpleExplodeObjectResponse struct {
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetPassThroughResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetDeepObjectResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetDeepObjectResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
-func (r GetSimpleExplodeObjectResponse) Status() string {
+func (r GetDeepObjectResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -2062,20 +2655,33 @@ func (r GetSimpleExplodeObjectResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetSimpleExplodeObjectResponse) StatusCode() int {
+func (r GetDeepObjectResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type GetSimpleNoExplodeArrayResponse struct {
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetDeepObjectResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetQueryDelimitedResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetQueryDelimitedResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
-func (r GetSimpleNoExplodeArrayResponse) Status() string {
+func (r GetQueryDelimitedResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -2083,20 +2689,33 @@ func (r GetSimpleNoExplodeArrayResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetSimpleNoExplodeArrayResponse) StatusCode() int {
+func (r GetQueryDelimitedResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type GetSimpleNoExplodeObjectResponse struct {
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetQueryDelimitedResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetQueryFormResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetQueryFormResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
-func (r GetSimpleNoExplodeObjectResponse) Status() string {
+func (r GetQueryFormResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -2104,20 +2723,33 @@ func (r GetSimpleNoExplodeObjectResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetSimpleNoExplodeObjectResponse) StatusCode() int {
+func (r GetQueryFormResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type GetSimplePrimitiveResponse struct {
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetQueryFormResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetSimpleExplodeArrayResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetSimpleExplodeArrayResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
-func (r GetSimplePrimitiveResponse) Status() string {
+func (r GetSimpleExplodeArrayResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -2125,20 +2757,33 @@ func (r GetSimplePrimitiveResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetSimplePrimitiveResponse) StatusCode() int {
+func (r GetSimpleExplodeArrayResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-type GetStartingWithNumberResponse struct {
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetSimpleExplodeArrayResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetSimpleExplodeObjectResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r GetSimpleExplodeObjectResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
-func (r GetStartingWithNumberResponse) Status() string {
+func (r GetSimpleExplodeObjectResponse) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
@@ -2146,17 +2791,195 @@ func (r GetStartingWithNumberResponse) Status() string {
}
// StatusCode returns HTTPResponse.StatusCode
-func (r GetStartingWithNumberResponse) StatusCode() int {
+func (r GetSimpleExplodeObjectResponse) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
-// GetContentObjectWithResponse request returning *GetContentObjectResponse
-func (c *ClientWithResponses) GetContentObjectWithResponse(ctx context.Context, param ComplexObject, reqEditors ...RequestEditorFn) (*GetContentObjectResponse, error) {
- rsp, err := c.GetContentObject(ctx, param, reqEditors...)
- if err != nil {
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetSimpleExplodeObjectResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetSimpleExplodePrimitiveResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetSimpleExplodePrimitiveResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetSimpleExplodePrimitiveResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetSimpleExplodePrimitiveResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetSimpleExplodePrimitiveResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetSimpleNoExplodeArrayResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetSimpleNoExplodeArrayResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetSimpleNoExplodeArrayResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetSimpleNoExplodeArrayResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetSimpleNoExplodeArrayResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetSimpleNoExplodeObjectResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetSimpleNoExplodeObjectResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetSimpleNoExplodeObjectResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetSimpleNoExplodeObjectResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetSimpleNoExplodeObjectResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetSimplePrimitiveResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetSimplePrimitiveResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetSimplePrimitiveResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetSimplePrimitiveResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetSimplePrimitiveResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetStartingWithNumberResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetStartingWithNumberResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetStartingWithNumberResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetStartingWithNumberResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetStartingWithNumberResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetContentObjectWithResponse request returning *GetContentObjectResponse
+func (c *ClientWithResponses) GetContentObjectWithResponse(ctx context.Context, param ComplexObject, reqEditors ...RequestEditorFn) (*GetContentObjectResponse, error) {
+ rsp, err := c.GetContentObject(ctx, param, reqEditors...)
+ if err != nil {
return nil, err
}
return ParseGetContentObjectResponse(rsp)
@@ -2207,6 +3030,15 @@ func (c *ClientWithResponses) GetLabelExplodeObjectWithResponse(ctx context.Cont
return ParseGetLabelExplodeObjectResponse(rsp)
}
+// GetLabelExplodePrimitiveWithResponse request returning *GetLabelExplodePrimitiveResponse
+func (c *ClientWithResponses) GetLabelExplodePrimitiveWithResponse(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*GetLabelExplodePrimitiveResponse, error) {
+ rsp, err := c.GetLabelExplodePrimitive(ctx, param, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetLabelExplodePrimitiveResponse(rsp)
+}
+
// GetLabelNoExplodeArrayWithResponse request returning *GetLabelNoExplodeArrayResponse
func (c *ClientWithResponses) GetLabelNoExplodeArrayWithResponse(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*GetLabelNoExplodeArrayResponse, error) {
rsp, err := c.GetLabelNoExplodeArray(ctx, param, reqEditors...)
@@ -2225,6 +3057,15 @@ func (c *ClientWithResponses) GetLabelNoExplodeObjectWithResponse(ctx context.Co
return ParseGetLabelNoExplodeObjectResponse(rsp)
}
+// GetLabelPrimitiveWithResponse request returning *GetLabelPrimitiveResponse
+func (c *ClientWithResponses) GetLabelPrimitiveWithResponse(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*GetLabelPrimitiveResponse, error) {
+ rsp, err := c.GetLabelPrimitive(ctx, param, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetLabelPrimitiveResponse(rsp)
+}
+
// GetMatrixExplodeArrayWithResponse request returning *GetMatrixExplodeArrayResponse
func (c *ClientWithResponses) GetMatrixExplodeArrayWithResponse(ctx context.Context, id []int32, reqEditors ...RequestEditorFn) (*GetMatrixExplodeArrayResponse, error) {
rsp, err := c.GetMatrixExplodeArray(ctx, id, reqEditors...)
@@ -2243,6 +3084,15 @@ func (c *ClientWithResponses) GetMatrixExplodeObjectWithResponse(ctx context.Con
return ParseGetMatrixExplodeObjectResponse(rsp)
}
+// GetMatrixExplodePrimitiveWithResponse request returning *GetMatrixExplodePrimitiveResponse
+func (c *ClientWithResponses) GetMatrixExplodePrimitiveWithResponse(ctx context.Context, id int32, reqEditors ...RequestEditorFn) (*GetMatrixExplodePrimitiveResponse, error) {
+ rsp, err := c.GetMatrixExplodePrimitive(ctx, id, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetMatrixExplodePrimitiveResponse(rsp)
+}
+
// GetMatrixNoExplodeArrayWithResponse request returning *GetMatrixNoExplodeArrayResponse
func (c *ClientWithResponses) GetMatrixNoExplodeArrayWithResponse(ctx context.Context, id []int32, reqEditors ...RequestEditorFn) (*GetMatrixNoExplodeArrayResponse, error) {
rsp, err := c.GetMatrixNoExplodeArray(ctx, id, reqEditors...)
@@ -2261,6 +3111,15 @@ func (c *ClientWithResponses) GetMatrixNoExplodeObjectWithResponse(ctx context.C
return ParseGetMatrixNoExplodeObjectResponse(rsp)
}
+// GetMatrixPrimitiveWithResponse request returning *GetMatrixPrimitiveResponse
+func (c *ClientWithResponses) GetMatrixPrimitiveWithResponse(ctx context.Context, id int32, reqEditors ...RequestEditorFn) (*GetMatrixPrimitiveResponse, error) {
+ rsp, err := c.GetMatrixPrimitive(ctx, id, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetMatrixPrimitiveResponse(rsp)
+}
+
// GetPassThroughWithResponse request returning *GetPassThroughResponse
func (c *ClientWithResponses) GetPassThroughWithResponse(ctx context.Context, param string, reqEditors ...RequestEditorFn) (*GetPassThroughResponse, error) {
rsp, err := c.GetPassThrough(ctx, param, reqEditors...)
@@ -2279,6 +3138,15 @@ func (c *ClientWithResponses) GetDeepObjectWithResponse(ctx context.Context, par
return ParseGetDeepObjectResponse(rsp)
}
+// GetQueryDelimitedWithResponse request returning *GetQueryDelimitedResponse
+func (c *ClientWithResponses) GetQueryDelimitedWithResponse(ctx context.Context, params *GetQueryDelimitedParams, reqEditors ...RequestEditorFn) (*GetQueryDelimitedResponse, error) {
+ rsp, err := c.GetQueryDelimited(ctx, params, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetQueryDelimitedResponse(rsp)
+}
+
// GetQueryFormWithResponse request returning *GetQueryFormResponse
func (c *ClientWithResponses) GetQueryFormWithResponse(ctx context.Context, params *GetQueryFormParams, reqEditors ...RequestEditorFn) (*GetQueryFormResponse, error) {
rsp, err := c.GetQueryForm(ctx, params, reqEditors...)
@@ -2306,6 +3174,15 @@ func (c *ClientWithResponses) GetSimpleExplodeObjectWithResponse(ctx context.Con
return ParseGetSimpleExplodeObjectResponse(rsp)
}
+// GetSimpleExplodePrimitiveWithResponse request returning *GetSimpleExplodePrimitiveResponse
+func (c *ClientWithResponses) GetSimpleExplodePrimitiveWithResponse(ctx context.Context, param int32, reqEditors ...RequestEditorFn) (*GetSimpleExplodePrimitiveResponse, error) {
+ rsp, err := c.GetSimpleExplodePrimitive(ctx, param, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetSimpleExplodePrimitiveResponse(rsp)
+}
+
// GetSimpleNoExplodeArrayWithResponse request returning *GetSimpleNoExplodeArrayResponse
func (c *ClientWithResponses) GetSimpleNoExplodeArrayWithResponse(ctx context.Context, param []int32, reqEditors ...RequestEditorFn) (*GetSimpleNoExplodeArrayResponse, error) {
rsp, err := c.GetSimpleNoExplodeArray(ctx, param, reqEditors...)
@@ -2438,6 +3315,22 @@ func ParseGetLabelExplodeObjectResponse(rsp *http.Response) (*GetLabelExplodeObj
return response, nil
}
+// ParseGetLabelExplodePrimitiveResponse parses an HTTP response from a GetLabelExplodePrimitiveWithResponse call
+func ParseGetLabelExplodePrimitiveResponse(rsp *http.Response) (*GetLabelExplodePrimitiveResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetLabelExplodePrimitiveResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
// ParseGetLabelNoExplodeArrayResponse parses an HTTP response from a GetLabelNoExplodeArrayWithResponse call
func ParseGetLabelNoExplodeArrayResponse(rsp *http.Response) (*GetLabelNoExplodeArrayResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
@@ -2470,6 +3363,22 @@ func ParseGetLabelNoExplodeObjectResponse(rsp *http.Response) (*GetLabelNoExplod
return response, nil
}
+// ParseGetLabelPrimitiveResponse parses an HTTP response from a GetLabelPrimitiveWithResponse call
+func ParseGetLabelPrimitiveResponse(rsp *http.Response) (*GetLabelPrimitiveResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetLabelPrimitiveResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
// ParseGetMatrixExplodeArrayResponse parses an HTTP response from a GetMatrixExplodeArrayWithResponse call
func ParseGetMatrixExplodeArrayResponse(rsp *http.Response) (*GetMatrixExplodeArrayResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
@@ -2502,6 +3411,22 @@ func ParseGetMatrixExplodeObjectResponse(rsp *http.Response) (*GetMatrixExplodeO
return response, nil
}
+// ParseGetMatrixExplodePrimitiveResponse parses an HTTP response from a GetMatrixExplodePrimitiveWithResponse call
+func ParseGetMatrixExplodePrimitiveResponse(rsp *http.Response) (*GetMatrixExplodePrimitiveResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetMatrixExplodePrimitiveResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
// ParseGetMatrixNoExplodeArrayResponse parses an HTTP response from a GetMatrixNoExplodeArrayWithResponse call
func ParseGetMatrixNoExplodeArrayResponse(rsp *http.Response) (*GetMatrixNoExplodeArrayResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
@@ -2534,6 +3459,22 @@ func ParseGetMatrixNoExplodeObjectResponse(rsp *http.Response) (*GetMatrixNoExpl
return response, nil
}
+// ParseGetMatrixPrimitiveResponse parses an HTTP response from a GetMatrixPrimitiveWithResponse call
+func ParseGetMatrixPrimitiveResponse(rsp *http.Response) (*GetMatrixPrimitiveResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetMatrixPrimitiveResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
// ParseGetPassThroughResponse parses an HTTP response from a GetPassThroughWithResponse call
func ParseGetPassThroughResponse(rsp *http.Response) (*GetPassThroughResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
@@ -2566,6 +3507,22 @@ func ParseGetDeepObjectResponse(rsp *http.Response) (*GetDeepObjectResponse, err
return response, nil
}
+// ParseGetQueryDelimitedResponse parses an HTTP response from a GetQueryDelimitedWithResponse call
+func ParseGetQueryDelimitedResponse(rsp *http.Response) (*GetQueryDelimitedResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetQueryDelimitedResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
// ParseGetQueryFormResponse parses an HTTP response from a GetQueryFormWithResponse call
func ParseGetQueryFormResponse(rsp *http.Response) (*GetQueryFormResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
@@ -2614,6 +3571,22 @@ func ParseGetSimpleExplodeObjectResponse(rsp *http.Response) (*GetSimpleExplodeO
return response, nil
}
+// ParseGetSimpleExplodePrimitiveResponse parses an HTTP response from a GetSimpleExplodePrimitiveWithResponse call
+func ParseGetSimpleExplodePrimitiveResponse(rsp *http.Response) (*GetSimpleExplodePrimitiveResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetSimpleExplodePrimitiveResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
// ParseGetSimpleNoExplodeArrayResponse parses an HTTP response from a GetSimpleNoExplodeArrayWithResponse call
func ParseGetSimpleNoExplodeArrayResponse(rsp *http.Response) (*GetSimpleNoExplodeArrayResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
@@ -2677,829 +3650,3 @@ func ParseGetStartingWithNumberResponse(rsp *http.Response) (*GetStartingWithNum
return response, nil
}
-
-// ServerInterface represents all server handlers.
-type ServerInterface interface {
-
- // (GET /contentObject/{param})
- GetContentObject(ctx echo.Context, param ComplexObject) error
-
- // (GET /cookie)
- GetCookie(ctx echo.Context, params GetCookieParams) error
-
- // (GET /enums)
- EnumParams(ctx echo.Context, params EnumParamsParams) error
-
- // (GET /header)
- GetHeader(ctx echo.Context, params GetHeaderParams) error
-
- // (GET /labelExplodeArray/{.param*})
- GetLabelExplodeArray(ctx echo.Context, param []int32) error
-
- // (GET /labelExplodeObject/{.param*})
- GetLabelExplodeObject(ctx echo.Context, param Object) error
-
- // (GET /labelNoExplodeArray/{.param})
- GetLabelNoExplodeArray(ctx echo.Context, param []int32) error
-
- // (GET /labelNoExplodeObject/{.param})
- GetLabelNoExplodeObject(ctx echo.Context, param Object) error
-
- // (GET /matrixExplodeArray/{.id*})
- GetMatrixExplodeArray(ctx echo.Context, id []int32) error
-
- // (GET /matrixExplodeObject/{.id*})
- GetMatrixExplodeObject(ctx echo.Context, id Object) error
-
- // (GET /matrixNoExplodeArray/{.id})
- GetMatrixNoExplodeArray(ctx echo.Context, id []int32) error
-
- // (GET /matrixNoExplodeObject/{.id})
- GetMatrixNoExplodeObject(ctx echo.Context, id Object) error
-
- // (GET /passThrough/{param})
- GetPassThrough(ctx echo.Context, param string) error
-
- // (GET /queryDeepObject)
- GetDeepObject(ctx echo.Context, params GetDeepObjectParams) error
-
- // (GET /queryForm)
- GetQueryForm(ctx echo.Context, params GetQueryFormParams) error
-
- // (GET /simpleExplodeArray/{param*})
- GetSimpleExplodeArray(ctx echo.Context, param []int32) error
-
- // (GET /simpleExplodeObject/{param*})
- GetSimpleExplodeObject(ctx echo.Context, param Object) error
-
- // (GET /simpleNoExplodeArray/{param})
- GetSimpleNoExplodeArray(ctx echo.Context, param []int32) error
-
- // (GET /simpleNoExplodeObject/{param})
- GetSimpleNoExplodeObject(ctx echo.Context, param Object) error
-
- // (GET /simplePrimitive/{param})
- GetSimplePrimitive(ctx echo.Context, param int32) error
-
- // (GET /startingWithNumber/{1param})
- GetStartingWithNumber(ctx echo.Context, n1param string) error
-}
-
-// ServerInterfaceWrapper converts echo contexts to parameters.
-type ServerInterfaceWrapper struct {
- Handler ServerInterface
-}
-
-// GetContentObject converts echo context to params.
-func (w *ServerInterfaceWrapper) GetContentObject(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "param" -------------
- var param ComplexObject
-
- err = json.Unmarshal([]byte(ctx.Param("param")), ¶m)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'param' as JSON")
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetContentObject(ctx, param)
- return err
-}
-
-// GetCookie converts echo context to params.
-func (w *ServerInterfaceWrapper) GetCookie(ctx echo.Context) error {
- var err error
-
- // Parameter object where we will unmarshal all parameters from the context
- var params GetCookieParams
-
- if cookie, err := ctx.Cookie("p"); err == nil {
-
- var value int32
- err = runtime.BindStyledParameterWithLocation("simple", false, "p", runtime.ParamLocationCookie, cookie.Value, &value)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter p: %s", err))
- }
- params.P = &value
-
- }
-
- if cookie, err := ctx.Cookie("ep"); err == nil {
-
- var value int32
- err = runtime.BindStyledParameterWithLocation("simple", true, "ep", runtime.ParamLocationCookie, cookie.Value, &value)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ep: %s", err))
- }
- params.Ep = &value
-
- }
-
- if cookie, err := ctx.Cookie("ea"); err == nil {
-
- var value []int32
- err = runtime.BindStyledParameterWithLocation("simple", true, "ea", runtime.ParamLocationCookie, cookie.Value, &value)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ea: %s", err))
- }
- params.Ea = &value
-
- }
-
- if cookie, err := ctx.Cookie("a"); err == nil {
-
- var value []int32
- err = runtime.BindStyledParameterWithLocation("simple", false, "a", runtime.ParamLocationCookie, cookie.Value, &value)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter a: %s", err))
- }
- params.A = &value
-
- }
-
- if cookie, err := ctx.Cookie("eo"); err == nil {
-
- var value Object
- err = runtime.BindStyledParameterWithLocation("simple", true, "eo", runtime.ParamLocationCookie, cookie.Value, &value)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter eo: %s", err))
- }
- params.Eo = &value
-
- }
-
- if cookie, err := ctx.Cookie("o"); err == nil {
-
- var value Object
- err = runtime.BindStyledParameterWithLocation("simple", false, "o", runtime.ParamLocationCookie, cookie.Value, &value)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter o: %s", err))
- }
- params.O = &value
-
- }
-
- if cookie, err := ctx.Cookie("co"); err == nil {
-
- var value ComplexObject
- var decoded string
- decoded, err := url.QueryUnescape(cookie.Value)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, "Error unescaping cookie parameter 'co'")
- }
- err = json.Unmarshal([]byte(decoded), &value)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'co' as JSON")
- }
- params.Co = &value
-
- }
-
- if cookie, err := ctx.Cookie("1s"); err == nil {
-
- var value string
- err = runtime.BindStyledParameterWithLocation("simple", true, "1s", runtime.ParamLocationCookie, cookie.Value, &value)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1s: %s", err))
- }
- params.N1s = &value
-
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetCookie(ctx, params)
- return err
-}
-
-// EnumParams converts echo context to params.
-func (w *ServerInterfaceWrapper) EnumParams(ctx echo.Context) error {
- var err error
-
- // Parameter object where we will unmarshal all parameters from the context
- var params EnumParamsParams
- // ------------- Optional query parameter "enumPathParam" -------------
-
- err = runtime.BindQueryParameter("form", true, false, "enumPathParam", ctx.QueryParams(), ¶ms.EnumPathParam)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter enumPathParam: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.EnumParams(ctx, params)
- return err
-}
-
-// GetHeader converts echo context to params.
-func (w *ServerInterfaceWrapper) GetHeader(ctx echo.Context) error {
- var err error
-
- // Parameter object where we will unmarshal all parameters from the context
- var params GetHeaderParams
-
- headers := ctx.Request().Header
- // ------------- Optional header parameter "X-Primitive" -------------
- if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive")]; found {
- var XPrimitive int32
- n := len(valueList)
- if n != 1 {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Primitive, got %d", n))
- }
-
- err = runtime.BindStyledParameterWithLocation("simple", false, "X-Primitive", runtime.ParamLocationHeader, valueList[0], &XPrimitive)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Primitive: %s", err))
- }
-
- params.XPrimitive = &XPrimitive
- }
- // ------------- Optional header parameter "X-Primitive-Exploded" -------------
- if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive-Exploded")]; found {
- var XPrimitiveExploded int32
- n := len(valueList)
- if n != 1 {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Primitive-Exploded, got %d", n))
- }
-
- err = runtime.BindStyledParameterWithLocation("simple", true, "X-Primitive-Exploded", runtime.ParamLocationHeader, valueList[0], &XPrimitiveExploded)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Primitive-Exploded: %s", err))
- }
-
- params.XPrimitiveExploded = &XPrimitiveExploded
- }
- // ------------- Optional header parameter "X-Array-Exploded" -------------
- if valueList, found := headers[http.CanonicalHeaderKey("X-Array-Exploded")]; found {
- var XArrayExploded []int32
- n := len(valueList)
- if n != 1 {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Array-Exploded, got %d", n))
- }
-
- err = runtime.BindStyledParameterWithLocation("simple", true, "X-Array-Exploded", runtime.ParamLocationHeader, valueList[0], &XArrayExploded)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Array-Exploded: %s", err))
- }
-
- params.XArrayExploded = &XArrayExploded
- }
- // ------------- Optional header parameter "X-Array" -------------
- if valueList, found := headers[http.CanonicalHeaderKey("X-Array")]; found {
- var XArray []int32
- n := len(valueList)
- if n != 1 {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Array, got %d", n))
- }
-
- err = runtime.BindStyledParameterWithLocation("simple", false, "X-Array", runtime.ParamLocationHeader, valueList[0], &XArray)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Array: %s", err))
- }
-
- params.XArray = &XArray
- }
- // ------------- Optional header parameter "X-Object-Exploded" -------------
- if valueList, found := headers[http.CanonicalHeaderKey("X-Object-Exploded")]; found {
- var XObjectExploded Object
- n := len(valueList)
- if n != 1 {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Object-Exploded, got %d", n))
- }
-
- err = runtime.BindStyledParameterWithLocation("simple", true, "X-Object-Exploded", runtime.ParamLocationHeader, valueList[0], &XObjectExploded)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Object-Exploded: %s", err))
- }
-
- params.XObjectExploded = &XObjectExploded
- }
- // ------------- Optional header parameter "X-Object" -------------
- if valueList, found := headers[http.CanonicalHeaderKey("X-Object")]; found {
- var XObject Object
- n := len(valueList)
- if n != 1 {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Object, got %d", n))
- }
-
- err = runtime.BindStyledParameterWithLocation("simple", false, "X-Object", runtime.ParamLocationHeader, valueList[0], &XObject)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Object: %s", err))
- }
-
- params.XObject = &XObject
- }
- // ------------- Optional header parameter "X-Complex-Object" -------------
- if valueList, found := headers[http.CanonicalHeaderKey("X-Complex-Object")]; found {
- var XComplexObject ComplexObject
- n := len(valueList)
- if n != 1 {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Complex-Object, got %d", n))
- }
-
- err = json.Unmarshal([]byte(valueList[0]), &XComplexObject)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'X-Complex-Object' as JSON")
- }
-
- params.XComplexObject = &XComplexObject
- }
- // ------------- Optional header parameter "1-Starting-With-Number" -------------
- if valueList, found := headers[http.CanonicalHeaderKey("1-Starting-With-Number")]; found {
- var N1StartingWithNumber string
- n := len(valueList)
- if n != 1 {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for 1-Starting-With-Number, got %d", n))
- }
-
- err = runtime.BindStyledParameterWithLocation("simple", false, "1-Starting-With-Number", runtime.ParamLocationHeader, valueList[0], &N1StartingWithNumber)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1-Starting-With-Number: %s", err))
- }
-
- params.N1StartingWithNumber = &N1StartingWithNumber
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetHeader(ctx, params)
- return err
-}
-
-// GetLabelExplodeArray converts echo context to params.
-func (w *ServerInterfaceWrapper) GetLabelExplodeArray(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "param" -------------
- var param []int32
-
- err = runtime.BindStyledParameterWithLocation("label", true, "param", runtime.ParamLocationPath, ctx.Param("param"), ¶m)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetLabelExplodeArray(ctx, param)
- return err
-}
-
-// GetLabelExplodeObject converts echo context to params.
-func (w *ServerInterfaceWrapper) GetLabelExplodeObject(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "param" -------------
- var param Object
-
- err = runtime.BindStyledParameterWithLocation("label", true, "param", runtime.ParamLocationPath, ctx.Param("param"), ¶m)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetLabelExplodeObject(ctx, param)
- return err
-}
-
-// GetLabelNoExplodeArray converts echo context to params.
-func (w *ServerInterfaceWrapper) GetLabelNoExplodeArray(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "param" -------------
- var param []int32
-
- err = runtime.BindStyledParameterWithLocation("label", false, "param", runtime.ParamLocationPath, ctx.Param("param"), ¶m)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetLabelNoExplodeArray(ctx, param)
- return err
-}
-
-// GetLabelNoExplodeObject converts echo context to params.
-func (w *ServerInterfaceWrapper) GetLabelNoExplodeObject(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "param" -------------
- var param Object
-
- err = runtime.BindStyledParameterWithLocation("label", false, "param", runtime.ParamLocationPath, ctx.Param("param"), ¶m)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetLabelNoExplodeObject(ctx, param)
- return err
-}
-
-// GetMatrixExplodeArray converts echo context to params.
-func (w *ServerInterfaceWrapper) GetMatrixExplodeArray(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "id" -------------
- var id []int32
-
- err = runtime.BindStyledParameterWithLocation("matrix", true, "id", runtime.ParamLocationPath, ctx.Param("id"), &id)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetMatrixExplodeArray(ctx, id)
- return err
-}
-
-// GetMatrixExplodeObject converts echo context to params.
-func (w *ServerInterfaceWrapper) GetMatrixExplodeObject(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "id" -------------
- var id Object
-
- err = runtime.BindStyledParameterWithLocation("matrix", true, "id", runtime.ParamLocationPath, ctx.Param("id"), &id)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetMatrixExplodeObject(ctx, id)
- return err
-}
-
-// GetMatrixNoExplodeArray converts echo context to params.
-func (w *ServerInterfaceWrapper) GetMatrixNoExplodeArray(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "id" -------------
- var id []int32
-
- err = runtime.BindStyledParameterWithLocation("matrix", false, "id", runtime.ParamLocationPath, ctx.Param("id"), &id)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetMatrixNoExplodeArray(ctx, id)
- return err
-}
-
-// GetMatrixNoExplodeObject converts echo context to params.
-func (w *ServerInterfaceWrapper) GetMatrixNoExplodeObject(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "id" -------------
- var id Object
-
- err = runtime.BindStyledParameterWithLocation("matrix", false, "id", runtime.ParamLocationPath, ctx.Param("id"), &id)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetMatrixNoExplodeObject(ctx, id)
- return err
-}
-
-// GetPassThrough converts echo context to params.
-func (w *ServerInterfaceWrapper) GetPassThrough(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "param" -------------
- var param string
-
- param = ctx.Param("param")
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetPassThrough(ctx, param)
- return err
-}
-
-// GetDeepObject converts echo context to params.
-func (w *ServerInterfaceWrapper) GetDeepObject(ctx echo.Context) error {
- var err error
-
- // Parameter object where we will unmarshal all parameters from the context
- var params GetDeepObjectParams
- // ------------- Required query parameter "deepObj" -------------
-
- err = runtime.BindQueryParameter("deepObject", true, true, "deepObj", ctx.QueryParams(), ¶ms.DeepObj)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter deepObj: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetDeepObject(ctx, params)
- return err
-}
-
-// GetQueryForm converts echo context to params.
-func (w *ServerInterfaceWrapper) GetQueryForm(ctx echo.Context) error {
- var err error
-
- // Parameter object where we will unmarshal all parameters from the context
- var params GetQueryFormParams
- // ------------- Optional query parameter "ea" -------------
-
- err = runtime.BindQueryParameter("form", true, false, "ea", ctx.QueryParams(), ¶ms.Ea)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ea: %s", err))
- }
-
- // ------------- Optional query parameter "a" -------------
-
- err = runtime.BindQueryParameter("form", false, false, "a", ctx.QueryParams(), ¶ms.A)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter a: %s", err))
- }
-
- // ------------- Optional query parameter "eo" -------------
-
- err = runtime.BindQueryParameter("form", true, false, "eo", ctx.QueryParams(), ¶ms.Eo)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter eo: %s", err))
- }
-
- // ------------- Optional query parameter "o" -------------
-
- err = runtime.BindQueryParameter("form", false, false, "o", ctx.QueryParams(), ¶ms.O)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter o: %s", err))
- }
-
- // ------------- Optional query parameter "ep" -------------
-
- err = runtime.BindQueryParameter("form", true, false, "ep", ctx.QueryParams(), ¶ms.Ep)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ep: %s", err))
- }
-
- // ------------- Optional query parameter "p" -------------
-
- err = runtime.BindQueryParameter("form", false, false, "p", ctx.QueryParams(), ¶ms.P)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter p: %s", err))
- }
-
- // ------------- Optional query parameter "ps" -------------
-
- err = runtime.BindQueryParameter("form", true, false, "ps", ctx.QueryParams(), ¶ms.Ps)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ps: %s", err))
- }
-
- // ------------- Optional query parameter "co" -------------
-
- if paramValue := ctx.QueryParam("co"); paramValue != "" {
-
- var value ComplexObject
- err = json.Unmarshal([]byte(paramValue), &value)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'co' as JSON")
- }
- params.Co = &value
-
- }
-
- // ------------- Optional query parameter "1s" -------------
-
- err = runtime.BindQueryParameter("form", true, false, "1s", ctx.QueryParams(), ¶ms.N1s)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1s: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetQueryForm(ctx, params)
- return err
-}
-
-// GetSimpleExplodeArray converts echo context to params.
-func (w *ServerInterfaceWrapper) GetSimpleExplodeArray(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "param" -------------
- var param []int32
-
- err = runtime.BindStyledParameterWithLocation("simple", true, "param", runtime.ParamLocationPath, ctx.Param("param"), ¶m)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetSimpleExplodeArray(ctx, param)
- return err
-}
-
-// GetSimpleExplodeObject converts echo context to params.
-func (w *ServerInterfaceWrapper) GetSimpleExplodeObject(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "param" -------------
- var param Object
-
- err = runtime.BindStyledParameterWithLocation("simple", true, "param", runtime.ParamLocationPath, ctx.Param("param"), ¶m)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetSimpleExplodeObject(ctx, param)
- return err
-}
-
-// GetSimpleNoExplodeArray converts echo context to params.
-func (w *ServerInterfaceWrapper) GetSimpleNoExplodeArray(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "param" -------------
- var param []int32
-
- err = runtime.BindStyledParameterWithLocation("simple", false, "param", runtime.ParamLocationPath, ctx.Param("param"), ¶m)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetSimpleNoExplodeArray(ctx, param)
- return err
-}
-
-// GetSimpleNoExplodeObject converts echo context to params.
-func (w *ServerInterfaceWrapper) GetSimpleNoExplodeObject(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "param" -------------
- var param Object
-
- err = runtime.BindStyledParameterWithLocation("simple", false, "param", runtime.ParamLocationPath, ctx.Param("param"), ¶m)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetSimpleNoExplodeObject(ctx, param)
- return err
-}
-
-// GetSimplePrimitive converts echo context to params.
-func (w *ServerInterfaceWrapper) GetSimplePrimitive(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "param" -------------
- var param int32
-
- err = runtime.BindStyledParameterWithLocation("simple", false, "param", runtime.ParamLocationPath, ctx.Param("param"), ¶m)
- if err != nil {
- return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
- }
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetSimplePrimitive(ctx, param)
- return err
-}
-
-// GetStartingWithNumber converts echo context to params.
-func (w *ServerInterfaceWrapper) GetStartingWithNumber(ctx echo.Context) error {
- var err error
- // ------------- Path parameter "1param" -------------
- var n1param string
-
- n1param = ctx.Param("1param")
-
- // Invoke the callback with all the unmarshaled arguments
- err = w.Handler.GetStartingWithNumber(ctx, n1param)
- return err
-}
-
-// This is a simple interface which specifies echo.Route addition functions which
-// are present on both echo.Echo and echo.Group, since we want to allow using
-// either of them for path registration
-type EchoRouter interface {
- CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
- TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
-}
-
-// RegisterHandlers adds each server route to the EchoRouter.
-func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
-}
-
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
-func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
-
- wrapper := ServerInterfaceWrapper{
- Handler: si,
- }
-
- router.GET(baseURL+"/contentObject/:param", wrapper.GetContentObject)
- router.GET(baseURL+"/cookie", wrapper.GetCookie)
- router.GET(baseURL+"/enums", wrapper.EnumParams)
- router.GET(baseURL+"/header", wrapper.GetHeader)
- router.GET(baseURL+"/labelExplodeArray/:param", wrapper.GetLabelExplodeArray)
- router.GET(baseURL+"/labelExplodeObject/:param", wrapper.GetLabelExplodeObject)
- router.GET(baseURL+"/labelNoExplodeArray/:param", wrapper.GetLabelNoExplodeArray)
- router.GET(baseURL+"/labelNoExplodeObject/:param", wrapper.GetLabelNoExplodeObject)
- router.GET(baseURL+"/matrixExplodeArray/:id", wrapper.GetMatrixExplodeArray)
- router.GET(baseURL+"/matrixExplodeObject/:id", wrapper.GetMatrixExplodeObject)
- router.GET(baseURL+"/matrixNoExplodeArray/:id", wrapper.GetMatrixNoExplodeArray)
- router.GET(baseURL+"/matrixNoExplodeObject/:id", wrapper.GetMatrixNoExplodeObject)
- router.GET(baseURL+"/passThrough/:param", wrapper.GetPassThrough)
- router.GET(baseURL+"/queryDeepObject", wrapper.GetDeepObject)
- router.GET(baseURL+"/queryForm", wrapper.GetQueryForm)
- router.GET(baseURL+"/simpleExplodeArray/:param", wrapper.GetSimpleExplodeArray)
- router.GET(baseURL+"/simpleExplodeObject/:param", wrapper.GetSimpleExplodeObject)
- router.GET(baseURL+"/simpleNoExplodeArray/:param", wrapper.GetSimpleNoExplodeArray)
- router.GET(baseURL+"/simpleNoExplodeObject/:param", wrapper.GetSimpleNoExplodeObject)
- router.GET(baseURL+"/simplePrimitive/:param", wrapper.GetSimplePrimitive)
- router.GET(baseURL+"/startingWithNumber/:1param", wrapper.GetStartingWithNumber)
-
-}
-
-// Base64 encoded, gzipped, json marshaled Swagger object
-var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/9xaUXOjNhD+K8y2Tx1i7Ls+8Za5XtvM9HJpnZnrTCYPCqyDroB0kpwm4+G/dySBAYEx",
- "dkyS61uCVvvtfqy+aJdsIGIZZznmSkK4AYGSs1yi+WVJM57iX+Uj/SRiucJc6R8VPqqAp4Tm+jcZJZgR",
- "8/yJI4QglaD5PRRF4UOMMhKUK8pyCOHck8avV2F57O4rRgq0qfVj0D8wbfX42S6GG+CCcRSK2uAu4gYa",
- "zRXeo4DChwt5Hmc2qHLxjrEUSa4Xa2c/ClxBCD8Edf5BCR58ruMR+G1NBcYQ3lSbfQ1d49y23LZjXFEh",
- "1SXJsIcYHwRL+xYcVGPlN1zdGk5pvmJ6c0ojLF9OboDg08W19q6o0u7hGqXyligeUIAPDyikfQ2L2Xw2",
- "14aMY044hRDez+azBfjAiUpM/EH5vm1+wYYTQbJCr9yjSVcnS/R71W8DfkP1obnBuBIkQ4VCQnjTqh/C",
- "eUojszn4KplTRUOvp10YJRsQmrDBr2gwyNDkUok1Frd+u8bfzee78LZ2gXMQCoMZRIz9Q3GYDWPRoaF9",
- "ILigGVX0QRviI09ZjBCuSCqxTCyq3FSpgd+gasVERpQ9BO/fgd85E4U/ClHTswMQn41YosQeEYI8jYUl",
- "LViqMJOj8LdPLFpPPJ0whvieLowtLaw6MKN4Ya2AxkmZC91FHKLgOMSpjns7k8ga1Bz2ZhAx6JKg1zyp",
- "iFA0v/f+pSrx8nV2Z6Sy18tCtohwpdtVlxhXZJ2qYxUG87UttV6B+ZivsystLHKfwlxVizZF7dZ7IOka",
- "ZZXntzWKp0aFGdcquSpFtM5Yr0B4s5jP/Xfz+a0/Qgy6kvuz5ab1JphXVUuZfIIkRjEkr79bi+fKa1K5",
- "KZP/++yqsWVSoR2APvtYasOLSG83kHNt3R/EiwnxjqheWY67UVlt6idrCnXeFcF3J9LdREpHVUJHSLbr",
- "c3G2LK3PvlCVnF1W1i8m4ym5w7QsDlPAwWZmJOunwbv0H+62rtL1leeYa/BpDpAPUj2ZJsNkCKe8XDc5",
- "q9qPQ0nb1YWcgrUxp2tyfi5ZX1Xt56e9b4Cgpuj8j+pqm3+7sg4gbm9pPYe5166tjChBH53SovHwwfvU",
- "2XTMwaPx5DVls5uOsG1NHcTY8Vq1h7LDimkycjpSReMR5JxAqL7niurq1GGsPUOl3npVcSLldSLY+j4Z",
- "M5e8qs0Hp5IHTLVfZeZo+vRfEHk9ct6VcsNqT4ccI/LhlscZD8TW9dEV4nQLdaHEdcynvoSbFH5lIhvi",
- "7M+t0R7KRjXV7lDlVHPEmi+9FQ5sqp2oXiyocc21y9n0o04H8RSA21T3zX/cbKeZ7A9kezpAr9TGHTjD",
- "c9NXHkM4wR43KnacHDgpfsbfBPs5tX29GtEpLzvb3u58waYIk7HW+sB5AG1vZ8IwGUPuxX3/XWvZs+8N",
- "zximZ2785/Nl38Y3MWWYjKXtB4/x/DQ/zzjMHMXEiOKZkobyb8oXqhI7mw42ixFUdLZN2NgsJu5sNMPm",
- "X1Rs3GuRQgiJUjwMgvL/UxRKNdP9QUb4jFAobov/AgAA//8eGGgVvSQAAA==",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
-func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
- if err != nil {
- return nil, fmt.Errorf("error base64 decoding spec: %w", err)
- }
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
- var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
-
- return buf.Bytes(), nil
-}
-
-var rawSpec = decodeSpecCached()
-
-// a naive cached of a decoded swagger spec
-func decodeSpecCached() func() ([]byte, error) {
- data, err := decodeSpec()
- return func() ([]byte, error) {
- return data, err
- }
-}
-
-// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
-func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
- res := make(map[string]func() ([]byte, error))
- if len(pathToFile) > 0 {
- res[pathToFile] = rawSpec
- }
-
- return res
-}
-
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
- resolvePath := PathToRawSpec("")
-
- loader := openapi3.NewLoader()
- loader.IsExternalRefsAllowed = true
- loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
- pathToFile := url.String()
- pathToFile = path.Clean(pathToFile)
- getSpec, ok := resolvePath[pathToFile]
- if !ok {
- err1 := fmt.Errorf("path not found: %s", pathToFile)
- return nil, err1
- }
- return getSpec()
- }
- var specData []byte
- specData, err = rawSpec()
- if err != nil {
- return
- }
- swagger, err = loader.LoadFromData(specData)
- if err != nil {
- return
- }
- return
-}
diff --git a/internal/test/parameters/config.yaml b/internal/test/parameters/config.yaml
deleted file mode 100644
index 962aa2c573..0000000000
--- a/internal/test/parameters/config.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-package: parameters
-generate:
- echo-server: true
- client: true
- models: true
- embedded-spec: true
-output: parameters.gen.go
diff --git a/internal/test/parameters/doc.go b/internal/test/parameters/doc.go
index 7868d53fff..d18914511e 100644
--- a/internal/test/parameters/doc.go
+++ b/internal/test/parameters/doc.go
@@ -1,3 +1,2 @@
+// Package parameters contains multi-router parameter roundtrip tests.
package parameters
-
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml parameters.yaml
diff --git a/internal/test/parameters/echo/gen/server.gen.go b/internal/test/parameters/echo/gen/server.gen.go
new file mode 100644
index 0000000000..f55c138151
--- /dev/null
+++ b/internal/test/parameters/echo/gen/server.gen.go
@@ -0,0 +1,1017 @@
+// Package echoparamsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package echoparamsgen
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/labstack/echo/v4"
+ "github.com/oapi-codegen/runtime"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /contentObject/{param})
+ GetContentObject(ctx echo.Context, param ComplexObject) error
+
+ // (GET /cookie)
+ GetCookie(ctx echo.Context, params GetCookieParams) error
+
+ // (GET /enums)
+ EnumParams(ctx echo.Context, params EnumParamsParams) error
+
+ // (GET /header)
+ GetHeader(ctx echo.Context, params GetHeaderParams) error
+
+ // (GET /labelExplodeArray/{.param*})
+ GetLabelExplodeArray(ctx echo.Context, param []int32) error
+
+ // (GET /labelExplodeObject/{.param*})
+ GetLabelExplodeObject(ctx echo.Context, param Object) error
+
+ // (GET /labelExplodePrimitive/{.param*})
+ GetLabelExplodePrimitive(ctx echo.Context, param int32) error
+
+ // (GET /labelNoExplodeArray/{.param})
+ GetLabelNoExplodeArray(ctx echo.Context, param []int32) error
+
+ // (GET /labelNoExplodeObject/{.param})
+ GetLabelNoExplodeObject(ctx echo.Context, param Object) error
+
+ // (GET /labelPrimitive/{.param})
+ GetLabelPrimitive(ctx echo.Context, param int32) error
+
+ // (GET /matrixExplodeArray/{.id*})
+ GetMatrixExplodeArray(ctx echo.Context, id []int32) error
+
+ // (GET /matrixExplodeObject/{.id*})
+ GetMatrixExplodeObject(ctx echo.Context, id Object) error
+
+ // (GET /matrixExplodePrimitive/{;id*})
+ GetMatrixExplodePrimitive(ctx echo.Context, id int32) error
+
+ // (GET /matrixNoExplodeArray/{.id})
+ GetMatrixNoExplodeArray(ctx echo.Context, id []int32) error
+
+ // (GET /matrixNoExplodeObject/{.id})
+ GetMatrixNoExplodeObject(ctx echo.Context, id Object) error
+
+ // (GET /matrixPrimitive/{;id})
+ GetMatrixPrimitive(ctx echo.Context, id int32) error
+
+ // (GET /passThrough/{param})
+ GetPassThrough(ctx echo.Context, param string) error
+
+ // (GET /queryDeepObject)
+ GetDeepObject(ctx echo.Context, params GetDeepObjectParams) error
+
+ // (GET /queryDelimited)
+ GetQueryDelimited(ctx echo.Context, params GetQueryDelimitedParams) error
+
+ // (GET /queryForm)
+ GetQueryForm(ctx echo.Context, params GetQueryFormParams) error
+
+ // (GET /simpleExplodeArray/{param*})
+ GetSimpleExplodeArray(ctx echo.Context, param []int32) error
+
+ // (GET /simpleExplodeObject/{param*})
+ GetSimpleExplodeObject(ctx echo.Context, param Object) error
+
+ // (GET /simpleExplodePrimitive/{param})
+ GetSimpleExplodePrimitive(ctx echo.Context, param int32) error
+
+ // (GET /simpleNoExplodeArray/{param})
+ GetSimpleNoExplodeArray(ctx echo.Context, param []int32) error
+
+ // (GET /simpleNoExplodeObject/{param})
+ GetSimpleNoExplodeObject(ctx echo.Context, param Object) error
+
+ // (GET /simplePrimitive/{param})
+ GetSimplePrimitive(ctx echo.Context, param int32) error
+
+ // (GET /startingWithNumber/{1param})
+ GetStartingWithNumber(ctx echo.Context, n1param string) error
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+// GetContentObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetContentObject(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param ComplexObject
+
+ err = json.Unmarshal([]byte(ctx.Param("param")), ¶m)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'param' as JSON")
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetContentObject(ctx, param)
+ return err
+}
+
+// GetCookie converts echo context to params.
+func (w *ServerInterfaceWrapper) GetCookie(ctx echo.Context) error {
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetCookieParams
+
+ if cookie, err := ctx.Cookie("p"); err == nil {
+
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "p", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter p: %s", err))
+ }
+ params.P = &value
+
+ }
+
+ if cookie, err := ctx.Cookie("ep"); err == nil {
+
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ep", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ep: %s", err))
+ }
+ params.Ep = &value
+
+ }
+
+ if cookie, err := ctx.Cookie("ea"); err == nil {
+
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ea", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ea: %s", err))
+ }
+ params.Ea = &value
+
+ }
+
+ if cookie, err := ctx.Cookie("a"); err == nil {
+
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "a", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter a: %s", err))
+ }
+ params.A = &value
+
+ }
+
+ if cookie, err := ctx.Cookie("eo"); err == nil {
+
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "eo", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter eo: %s", err))
+ }
+ params.Eo = &value
+
+ }
+
+ if cookie, err := ctx.Cookie("o"); err == nil {
+
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "o", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter o: %s", err))
+ }
+ params.O = &value
+
+ }
+
+ if cookie, err := ctx.Cookie("co"); err == nil {
+
+ var value ComplexObject
+ var decoded string
+ decoded, err := url.QueryUnescape(cookie.Value)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unescaping cookie parameter 'co'")
+ }
+ err = json.Unmarshal([]byte(decoded), &value)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'co' as JSON")
+ }
+ params.Co = &value
+
+ }
+
+ if cookie, err := ctx.Cookie("1s"); err == nil {
+
+ var value string
+ err = runtime.BindStyledParameterWithOptions("simple", "1s", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1s: %s", err))
+ }
+ params.N1s = &value
+
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetCookie(ctx, params)
+ return err
+}
+
+// EnumParams converts echo context to params.
+func (w *ServerInterfaceWrapper) EnumParams(ctx echo.Context) error {
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params EnumParamsParams
+ // ------------- Optional query parameter "enumPathParam" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "enumPathParam", ctx.QueryParams(), ¶ms.EnumPathParam, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter enumPathParam: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.EnumParams(ctx, params)
+ return err
+}
+
+// GetHeader converts echo context to params.
+func (w *ServerInterfaceWrapper) GetHeader(ctx echo.Context) error {
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetHeaderParams
+
+ headers := ctx.Request().Header
+ // ------------- Optional header parameter "X-Primitive" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive")]; found {
+ var XPrimitive int32
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Primitive, got %d", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive", valueList[0], &XPrimitive, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Primitive: %s", err))
+ }
+
+ params.XPrimitive = &XPrimitive
+ }
+ // ------------- Optional header parameter "X-Primitive-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive-Exploded")]; found {
+ var XPrimitiveExploded int32
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Primitive-Exploded, got %d", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive-Exploded", valueList[0], &XPrimitiveExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Primitive-Exploded: %s", err))
+ }
+
+ params.XPrimitiveExploded = &XPrimitiveExploded
+ }
+ // ------------- Optional header parameter "X-Array-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array-Exploded")]; found {
+ var XArrayExploded []int32
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Array-Exploded, got %d", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array-Exploded", valueList[0], &XArrayExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Array-Exploded: %s", err))
+ }
+
+ params.XArrayExploded = &XArrayExploded
+ }
+ // ------------- Optional header parameter "X-Array" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array")]; found {
+ var XArray []int32
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Array, got %d", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array", valueList[0], &XArray, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Array: %s", err))
+ }
+
+ params.XArray = &XArray
+ }
+ // ------------- Optional header parameter "X-Object-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object-Exploded")]; found {
+ var XObjectExploded Object
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Object-Exploded, got %d", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object-Exploded", valueList[0], &XObjectExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Object-Exploded: %s", err))
+ }
+
+ params.XObjectExploded = &XObjectExploded
+ }
+ // ------------- Optional header parameter "X-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object")]; found {
+ var XObject Object
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Object, got %d", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object", valueList[0], &XObject, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Object: %s", err))
+ }
+
+ params.XObject = &XObject
+ }
+ // ------------- Optional header parameter "X-Complex-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Complex-Object")]; found {
+ var XComplexObject ComplexObject
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Complex-Object, got %d", n))
+ }
+
+ err = json.Unmarshal([]byte(valueList[0]), &XComplexObject)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'X-Complex-Object' as JSON")
+ }
+
+ params.XComplexObject = &XComplexObject
+ }
+ // ------------- Optional header parameter "1-Starting-With-Number" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("1-Starting-With-Number")]; found {
+ var N1StartingWithNumber string
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for 1-Starting-With-Number, got %d", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "1-Starting-With-Number", valueList[0], &N1StartingWithNumber, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1-Starting-With-Number: %s", err))
+ }
+
+ params.N1StartingWithNumber = &N1StartingWithNumber
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetHeader(ctx, params)
+ return err
+}
+
+// GetLabelExplodeArray converts echo context to params.
+func (w *ServerInterfaceWrapper) GetLabelExplodeArray(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetLabelExplodeArray(ctx, param)
+ return err
+}
+
+// GetLabelExplodeObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetLabelExplodeObject(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetLabelExplodeObject(ctx, param)
+ return err
+}
+
+// GetLabelExplodePrimitive converts echo context to params.
+func (w *ServerInterfaceWrapper) GetLabelExplodePrimitive(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetLabelExplodePrimitive(ctx, param)
+ return err
+}
+
+// GetLabelNoExplodeArray converts echo context to params.
+func (w *ServerInterfaceWrapper) GetLabelNoExplodeArray(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetLabelNoExplodeArray(ctx, param)
+ return err
+}
+
+// GetLabelNoExplodeObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetLabelNoExplodeObject(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetLabelNoExplodeObject(ctx, param)
+ return err
+}
+
+// GetLabelPrimitive converts echo context to params.
+func (w *ServerInterfaceWrapper) GetLabelPrimitive(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetLabelPrimitive(ctx, param)
+ return err
+}
+
+// GetMatrixExplodeArray converts echo context to params.
+func (w *ServerInterfaceWrapper) GetMatrixExplodeArray(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetMatrixExplodeArray(ctx, id)
+ return err
+}
+
+// GetMatrixExplodeObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetMatrixExplodeObject(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetMatrixExplodeObject(ctx, id)
+ return err
+}
+
+// GetMatrixExplodePrimitive converts echo context to params.
+func (w *ServerInterfaceWrapper) GetMatrixExplodePrimitive(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetMatrixExplodePrimitive(ctx, id)
+ return err
+}
+
+// GetMatrixNoExplodeArray converts echo context to params.
+func (w *ServerInterfaceWrapper) GetMatrixNoExplodeArray(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetMatrixNoExplodeArray(ctx, id)
+ return err
+}
+
+// GetMatrixNoExplodeObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetMatrixNoExplodeObject(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetMatrixNoExplodeObject(ctx, id)
+ return err
+}
+
+// GetMatrixPrimitive converts echo context to params.
+func (w *ServerInterfaceWrapper) GetMatrixPrimitive(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetMatrixPrimitive(ctx, id)
+ return err
+}
+
+// GetPassThrough converts echo context to params.
+func (w *ServerInterfaceWrapper) GetPassThrough(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param string
+
+ param = ctx.Param("param")
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetPassThrough(ctx, param)
+ return err
+}
+
+// GetDeepObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetDeepObject(ctx echo.Context) error {
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetDeepObjectParams
+ // ------------- Required query parameter "deepObj" -------------
+
+ err = runtime.BindQueryParameterWithOptions("deepObject", true, true, "deepObj", ctx.QueryParams(), ¶ms.DeepObj, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter deepObj: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetDeepObject(ctx, params)
+ return err
+}
+
+// GetQueryDelimited converts echo context to params.
+func (w *ServerInterfaceWrapper) GetQueryDelimited(ctx echo.Context) error {
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryDelimitedParams
+ // ------------- Optional query parameter "sa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("spaceDelimited", false, false, "sa", ctx.QueryParams(), ¶ms.Sa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter sa: %s", err))
+ }
+
+ // ------------- Optional query parameter "pa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("pipeDelimited", false, false, "pa", ctx.QueryParams(), ¶ms.Pa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter pa: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetQueryDelimited(ctx, params)
+ return err
+}
+
+// GetQueryForm converts echo context to params.
+func (w *ServerInterfaceWrapper) GetQueryForm(ctx echo.Context) error {
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryFormParams
+ // ------------- Optional query parameter "ea" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ea", ctx.QueryParams(), ¶ms.Ea, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ea: %s", err))
+ }
+
+ // ------------- Optional query parameter "a" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "a", ctx.QueryParams(), ¶ms.A, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter a: %s", err))
+ }
+
+ // ------------- Optional query parameter "eo" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "eo", ctx.QueryParams(), ¶ms.Eo, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter eo: %s", err))
+ }
+
+ // ------------- Optional query parameter "o" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "o", ctx.QueryParams(), ¶ms.O, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter o: %s", err))
+ }
+
+ // ------------- Optional query parameter "ep" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ep", ctx.QueryParams(), ¶ms.Ep, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ep: %s", err))
+ }
+
+ // ------------- Optional query parameter "p" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "p", ctx.QueryParams(), ¶ms.P, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter p: %s", err))
+ }
+
+ // ------------- Optional query parameter "ps" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ps", ctx.QueryParams(), ¶ms.Ps, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ps: %s", err))
+ }
+
+ // ------------- Optional query parameter "co" -------------
+
+ if paramValue := ctx.QueryParam("co"); paramValue != "" {
+
+ var value ComplexObject
+ err = json.Unmarshal([]byte(paramValue), &value)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'co' as JSON")
+ }
+ params.Co = &value
+
+ }
+
+ // ------------- Optional query parameter "1s" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "1s", ctx.QueryParams(), ¶ms.N1s, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1s: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetQueryForm(ctx, params)
+ return err
+}
+
+// GetSimpleExplodeArray converts echo context to params.
+func (w *ServerInterfaceWrapper) GetSimpleExplodeArray(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetSimpleExplodeArray(ctx, param)
+ return err
+}
+
+// GetSimpleExplodeObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetSimpleExplodeObject(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetSimpleExplodeObject(ctx, param)
+ return err
+}
+
+// GetSimpleExplodePrimitive converts echo context to params.
+func (w *ServerInterfaceWrapper) GetSimpleExplodePrimitive(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetSimpleExplodePrimitive(ctx, param)
+ return err
+}
+
+// GetSimpleNoExplodeArray converts echo context to params.
+func (w *ServerInterfaceWrapper) GetSimpleNoExplodeArray(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetSimpleNoExplodeArray(ctx, param)
+ return err
+}
+
+// GetSimpleNoExplodeObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetSimpleNoExplodeObject(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetSimpleNoExplodeObject(ctx, param)
+ return err
+}
+
+// GetSimplePrimitive converts echo context to params.
+func (w *ServerInterfaceWrapper) GetSimplePrimitive(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetSimplePrimitive(ctx, param)
+ return err
+}
+
+// GetStartingWithNumber converts echo context to params.
+func (w *ServerInterfaceWrapper) GetStartingWithNumber(ctx echo.Context) error {
+ var err error
+ // ------------- Path parameter "1param" -------------
+ var n1param string
+
+ n1param = ctx.Param("1param")
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetStartingWithNumber(ctx, n1param)
+ return err
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
+}
+
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
+}
+
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.GET(options.BaseURL+"/contentObject/:param", wrapper.GetContentObject, options.OperationMiddlewares["getContentObject"]...)
+ router.GET(options.BaseURL+"/cookie", wrapper.GetCookie, options.OperationMiddlewares["getCookie"]...)
+ router.GET(options.BaseURL+"/enums", wrapper.EnumParams, options.OperationMiddlewares["enumParams"]...)
+ router.GET(options.BaseURL+"/header", wrapper.GetHeader, options.OperationMiddlewares["getHeader"]...)
+ router.GET(options.BaseURL+"/labelExplodeArray/:param", wrapper.GetLabelExplodeArray, options.OperationMiddlewares["getLabelExplodeArray"]...)
+ router.GET(options.BaseURL+"/labelExplodeObject/:param", wrapper.GetLabelExplodeObject, options.OperationMiddlewares["getLabelExplodeObject"]...)
+ router.GET(options.BaseURL+"/labelExplodePrimitive/:param", wrapper.GetLabelExplodePrimitive, options.OperationMiddlewares["getLabelExplodePrimitive"]...)
+ router.GET(options.BaseURL+"/labelNoExplodeArray/:param", wrapper.GetLabelNoExplodeArray, options.OperationMiddlewares["getLabelNoExplodeArray"]...)
+ router.GET(options.BaseURL+"/labelNoExplodeObject/:param", wrapper.GetLabelNoExplodeObject, options.OperationMiddlewares["getLabelNoExplodeObject"]...)
+ router.GET(options.BaseURL+"/labelPrimitive/:param", wrapper.GetLabelPrimitive, options.OperationMiddlewares["getLabelPrimitive"]...)
+ router.GET(options.BaseURL+"/matrixExplodeArray/:id", wrapper.GetMatrixExplodeArray, options.OperationMiddlewares["getMatrixExplodeArray"]...)
+ router.GET(options.BaseURL+"/matrixExplodeObject/:id", wrapper.GetMatrixExplodeObject, options.OperationMiddlewares["getMatrixExplodeObject"]...)
+ router.GET(options.BaseURL+"/matrixExplodePrimitive/:id", wrapper.GetMatrixExplodePrimitive, options.OperationMiddlewares["getMatrixExplodePrimitive"]...)
+ router.GET(options.BaseURL+"/matrixNoExplodeArray/:id", wrapper.GetMatrixNoExplodeArray, options.OperationMiddlewares["getMatrixNoExplodeArray"]...)
+ router.GET(options.BaseURL+"/matrixNoExplodeObject/:id", wrapper.GetMatrixNoExplodeObject, options.OperationMiddlewares["getMatrixNoExplodeObject"]...)
+ router.GET(options.BaseURL+"/matrixPrimitive/:id", wrapper.GetMatrixPrimitive, options.OperationMiddlewares["getMatrixPrimitive"]...)
+ router.GET(options.BaseURL+"/passThrough/:param", wrapper.GetPassThrough, options.OperationMiddlewares["getPassThrough"]...)
+ router.GET(options.BaseURL+"/queryDeepObject", wrapper.GetDeepObject, options.OperationMiddlewares["getDeepObject"]...)
+ router.GET(options.BaseURL+"/queryDelimited", wrapper.GetQueryDelimited, options.OperationMiddlewares["getQueryDelimited"]...)
+ router.GET(options.BaseURL+"/queryForm", wrapper.GetQueryForm, options.OperationMiddlewares["getQueryForm"]...)
+ router.GET(options.BaseURL+"/simpleExplodeArray/:param", wrapper.GetSimpleExplodeArray, options.OperationMiddlewares["getSimpleExplodeArray"]...)
+ router.GET(options.BaseURL+"/simpleExplodeObject/:param", wrapper.GetSimpleExplodeObject, options.OperationMiddlewares["getSimpleExplodeObject"]...)
+ router.GET(options.BaseURL+"/simpleExplodePrimitive/:param", wrapper.GetSimpleExplodePrimitive, options.OperationMiddlewares["getSimpleExplodePrimitive"]...)
+ router.GET(options.BaseURL+"/simpleNoExplodeArray/:param", wrapper.GetSimpleNoExplodeArray, options.OperationMiddlewares["getSimpleNoExplodeArray"]...)
+ router.GET(options.BaseURL+"/simpleNoExplodeObject/:param", wrapper.GetSimpleNoExplodeObject, options.OperationMiddlewares["getSimpleNoExplodeObject"]...)
+ router.GET(options.BaseURL+"/simplePrimitive/:param", wrapper.GetSimplePrimitive, options.OperationMiddlewares["getSimplePrimitive"]...)
+ router.GET(options.BaseURL+"/startingWithNumber/:1param", wrapper.GetStartingWithNumber, options.OperationMiddlewares["getStartingWithNumber"]...)
+
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "3FpLb+M2F/0rwv2+VaFYdqYrdRVMp22ATiatA0yBIAtGuo44lUQOSacJDP33gpRkPa2HLeXRXWJd3sch",
+ "z6F4qR14LOIsxlhJcHcgUHIWSzT/rGnEQ/wz+0n/4rFYYaz0nwqflMNDQmP9n/QCjIj5/ZkjuCCVoPED",
+ "JElig4/SE5QrymJw4cKSxq+Vx7LY/Tf0FGjT1I+J/pFpq6cv6UN3B1wwjkLRNLlLvxSNxgofUEBiw6W8",
+ "8KM0qezhPWMhklg/LJz9X+AGXPifU9TvZMGdL0U+Ar9vqUAf3Nt8sK1DF3HuKm6rOW6okOqKRNgCjA2C",
+ "hW0PalGNlV1ydWcwpfGG6cEh9TCbnNgEgs+XN9q7okq7hxuUylqjeEQBNjyikOk0rBbLxVIbMo4x4RRc",
+ "+LBYLlZgAycqMPk72Xyn9Tk7TgSJEv3kAU25ulii51XPBvyK6mN5gHElSIQKhQT3trJ+COch9cxg55tk",
+ "tVXUNT3VhZGhAa5JG+wcBhMZylgqscXkzq6u8fPl8lC8vZ1TI0JiYjoeY39T7EbDWDRgqBKCCxpRRR+1",
+ "IT7xkPkI7oaEErPCvNxNXhrYJag2TEREpST4cA52gxOJPSiihudAQDw5YhbFt4gQ5HloWFIJSxVGclD8",
+ "/S9ptJZ8Gml04T1fGntYWE6YQbiwSkLDpKweuhmxC4LjIs5F92olXmpQYNhagcegCYJ+ZklFhKLxg/UP",
+ "VYEVb6N7I5WtXlayAkRduuvq4uOGbEN1rMJgvE2XWqvAfIq30bUWFtmnMNf5w7RE7dZ6JOEWZV7n9y2K",
+ "59IKM65VcJ2JaFGxfgLu7Wq5tM+Xyzt7gBg0JffHFJvKTDArXy1Z8QESH0WXvP6WWpwqr0HuJiv+r7Pr",
+ "0pBZhbYj9NmnTBteRHqbiVxo6/YkXkyID2T1ynLczCrVpnaw5lDnQxm8O5FuFpI5ygs6QrLrPldn68z6",
+ "7CtVwdlVbv1iMh6SewyzxWEWsLNbGMn6ofNd+vf6sKbStS3PIa/B0xDIBqmezSHDVAhTvlyXMcuPH2NB",
+ "O3QKmQK1Iex6KXz2e8Z4iMo73QwoDVhSM0N0xdqI149PdVwHOmVd/g9Rb19/lXwjgOtl3ynIvQn6NXjX",
+ "j84Qvp2Cy6sSLiJK0Kca36jfrUafG4OOkSLqz060tLr5ANsTbRRix+9xPZCNY9jc4JSo9tMofE7a4Hog",
+ "GkG22fBp7G/UHwDOBLvbe2Zcc3Mbh9oJW9v7YF2VbgOgOW1fe9M840TKm0Cw7UMw5AbkujDvvP8YcX/2",
+ "KrcbpiP4MyIvLrcOlVyy6unF+Yi8u7lSa0T6qeujOVPrSxQLxS9ynvq4nyEXakag3wXcH1XLHvAkJx5a",
+ "fm5udbbOajjKqe4wCgRNOkXyLc1Pyo9Nl0+frs6mlO3UTPmFiah3qo1RzywPatfW2/XTw6WHwsh2bS2r",
+ "F0tqWNu2jtn8l2i1iFME3Jfad7NQr3aeO+MuCk8W0Mr2wgNxum/kXrnBXUv2uEvImpORd5AnKFv6oU71",
+ "gDGgwbhuDHu7neu0RJgNtcqnMyNgezu967kRKp01+t+u160jX715PRtG9eP9UITeTft6fuSGf7y2bhv4",
+ "JhrYs6F0BPk6WPceaZbtu1+pCtKbYWe3GgBFY9iMh/3VzKd9jbD5QDTNeytCcCFQiruOk30dqlCqhT4z",
+ "R4QvCIXkLvk3AAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/parameters/echo/gen/types.gen.go b/internal/test/parameters/echo/gen/types.gen.go
new file mode 100644
index 0000000000..043be6dba0
--- /dev/null
+++ b/internal/test/parameters/echo/gen/types.gen.go
@@ -0,0 +1,143 @@
+// Package echoparamsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package echoparamsgen
+
+// Defines values for EnumParamsParamsEnumPathParam.
+const (
+ N100 EnumParamsParamsEnumPathParam = 100
+ N200 EnumParamsParamsEnumPathParam = 200
+)
+
+// Valid indicates whether the value is a known member of the EnumParamsParamsEnumPathParam enum.
+func (e EnumParamsParamsEnumPathParam) Valid() bool {
+ switch e {
+ case N100:
+ return true
+ case N200:
+ return true
+ default:
+ return false
+ }
+}
+
+// ComplexObject defines model for ComplexObject.
+type ComplexObject struct {
+ Id int `json:"Id"`
+ IsAdmin bool `json:"IsAdmin"`
+ Object Object `json:"Object"`
+}
+
+// Object defines model for Object.
+type Object struct {
+ FirstName string `json:"firstName"`
+ Role string `json:"role"`
+}
+
+// GetCookieParams defines parameters for GetCookie.
+type GetCookieParams struct {
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ep primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
+
+// EnumParamsParams defines parameters for EnumParams.
+type EnumParamsParams struct {
+ // EnumPathParam Parameter with enum values
+ EnumPathParam *EnumParamsParamsEnumPathParam `form:"enumPathParam,omitempty" json:"enumPathParam,omitempty"`
+}
+
+// EnumParamsParamsEnumPathParam defines parameters for EnumParams.
+type EnumParamsParamsEnumPathParam int32
+
+// GetHeaderParams defines parameters for GetHeader.
+type GetHeaderParams struct {
+ // XPrimitive primitive
+ XPrimitive *int32 `json:"X-Primitive,omitempty"`
+
+ // XPrimitiveExploded primitive
+ XPrimitiveExploded *int32 `json:"X-Primitive-Exploded,omitempty"`
+
+ // XArrayExploded exploded array
+ XArrayExploded *[]int32 `json:"X-Array-Exploded,omitempty"`
+
+ // XArray array
+ XArray *[]int32 `json:"X-Array,omitempty"`
+
+ // XObjectExploded exploded object
+ XObjectExploded *Object `json:"X-Object-Exploded,omitempty"`
+
+ // XObject object
+ XObject *Object `json:"X-Object,omitempty"`
+
+ // XComplexObject complex object
+ XComplexObject *ComplexObject `json:"X-Complex-Object,omitempty"`
+
+ // N1StartingWithNumber name starting with number
+ N1StartingWithNumber *string `json:"1-Starting-With-Number,omitempty"`
+}
+
+// GetDeepObjectParams defines parameters for GetDeepObject.
+type GetDeepObjectParams struct {
+ // DeepObj deep object
+ DeepObj ComplexObject `json:"deepObj"`
+}
+
+// GetQueryDelimitedParams defines parameters for GetQueryDelimited.
+type GetQueryDelimitedParams struct {
+ // Sa space delimited array
+ Sa *[]int32 `json:"sa,omitempty"`
+
+ // Pa pipe delimited array
+ Pa *[]int32 `json:"pa,omitempty"`
+}
+
+// GetQueryFormParams defines parameters for GetQueryForm.
+type GetQueryFormParams struct {
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Ep exploded primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ps primitive string
+ Ps *string `form:"ps,omitempty" json:"ps,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
diff --git a/internal/test/parameters/parameters_test.go b/internal/test/parameters/echo/parameters_test.go
similarity index 63%
rename from internal/test/parameters/parameters_test.go
rename to internal/test/parameters/echo/parameters_test.go
index 3e3fb5408b..6e6d63bea5 100644
--- a/internal/test/parameters/parameters_test.go
+++ b/internal/test/parameters/echo/parameters_test.go
@@ -1,30 +1,30 @@
-package parameters
+package echoparams
import (
"encoding/json"
"fmt"
"net/http"
- "net/http/httptest"
"testing"
- "github.com/deepmap/oapi-codegen/pkg/testutil"
"github.com/labstack/echo/v4"
- "github.com/labstack/echo/v4/middleware"
+ "github.com/oapi-codegen/testutil"
"github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
+
+ . "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/echo/gen"
)
type testServer struct {
- array []int32
- object *Object
- complexObject *ComplexObject
- passThrough *string
- n1param *string
- primitive *int32
- primitiveString *string
- cookieParams *GetCookieParams
- queryParams *GetQueryFormParams
- headerParams *GetHeaderParams
+ array []int32
+ object *Object
+ complexObject *ComplexObject
+ passThrough *string
+ n1param *string
+ primitive *int32
+ primitiveString *string
+ cookieParams *GetCookieParams
+ queryParams *GetQueryFormParams
+ queryDelimitedParams *GetQueryDelimitedParams
+ headerParams *GetHeaderParams
}
func (t *testServer) reset() {
@@ -37,6 +37,7 @@ func (t *testServer) reset() {
t.primitiveString = nil
t.cookieParams = nil
t.queryParams = nil
+ t.queryDelimitedParams = nil
t.headerParams = nil
}
@@ -142,6 +143,48 @@ func (t *testServer) GetSimplePrimitive(ctx echo.Context, param int32) error {
return nil
}
+// (GET /simpleExplodePrimitive/{param})
+func (t *testServer) GetSimpleExplodePrimitive(ctx echo.Context, param int32) error {
+ t.primitive = ¶m
+ return nil
+}
+
+// (GET /labelPrimitive/{.param})
+func (t *testServer) GetLabelPrimitive(ctx echo.Context, param int32) error {
+ t.primitive = ¶m
+ return nil
+}
+
+// (GET /labelExplodePrimitive/{.param*})
+func (t *testServer) GetLabelExplodePrimitive(ctx echo.Context, param int32) error {
+ t.primitive = ¶m
+ return nil
+}
+
+// (GET /matrixPrimitive/{;id})
+func (t *testServer) GetMatrixPrimitive(ctx echo.Context, id int32) error {
+ t.primitive = &id
+ return nil
+}
+
+// (GET /matrixExplodePrimitive/{;id*})
+func (t *testServer) GetMatrixExplodePrimitive(ctx echo.Context, id int32) error {
+ t.primitive = &id
+ return nil
+}
+
+// (GET /queryDelimited)
+func (t *testServer) GetQueryDelimited(ctx echo.Context, params GetQueryDelimitedParams) error {
+ t.queryDelimitedParams = ¶ms
+ if params.Sa != nil {
+ t.array = *params.Sa
+ }
+ if params.Pa != nil {
+ t.array = *params.Pa
+ }
+ return nil
+}
+
// (GET /queryForm)
func (t *testServer) GetQueryForm(ctx echo.Context, params GetQueryFormParams) error {
t.queryParams = ¶ms
@@ -243,7 +286,6 @@ func (t *testServer) EnumParams(ctx echo.Context, params EnumParamsParams) error
func TestParameterBinding(t *testing.T) {
var ts testServer
e := echo.New()
- e.Use(middleware.Logger())
RegisterHandlers(e, &ts)
expectedObject := Object{
@@ -267,9 +309,9 @@ func TestParameterBinding(t *testing.T) {
// Check the passthrough case
// (GET /passThrough/{param})
- result := testutil.NewRequest().Get("/passThrough/some%20string").Go(t, e)
+ result := testutil.NewRequest().Get("/passThrough/some%20string").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
- require.NotNil(t, ts.passThrough)
+ assert.NotNil(t, ts.passThrough)
assert.EqualValues(t, "some string", *ts.passThrough)
ts.reset()
@@ -278,159 +320,208 @@ func TestParameterBinding(t *testing.T) {
marshaledComplexObject, err := json.Marshal(expectedComplexObject)
assert.NoError(t, err)
q := fmt.Sprintf("/contentObject/%s", string(marshaledComplexObject))
- result = testutil.NewRequest().Get(q).Go(t, e)
+ result = testutil.NewRequest().Get(q).GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedComplexObject, ts.complexObject)
ts.reset()
// (GET /labelExplodeArray/{.param*})
- result = testutil.NewRequest().Get("/labelExplodeArray/.3.4.5").Go(t, e)
+ result = testutil.NewRequest().Get("/labelExplodeArray/.3.4.5").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, expectedArray, ts.array)
ts.reset()
// (GET /labelExplodeObject/{.param*})
- result = testutil.NewRequest().Get("/labelExplodeObject/.role=admin.firstName=Alex").Go(t, e)
+ result = testutil.NewRequest().Get("/labelExplodeObject/.role=admin.firstName=Alex").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedObject, ts.object)
ts.reset()
// (GET /labelNoExplodeArray/{.param})
- result = testutil.NewRequest().Get("/labelNoExplodeArray/.3,4,5").Go(t, e)
+ result = testutil.NewRequest().Get("/labelNoExplodeArray/.3,4,5").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, expectedArray, ts.array)
ts.reset()
// (GET /labelNoExplodeObject/{.param})
- result = testutil.NewRequest().Get("/labelNoExplodeObject/.role,admin,firstName,Alex").Go(t, e)
+ result = testutil.NewRequest().Get("/labelNoExplodeObject/.role,admin,firstName,Alex").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedObject, ts.object)
ts.reset()
// (GET /matrixExplodeArray/{.param*})
uri := "/matrixExplodeArray/;id=3;id=4;id=5"
- result = testutil.NewRequest().Get(uri).Go(t, e)
+ result = testutil.NewRequest().Get(uri).GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, expectedArray, ts.array)
ts.reset()
// (GET /matrixExplodeObject/{.param*})
uri = "/matrixExplodeObject/;role=admin;firstName=Alex"
- result = testutil.NewRequest().Get(uri).Go(t, e)
+ result = testutil.NewRequest().Get(uri).GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedObject, ts.object)
ts.reset()
// (GET /matrixNoExplodeArray/{.param})
- result = testutil.NewRequest().Get("/matrixNoExplodeArray/;id=3,4,5").Go(t, e)
+ result = testutil.NewRequest().Get("/matrixNoExplodeArray/;id=3,4,5").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, expectedArray, ts.array)
ts.reset()
// (GET /matrixNoExplodeObject/{.param})
- result = testutil.NewRequest().Get("/matrixNoExplodeObject/;id=role,admin,firstName,Alex").Go(t, e)
+ result = testutil.NewRequest().Get("/matrixNoExplodeObject/;id=role,admin,firstName,Alex").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedObject, ts.object)
ts.reset()
// (GET /simpleExplodeArray/{param*})
- result = testutil.NewRequest().Get("/simpleExplodeArray/3,4,5").Go(t, e)
+ result = testutil.NewRequest().Get("/simpleExplodeArray/3,4,5").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, expectedArray, ts.array)
ts.reset()
// (GET /simpleExplodeObject/{param*})
- result = testutil.NewRequest().Get("/simpleExplodeObject/role=admin,firstName=Alex").Go(t, e)
+ result = testutil.NewRequest().Get("/simpleExplodeObject/role=admin,firstName=Alex").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedObject, ts.object)
ts.reset()
// (GET /simpleNoExplodeArray/{param})
- result = testutil.NewRequest().Get("/simpleNoExplodeArray/3,4,5").Go(t, e)
+ result = testutil.NewRequest().Get("/simpleNoExplodeArray/3,4,5").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, expectedArray, ts.array)
ts.reset()
// (GET /simpleNoExplodeObject/{param})
- result = testutil.NewRequest().Get("/simpleNoExplodeObject/role,admin,firstName,Alex").Go(t, e)
+ result = testutil.NewRequest().Get("/simpleNoExplodeObject/role,admin,firstName,Alex").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedObject, ts.object)
ts.reset()
// (GET /simplePrimitive/{param})
- result = testutil.NewRequest().Get("/simplePrimitive/5").Go(t, e)
+ result = testutil.NewRequest().Get("/simplePrimitive/5").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedPrimitive, ts.primitive)
ts.reset()
// (GET /startingWithNumber/{1param})
- result = testutil.NewRequest().Get("/startingWithNumber/foo").Go(t, e)
+ result = testutil.NewRequest().Get("/startingWithNumber/foo").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedN1Param, ts.n1param)
ts.reset()
+ // (GET /simpleExplodePrimitive/{param})
+ result = testutil.NewRequest().Get("/simpleExplodePrimitive/5").GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusOK, result.Code())
+ assert.EqualValues(t, &expectedPrimitive, ts.primitive)
+ ts.reset()
+
+ // (GET /labelPrimitive/{.param})
+ result = testutil.NewRequest().Get("/labelPrimitive/.5").GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusOK, result.Code())
+ assert.EqualValues(t, &expectedPrimitive, ts.primitive)
+ ts.reset()
+
+ // (GET /labelExplodePrimitive/{.param*})
+ result = testutil.NewRequest().Get("/labelExplodePrimitive/.5").GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusOK, result.Code())
+ assert.EqualValues(t, &expectedPrimitive, ts.primitive)
+ ts.reset()
+
+ // (GET /matrixPrimitive/{;id})
+ result = testutil.NewRequest().Get("/matrixPrimitive/;id=5").GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusOK, result.Code())
+ assert.EqualValues(t, &expectedPrimitive, ts.primitive)
+ ts.reset()
+
+ // (GET /matrixExplodePrimitive/{;id*})
+ result = testutil.NewRequest().Get("/matrixExplodePrimitive/;id=5").GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusOK, result.Code())
+ assert.EqualValues(t, &expectedPrimitive, ts.primitive)
+ ts.reset()
+
// ---------------------- Test Form Query Parameters ----------------------
// (GET /queryForm)
// unexploded array
- result = testutil.NewRequest().Get("/queryForm?a=3,4,5").Go(t, e)
+ result = testutil.NewRequest().Get("/queryForm?a=3,4,5").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, expectedArray, ts.array)
ts.reset()
// exploded array
- result = testutil.NewRequest().Get("/queryForm?ea=3&ea=4&ea=5").Go(t, e)
+ result = testutil.NewRequest().Get("/queryForm?ea=3&ea=4&ea=5").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, expectedArray, ts.array)
ts.reset()
// unexploded object
- result = testutil.NewRequest().Get("/queryForm?o=role,admin,firstName,Alex").Go(t, e)
+ result = testutil.NewRequest().Get("/queryForm?o=role,admin,firstName,Alex").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedObject, ts.object)
ts.reset()
// exploded object
- result = testutil.NewRequest().Get("/queryForm?role=admin&firstName=Alex").Go(t, e)
+ result = testutil.NewRequest().Get("/queryForm?role=admin&firstName=Alex").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedObject, ts.object)
ts.reset()
// exploded primitive
- result = testutil.NewRequest().Get("/queryForm?ep=5").Go(t, e)
+ result = testutil.NewRequest().Get("/queryForm?ep=5").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedPrimitive, ts.primitive)
ts.reset()
// unexploded primitive
- result = testutil.NewRequest().Get("/queryForm?p=5").Go(t, e)
+ result = testutil.NewRequest().Get("/queryForm?p=5").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedPrimitive, ts.primitive)
ts.reset()
// primitive string within reserved char, i.e., ';' escaped to '%3B'
- result = testutil.NewRequest().Get("/queryForm?ps=123%3B456").Go(t, e)
+ result = testutil.NewRequest().Get("/queryForm?ps=123%3B456").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedPrimitiveString, ts.primitiveString)
ts.reset()
// complex object
q = fmt.Sprintf("/queryForm?co=%s", string(marshaledComplexObject))
- result = testutil.NewRequest().Get(q).Go(t, e)
+ result = testutil.NewRequest().Get(q).GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedComplexObject, ts.complexObject)
ts.reset()
// starting with number
- result = testutil.NewRequest().Get("/queryForm?1s=foo").Go(t, e)
+ result = testutil.NewRequest().Get("/queryForm?1s=foo").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedN1Param, ts.n1param)
ts.reset()
+ // -------------------- Test Delimited Query Parameters --------------------
+ // (GET /queryDelimited)
+ // These styles are not yet supported by the runtime binding layer.
+ // See https://github.com/oapi-codegen/runtime/issues/116
+
+ t.Run("spaceDelimited array", func(t *testing.T) {
+ result = testutil.NewRequest().Get("/queryDelimited?sa=3%204%205").GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusOK, result.Code())
+ assert.EqualValues(t, expectedArray, ts.array)
+ ts.reset()
+ })
+
+ t.Run("pipeDelimited array", func(t *testing.T) {
+ result = testutil.NewRequest().Get("/queryDelimited?pa=3|4|5").GoWithHTTPHandler(t, e)
+ assert.Equal(t, http.StatusOK, result.Code())
+ assert.EqualValues(t, expectedArray, ts.array)
+ ts.reset()
+ })
+
// complex object via deepObject
do := `deepObj[Id]=12345&deepObj[IsAdmin]=true&deepObj[Object][firstName]=Alex&deepObj[Object][role]=admin`
q = "/queryDeepObject?" + do
- result = testutil.NewRequest().Get(q).Go(t, e)
+ result = testutil.NewRequest().Get(q).GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedComplexObject, ts.complexObject)
ts.reset()
@@ -438,300 +529,84 @@ func TestParameterBinding(t *testing.T) {
// ---------------------- Test Header Query Parameters --------------------
// unexploded header primitive.
- result = testutil.NewRequest().WithHeader("X-Primitive", "5").Get("/header").Go(t, e)
+ result = testutil.NewRequest().WithHeader("X-Primitive", "5").Get("/header").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedPrimitive, ts.primitive)
ts.reset()
// exploded header primitive.
- result = testutil.NewRequest().WithHeader("X-Primitive-Exploded", "5").Get("/header").Go(t, e)
+ result = testutil.NewRequest().WithHeader("X-Primitive-Exploded", "5").Get("/header").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedPrimitive, ts.primitive)
ts.reset()
// unexploded header array
- result = testutil.NewRequest().WithHeader("X-Array", "3,4,5").Get("/header").Go(t, e)
+ result = testutil.NewRequest().WithHeader("X-Array", "3,4,5").Get("/header").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, expectedArray, ts.array)
ts.reset()
// exploded header array
- result = testutil.NewRequest().WithHeader("X-Array-Exploded", "3,4,5").Get("/header").Go(t, e)
+ result = testutil.NewRequest().WithHeader("X-Array-Exploded", "3,4,5").Get("/header").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, expectedArray, ts.array)
ts.reset()
// unexploded header object
result = testutil.NewRequest().WithHeader("X-Object",
- "role,admin,firstName,Alex").Get("/header").Go(t, e)
+ "role,admin,firstName,Alex").Get("/header").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedObject, ts.object)
ts.reset()
// exploded header object
result = testutil.NewRequest().WithHeader("X-Object-Exploded",
- "role=admin,firstName=Alex").Get("/header").Go(t, e)
+ "role=admin,firstName=Alex").Get("/header").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedObject, ts.object)
ts.reset()
// complex object
result = testutil.NewRequest().WithHeader("X-Complex-Object",
- string(marshaledComplexObject)).Get("/header").Go(t, e)
+ string(marshaledComplexObject)).Get("/header").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedComplexObject, ts.complexObject)
ts.reset()
// starting with number
result = testutil.NewRequest().WithHeader("1-Starting-With-Number",
- "foo").Get("/header").Go(t, e)
+ "foo").Get("/header").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedN1Param, ts.n1param)
ts.reset()
// ------------------------- Test Cookie Parameters ------------------------
- result = testutil.NewRequest().WithCookieNameValue("p", "5").Get("/cookie").Go(t, e)
+ result = testutil.NewRequest().WithCookieNameValue("p", "5").Get("/cookie").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedPrimitive, ts.primitive)
ts.reset()
- result = testutil.NewRequest().WithCookieNameValue("ep", "5").Get("/cookie").Go(t, e)
+ result = testutil.NewRequest().WithCookieNameValue("ep", "5").Get("/cookie").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedPrimitive, ts.primitive)
ts.reset()
- result = testutil.NewRequest().WithCookieNameValue("a", "3,4,5").Get("/cookie").Go(t, e)
+ result = testutil.NewRequest().WithCookieNameValue("a", "3,4,5").Get("/cookie").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, expectedArray, ts.array)
ts.reset()
result = testutil.NewRequest().WithCookieNameValue(
- "o", "role,admin,firstName,Alex").Get("/cookie").Go(t, e)
+ "o", "role,admin,firstName,Alex").Get("/cookie").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedObject, ts.object)
ts.reset()
- result = testutil.NewRequest().WithCookieNameValue("1s", "foo").Get("/cookie").Go(t, e)
+ result = testutil.NewRequest().WithCookieNameValue("1s", "foo").Get("/cookie").GoWithHTTPHandler(t, e)
assert.Equal(t, http.StatusOK, result.Code())
assert.EqualValues(t, &expectedN1Param, ts.n1param)
ts.reset()
}
-func doRequest(t *testing.T, e *echo.Echo, code int, req *http.Request) *httptest.ResponseRecorder {
- rec := httptest.NewRecorder()
- e.ServeHTTP(rec, req)
- assert.Equal(t, code, rec.Code)
- return rec
-}
-
-func TestClientPathParams(t *testing.T) {
- var ts testServer
- e := echo.New()
- e.Use(middleware.Logger())
- RegisterHandlers(e, &ts)
- server := "http://example.com"
-
- expectedObject := Object{
- FirstName: "Alex",
- Role: "admin",
- }
-
- expectedComplexObject := ComplexObject{
- Object: expectedObject,
- Id: 12345,
- IsAdmin: true,
- }
-
- expectedArray := []int32{3, 4, 5}
-
- var expectedPrimitive int32 = 5
-
- req, err := NewGetPassThroughRequest(server, "some string")
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- require.NotNil(t, ts.passThrough)
- assert.Equal(t, "some string", *ts.passThrough)
- ts.reset()
-
- req, err = NewGetStartingWithNumberRequest(server, "some string")
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- require.NotNil(t, ts.n1param)
- assert.Equal(t, "some string", *ts.n1param)
- ts.reset()
-
- req, err = NewGetContentObjectRequest(server, expectedComplexObject)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- assert.EqualValues(t, &expectedComplexObject, ts.complexObject)
- ts.reset()
-
- // Label style
- req, err = NewGetLabelExplodeArrayRequest(server, expectedArray)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- assert.EqualValues(t, expectedArray, ts.array)
- ts.reset()
-
- req, err = NewGetLabelNoExplodeArrayRequest(server, expectedArray)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- assert.EqualValues(t, expectedArray, ts.array)
- ts.reset()
-
- req, err = NewGetLabelExplodeObjectRequest(server, expectedObject)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- assert.EqualValues(t, &expectedObject, ts.object)
- ts.reset()
-
- req, err = NewGetLabelNoExplodeObjectRequest(server, expectedObject)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- assert.EqualValues(t, &expectedObject, ts.object)
- ts.reset()
-
- // Matrix style
- req, err = NewGetMatrixExplodeArrayRequest(server, expectedArray)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- assert.EqualValues(t, expectedArray, ts.array)
- ts.reset()
-
- req, err = NewGetMatrixNoExplodeArrayRequest(server, expectedArray)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- assert.EqualValues(t, expectedArray, ts.array)
- ts.reset()
-
- req, err = NewGetMatrixExplodeObjectRequest(server, expectedObject)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- assert.EqualValues(t, &expectedObject, ts.object)
- ts.reset()
-
- req, err = NewGetMatrixNoExplodeObjectRequest(server, expectedObject)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- assert.EqualValues(t, &expectedObject, ts.object)
- ts.reset()
-
- // Simple style
- req, err = NewGetSimpleExplodeArrayRequest(server, expectedArray)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- assert.EqualValues(t, expectedArray, ts.array)
- ts.reset()
-
- req, err = NewGetSimpleNoExplodeArrayRequest(server, expectedArray)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- assert.EqualValues(t, expectedArray, ts.array)
- ts.reset()
-
- req, err = NewGetSimpleExplodeObjectRequest(server, expectedObject)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- assert.EqualValues(t, &expectedObject, ts.object)
- ts.reset()
-
- req, err = NewGetSimpleNoExplodeObjectRequest(server, expectedObject)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- assert.EqualValues(t, &expectedObject, ts.object)
- ts.reset()
-
- req, err = NewGetSimplePrimitiveRequest(server, expectedPrimitive)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- assert.EqualValues(t, &expectedPrimitive, ts.primitive)
- ts.reset()
-}
-
-func TestClientQueryParams(t *testing.T) {
- var ts testServer
- e := echo.New()
- e.Use(middleware.Logger())
- RegisterHandlers(e, &ts)
- server := "http://example.com"
-
- expectedObject1 := Object{
- FirstName: "Alex",
- Role: "admin",
- }
- expectedObject2 := Object{
- FirstName: "Marcin",
- Role: "annoyed_at_swagger",
- }
-
- expectedComplexObject := ComplexObject{
- Object: expectedObject2,
- Id: 12345,
- IsAdmin: true,
- }
-
- expectedArray1 := []int32{3, 4, 5}
- expectedArray2 := []int32{6, 7, 8}
-
- var expectedPrimitive1 int32 = 5
- var expectedPrimitive2 int32 = 100
- var expectedPrimitiveString = "123;456"
-
- var expectedStartingWithNumber = "111"
-
- // Check query params
- qParams := GetQueryFormParams{
- Ea: &expectedArray1,
- A: &expectedArray2,
- Eo: &expectedObject1,
- O: &expectedObject2,
- Ep: &expectedPrimitive1,
- P: &expectedPrimitive2,
- Ps: &expectedPrimitiveString,
- Co: &expectedComplexObject,
- N1s: &expectedStartingWithNumber,
- }
-
- req, err := NewGetQueryFormRequest(server, &qParams)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- require.NotNil(t, ts.queryParams)
- assert.EqualValues(t, qParams, *ts.queryParams)
- ts.reset()
-
- // Check cookie params
- cParams := GetCookieParams{
- Ea: &expectedArray1,
- A: &expectedArray2,
- Eo: &expectedObject1,
- O: &expectedObject2,
- Ep: &expectedPrimitive1,
- P: &expectedPrimitive2,
- Co: &expectedComplexObject,
- N1s: &expectedStartingWithNumber,
- }
- req, err = NewGetCookieRequest(server, &cParams)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- require.NotNil(t, ts.cookieParams)
- assert.EqualValues(t, cParams, *ts.cookieParams)
- ts.reset()
-
- // Check Header parameters
- hParams := GetHeaderParams{
- XArrayExploded: &expectedArray1,
- XArray: &expectedArray2,
- XObjectExploded: &expectedObject1,
- XObject: &expectedObject2,
- XPrimitiveExploded: &expectedPrimitive1,
- XPrimitive: &expectedPrimitive2,
- XComplexObject: &expectedComplexObject,
- N1StartingWithNumber: &expectedStartingWithNumber,
- }
- req, err = NewGetHeaderRequest(server, &hParams)
- assert.NoError(t, err)
- doRequest(t, e, http.StatusOK, req)
- require.NotNil(t, ts.headerParams)
- assert.EqualValues(t, hParams, *ts.headerParams)
- ts.reset()
-}
+// TestClientPathParams, TestClientQueryParams, and the doRequest helper have been
+// superseded by the multi-router TestParameterRoundTrip in param_roundtrip_test.go.
diff --git a/internal/test/parameters/echo/server.cfg.yaml b/internal/test/parameters/echo/server.cfg.yaml
new file mode 100644
index 0000000000..2e7156dae7
--- /dev/null
+++ b/internal/test/parameters/echo/server.cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: echoparamsgen
+generate:
+ echo-server: true
+ embedded-spec: true
+output: gen/server.gen.go
diff --git a/internal/test/parameters/echo/server.go b/internal/test/parameters/echo/server.go
new file mode 100644
index 0000000000..dd05c320cd
--- /dev/null
+++ b/internal/test/parameters/echo/server.go
@@ -0,0 +1,44 @@
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../parameters.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../parameters.yaml
+
+package echoparams
+
+import (
+ "net/http"
+
+ "github.com/labstack/echo/v4"
+
+ gen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/echo/gen"
+)
+
+type Server struct{}
+
+var _ gen.ServerInterface = (*Server)(nil)
+
+func (s *Server) GetContentObject(ctx echo.Context, param gen.ComplexObject) error { return ctx.JSON(http.StatusOK, param) }
+func (s *Server) GetCookie(ctx echo.Context, params gen.GetCookieParams) error { return ctx.JSON(http.StatusOK, params) }
+func (s *Server) EnumParams(ctx echo.Context, params gen.EnumParamsParams) error { return ctx.NoContent(http.StatusNoContent) }
+func (s *Server) GetHeader(ctx echo.Context, params gen.GetHeaderParams) error { return ctx.JSON(http.StatusOK, params) }
+func (s *Server) GetLabelExplodeArray(ctx echo.Context, param []int32) error { return ctx.JSON(http.StatusOK, param) }
+func (s *Server) GetLabelExplodeObject(ctx echo.Context, param gen.Object) error { return ctx.JSON(http.StatusOK, param) }
+func (s *Server) GetLabelExplodePrimitive(ctx echo.Context, param int32) error { return ctx.JSON(http.StatusOK, param) }
+func (s *Server) GetLabelNoExplodeArray(ctx echo.Context, param []int32) error { return ctx.JSON(http.StatusOK, param) }
+func (s *Server) GetLabelNoExplodeObject(ctx echo.Context, param gen.Object) error { return ctx.JSON(http.StatusOK, param) }
+func (s *Server) GetLabelPrimitive(ctx echo.Context, param int32) error { return ctx.JSON(http.StatusOK, param) }
+func (s *Server) GetMatrixExplodeArray(ctx echo.Context, id []int32) error { return ctx.JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixExplodeObject(ctx echo.Context, id gen.Object) error { return ctx.JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixExplodePrimitive(ctx echo.Context, id int32) error { return ctx.JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixNoExplodeArray(ctx echo.Context, id []int32) error { return ctx.JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixNoExplodeObject(ctx echo.Context, id gen.Object) error { return ctx.JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixPrimitive(ctx echo.Context, id int32) error { return ctx.JSON(http.StatusOK, id) }
+func (s *Server) GetPassThrough(ctx echo.Context, param string) error { return ctx.JSON(http.StatusOK, param) }
+func (s *Server) GetDeepObject(ctx echo.Context, params gen.GetDeepObjectParams) error { return ctx.JSON(http.StatusOK, params) }
+func (s *Server) GetQueryDelimited(ctx echo.Context, params gen.GetQueryDelimitedParams) error { return ctx.JSON(http.StatusOK, params) }
+func (s *Server) GetQueryForm(ctx echo.Context, params gen.GetQueryFormParams) error { return ctx.JSON(http.StatusOK, params) }
+func (s *Server) GetSimpleExplodeArray(ctx echo.Context, param []int32) error { return ctx.JSON(http.StatusOK, param) }
+func (s *Server) GetSimpleExplodeObject(ctx echo.Context, param gen.Object) error { return ctx.JSON(http.StatusOK, param) }
+func (s *Server) GetSimpleExplodePrimitive(ctx echo.Context, param int32) error { return ctx.JSON(http.StatusOK, param) }
+func (s *Server) GetSimpleNoExplodeArray(ctx echo.Context, param []int32) error { return ctx.JSON(http.StatusOK, param) }
+func (s *Server) GetSimpleNoExplodeObject(ctx echo.Context, param gen.Object) error { return ctx.JSON(http.StatusOK, param) }
+func (s *Server) GetSimplePrimitive(ctx echo.Context, param int32) error { return ctx.JSON(http.StatusOK, param) }
+func (s *Server) GetStartingWithNumber(ctx echo.Context, n1param string) error { return ctx.JSON(http.StatusOK, n1param) }
diff --git a/internal/test/parameters/echo/types.cfg.yaml b/internal/test/parameters/echo/types.cfg.yaml
new file mode 100644
index 0000000000..fce1d24f13
--- /dev/null
+++ b/internal/test/parameters/echo/types.cfg.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: echoparamsgen
+generate:
+ models: true
+output: gen/types.gen.go
diff --git a/internal/test/parameters/echov5/gen/server.gen.go b/internal/test/parameters/echov5/gen/server.gen.go
new file mode 100644
index 0000000000..30bebc6b46
--- /dev/null
+++ b/internal/test/parameters/echov5/gen/server.gen.go
@@ -0,0 +1,1017 @@
+// Package echov5paramsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package echov5paramsgen
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/labstack/echo/v5"
+ "github.com/oapi-codegen/runtime"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /contentObject/{param})
+ GetContentObject(ctx *echo.Context, param ComplexObject) error
+
+ // (GET /cookie)
+ GetCookie(ctx *echo.Context, params GetCookieParams) error
+
+ // (GET /enums)
+ EnumParams(ctx *echo.Context, params EnumParamsParams) error
+
+ // (GET /header)
+ GetHeader(ctx *echo.Context, params GetHeaderParams) error
+
+ // (GET /labelExplodeArray/{.param*})
+ GetLabelExplodeArray(ctx *echo.Context, param []int32) error
+
+ // (GET /labelExplodeObject/{.param*})
+ GetLabelExplodeObject(ctx *echo.Context, param Object) error
+
+ // (GET /labelExplodePrimitive/{.param*})
+ GetLabelExplodePrimitive(ctx *echo.Context, param int32) error
+
+ // (GET /labelNoExplodeArray/{.param})
+ GetLabelNoExplodeArray(ctx *echo.Context, param []int32) error
+
+ // (GET /labelNoExplodeObject/{.param})
+ GetLabelNoExplodeObject(ctx *echo.Context, param Object) error
+
+ // (GET /labelPrimitive/{.param})
+ GetLabelPrimitive(ctx *echo.Context, param int32) error
+
+ // (GET /matrixExplodeArray/{.id*})
+ GetMatrixExplodeArray(ctx *echo.Context, id []int32) error
+
+ // (GET /matrixExplodeObject/{.id*})
+ GetMatrixExplodeObject(ctx *echo.Context, id Object) error
+
+ // (GET /matrixExplodePrimitive/{;id*})
+ GetMatrixExplodePrimitive(ctx *echo.Context, id int32) error
+
+ // (GET /matrixNoExplodeArray/{.id})
+ GetMatrixNoExplodeArray(ctx *echo.Context, id []int32) error
+
+ // (GET /matrixNoExplodeObject/{.id})
+ GetMatrixNoExplodeObject(ctx *echo.Context, id Object) error
+
+ // (GET /matrixPrimitive/{;id})
+ GetMatrixPrimitive(ctx *echo.Context, id int32) error
+
+ // (GET /passThrough/{param})
+ GetPassThrough(ctx *echo.Context, param string) error
+
+ // (GET /queryDeepObject)
+ GetDeepObject(ctx *echo.Context, params GetDeepObjectParams) error
+
+ // (GET /queryDelimited)
+ GetQueryDelimited(ctx *echo.Context, params GetQueryDelimitedParams) error
+
+ // (GET /queryForm)
+ GetQueryForm(ctx *echo.Context, params GetQueryFormParams) error
+
+ // (GET /simpleExplodeArray/{param*})
+ GetSimpleExplodeArray(ctx *echo.Context, param []int32) error
+
+ // (GET /simpleExplodeObject/{param*})
+ GetSimpleExplodeObject(ctx *echo.Context, param Object) error
+
+ // (GET /simpleExplodePrimitive/{param})
+ GetSimpleExplodePrimitive(ctx *echo.Context, param int32) error
+
+ // (GET /simpleNoExplodeArray/{param})
+ GetSimpleNoExplodeArray(ctx *echo.Context, param []int32) error
+
+ // (GET /simpleNoExplodeObject/{param})
+ GetSimpleNoExplodeObject(ctx *echo.Context, param Object) error
+
+ // (GET /simplePrimitive/{param})
+ GetSimplePrimitive(ctx *echo.Context, param int32) error
+
+ // (GET /startingWithNumber/{1param})
+ GetStartingWithNumber(ctx *echo.Context, n1param string) error
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+// GetContentObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetContentObject(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param ComplexObject
+
+ err = json.Unmarshal([]byte(ctx.Param("param")), ¶m)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'param' as JSON")
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetContentObject(ctx, param)
+ return err
+}
+
+// GetCookie converts echo context to params.
+func (w *ServerInterfaceWrapper) GetCookie(ctx *echo.Context) error {
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetCookieParams
+
+ if cookie, err := ctx.Cookie("p"); err == nil {
+
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "p", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter p: %s", err))
+ }
+ params.P = &value
+
+ }
+
+ if cookie, err := ctx.Cookie("ep"); err == nil {
+
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ep", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ep: %s", err))
+ }
+ params.Ep = &value
+
+ }
+
+ if cookie, err := ctx.Cookie("ea"); err == nil {
+
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ea", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ea: %s", err))
+ }
+ params.Ea = &value
+
+ }
+
+ if cookie, err := ctx.Cookie("a"); err == nil {
+
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "a", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter a: %s", err))
+ }
+ params.A = &value
+
+ }
+
+ if cookie, err := ctx.Cookie("eo"); err == nil {
+
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "eo", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter eo: %s", err))
+ }
+ params.Eo = &value
+
+ }
+
+ if cookie, err := ctx.Cookie("o"); err == nil {
+
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "o", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter o: %s", err))
+ }
+ params.O = &value
+
+ }
+
+ if cookie, err := ctx.Cookie("co"); err == nil {
+
+ var value ComplexObject
+ var decoded string
+ decoded, err := url.QueryUnescape(cookie.Value)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unescaping cookie parameter 'co'")
+ }
+ err = json.Unmarshal([]byte(decoded), &value)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'co' as JSON")
+ }
+ params.Co = &value
+
+ }
+
+ if cookie, err := ctx.Cookie("1s"); err == nil {
+
+ var value string
+ err = runtime.BindStyledParameterWithOptions("simple", "1s", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1s: %s", err))
+ }
+ params.N1s = &value
+
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetCookie(ctx, params)
+ return err
+}
+
+// EnumParams converts echo context to params.
+func (w *ServerInterfaceWrapper) EnumParams(ctx *echo.Context) error {
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params EnumParamsParams
+ // ------------- Optional query parameter "enumPathParam" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "enumPathParam", ctx.QueryParams(), ¶ms.EnumPathParam, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter enumPathParam: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.EnumParams(ctx, params)
+ return err
+}
+
+// GetHeader converts echo context to params.
+func (w *ServerInterfaceWrapper) GetHeader(ctx *echo.Context) error {
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetHeaderParams
+
+ headers := ctx.Request().Header
+ // ------------- Optional header parameter "X-Primitive" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive")]; found {
+ var XPrimitive int32
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Primitive, got %d", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive", valueList[0], &XPrimitive, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Primitive: %s", err))
+ }
+
+ params.XPrimitive = &XPrimitive
+ }
+ // ------------- Optional header parameter "X-Primitive-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive-Exploded")]; found {
+ var XPrimitiveExploded int32
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Primitive-Exploded, got %d", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive-Exploded", valueList[0], &XPrimitiveExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Primitive-Exploded: %s", err))
+ }
+
+ params.XPrimitiveExploded = &XPrimitiveExploded
+ }
+ // ------------- Optional header parameter "X-Array-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array-Exploded")]; found {
+ var XArrayExploded []int32
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Array-Exploded, got %d", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array-Exploded", valueList[0], &XArrayExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Array-Exploded: %s", err))
+ }
+
+ params.XArrayExploded = &XArrayExploded
+ }
+ // ------------- Optional header parameter "X-Array" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array")]; found {
+ var XArray []int32
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Array, got %d", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array", valueList[0], &XArray, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Array: %s", err))
+ }
+
+ params.XArray = &XArray
+ }
+ // ------------- Optional header parameter "X-Object-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object-Exploded")]; found {
+ var XObjectExploded Object
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Object-Exploded, got %d", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object-Exploded", valueList[0], &XObjectExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Object-Exploded: %s", err))
+ }
+
+ params.XObjectExploded = &XObjectExploded
+ }
+ // ------------- Optional header parameter "X-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object")]; found {
+ var XObject Object
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Object, got %d", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object", valueList[0], &XObject, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter X-Object: %s", err))
+ }
+
+ params.XObject = &XObject
+ }
+ // ------------- Optional header parameter "X-Complex-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Complex-Object")]; found {
+ var XComplexObject ComplexObject
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for X-Complex-Object, got %d", n))
+ }
+
+ err = json.Unmarshal([]byte(valueList[0]), &XComplexObject)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'X-Complex-Object' as JSON")
+ }
+
+ params.XComplexObject = &XComplexObject
+ }
+ // ------------- Optional header parameter "1-Starting-With-Number" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("1-Starting-With-Number")]; found {
+ var N1StartingWithNumber string
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for 1-Starting-With-Number, got %d", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "1-Starting-With-Number", valueList[0], &N1StartingWithNumber, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1-Starting-With-Number: %s", err))
+ }
+
+ params.N1StartingWithNumber = &N1StartingWithNumber
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetHeader(ctx, params)
+ return err
+}
+
+// GetLabelExplodeArray converts echo context to params.
+func (w *ServerInterfaceWrapper) GetLabelExplodeArray(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetLabelExplodeArray(ctx, param)
+ return err
+}
+
+// GetLabelExplodeObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetLabelExplodeObject(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetLabelExplodeObject(ctx, param)
+ return err
+}
+
+// GetLabelExplodePrimitive converts echo context to params.
+func (w *ServerInterfaceWrapper) GetLabelExplodePrimitive(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetLabelExplodePrimitive(ctx, param)
+ return err
+}
+
+// GetLabelNoExplodeArray converts echo context to params.
+func (w *ServerInterfaceWrapper) GetLabelNoExplodeArray(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetLabelNoExplodeArray(ctx, param)
+ return err
+}
+
+// GetLabelNoExplodeObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetLabelNoExplodeObject(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetLabelNoExplodeObject(ctx, param)
+ return err
+}
+
+// GetLabelPrimitive converts echo context to params.
+func (w *ServerInterfaceWrapper) GetLabelPrimitive(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetLabelPrimitive(ctx, param)
+ return err
+}
+
+// GetMatrixExplodeArray converts echo context to params.
+func (w *ServerInterfaceWrapper) GetMatrixExplodeArray(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetMatrixExplodeArray(ctx, id)
+ return err
+}
+
+// GetMatrixExplodeObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetMatrixExplodeObject(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetMatrixExplodeObject(ctx, id)
+ return err
+}
+
+// GetMatrixExplodePrimitive converts echo context to params.
+func (w *ServerInterfaceWrapper) GetMatrixExplodePrimitive(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetMatrixExplodePrimitive(ctx, id)
+ return err
+}
+
+// GetMatrixNoExplodeArray converts echo context to params.
+func (w *ServerInterfaceWrapper) GetMatrixNoExplodeArray(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetMatrixNoExplodeArray(ctx, id)
+ return err
+}
+
+// GetMatrixNoExplodeObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetMatrixNoExplodeObject(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetMatrixNoExplodeObject(ctx, id)
+ return err
+}
+
+// GetMatrixPrimitive converts echo context to params.
+func (w *ServerInterfaceWrapper) GetMatrixPrimitive(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter id: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetMatrixPrimitive(ctx, id)
+ return err
+}
+
+// GetPassThrough converts echo context to params.
+func (w *ServerInterfaceWrapper) GetPassThrough(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param string
+
+ param = ctx.Param("param")
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetPassThrough(ctx, param)
+ return err
+}
+
+// GetDeepObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetDeepObject(ctx *echo.Context) error {
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetDeepObjectParams
+ // ------------- Required query parameter "deepObj" -------------
+
+ err = runtime.BindQueryParameterWithOptions("deepObject", true, true, "deepObj", ctx.QueryParams(), ¶ms.DeepObj, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter deepObj: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetDeepObject(ctx, params)
+ return err
+}
+
+// GetQueryDelimited converts echo context to params.
+func (w *ServerInterfaceWrapper) GetQueryDelimited(ctx *echo.Context) error {
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryDelimitedParams
+ // ------------- Optional query parameter "sa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("spaceDelimited", false, false, "sa", ctx.QueryParams(), ¶ms.Sa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter sa: %s", err))
+ }
+
+ // ------------- Optional query parameter "pa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("pipeDelimited", false, false, "pa", ctx.QueryParams(), ¶ms.Pa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter pa: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetQueryDelimited(ctx, params)
+ return err
+}
+
+// GetQueryForm converts echo context to params.
+func (w *ServerInterfaceWrapper) GetQueryForm(ctx *echo.Context) error {
+ var err error
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryFormParams
+ // ------------- Optional query parameter "ea" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ea", ctx.QueryParams(), ¶ms.Ea, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ea: %s", err))
+ }
+
+ // ------------- Optional query parameter "a" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "a", ctx.QueryParams(), ¶ms.A, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter a: %s", err))
+ }
+
+ // ------------- Optional query parameter "eo" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "eo", ctx.QueryParams(), ¶ms.Eo, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter eo: %s", err))
+ }
+
+ // ------------- Optional query parameter "o" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "o", ctx.QueryParams(), ¶ms.O, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter o: %s", err))
+ }
+
+ // ------------- Optional query parameter "ep" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ep", ctx.QueryParams(), ¶ms.Ep, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ep: %s", err))
+ }
+
+ // ------------- Optional query parameter "p" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "p", ctx.QueryParams(), ¶ms.P, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter p: %s", err))
+ }
+
+ // ------------- Optional query parameter "ps" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ps", ctx.QueryParams(), ¶ms.Ps, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter ps: %s", err))
+ }
+
+ // ------------- Optional query parameter "co" -------------
+
+ if paramValue := ctx.QueryParam("co"); paramValue != "" {
+
+ var value ComplexObject
+ err = json.Unmarshal([]byte(paramValue), &value)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter 'co' as JSON")
+ }
+ params.Co = &value
+
+ }
+
+ // ------------- Optional query parameter "1s" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "1s", ctx.QueryParams(), ¶ms.N1s, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1s: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetQueryForm(ctx, params)
+ return err
+}
+
+// GetSimpleExplodeArray converts echo context to params.
+func (w *ServerInterfaceWrapper) GetSimpleExplodeArray(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetSimpleExplodeArray(ctx, param)
+ return err
+}
+
+// GetSimpleExplodeObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetSimpleExplodeObject(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetSimpleExplodeObject(ctx, param)
+ return err
+}
+
+// GetSimpleExplodePrimitive converts echo context to params.
+func (w *ServerInterfaceWrapper) GetSimpleExplodePrimitive(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetSimpleExplodePrimitive(ctx, param)
+ return err
+}
+
+// GetSimpleNoExplodeArray converts echo context to params.
+func (w *ServerInterfaceWrapper) GetSimpleNoExplodeArray(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetSimpleNoExplodeArray(ctx, param)
+ return err
+}
+
+// GetSimpleNoExplodeObject converts echo context to params.
+func (w *ServerInterfaceWrapper) GetSimpleNoExplodeObject(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetSimpleNoExplodeObject(ctx, param)
+ return err
+}
+
+// GetSimplePrimitive converts echo context to params.
+func (w *ServerInterfaceWrapper) GetSimplePrimitive(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter param: %s", err))
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetSimplePrimitive(ctx, param)
+ return err
+}
+
+// GetStartingWithNumber converts echo context to params.
+func (w *ServerInterfaceWrapper) GetStartingWithNumber(ctx *echo.Context) error {
+ var err error
+ // ------------- Path parameter "1param" -------------
+ var n1param string
+
+ n1param = ctx.Param("1param")
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.GetStartingWithNumber(ctx, n1param)
+ return err
+}
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+}
+
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
+}
+
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.GET(options.BaseURL+"/contentObject/:param", wrapper.GetContentObject, options.OperationMiddlewares["getContentObject"]...)
+ router.GET(options.BaseURL+"/cookie", wrapper.GetCookie, options.OperationMiddlewares["getCookie"]...)
+ router.GET(options.BaseURL+"/enums", wrapper.EnumParams, options.OperationMiddlewares["enumParams"]...)
+ router.GET(options.BaseURL+"/header", wrapper.GetHeader, options.OperationMiddlewares["getHeader"]...)
+ router.GET(options.BaseURL+"/labelExplodeArray/:param", wrapper.GetLabelExplodeArray, options.OperationMiddlewares["getLabelExplodeArray"]...)
+ router.GET(options.BaseURL+"/labelExplodeObject/:param", wrapper.GetLabelExplodeObject, options.OperationMiddlewares["getLabelExplodeObject"]...)
+ router.GET(options.BaseURL+"/labelExplodePrimitive/:param", wrapper.GetLabelExplodePrimitive, options.OperationMiddlewares["getLabelExplodePrimitive"]...)
+ router.GET(options.BaseURL+"/labelNoExplodeArray/:param", wrapper.GetLabelNoExplodeArray, options.OperationMiddlewares["getLabelNoExplodeArray"]...)
+ router.GET(options.BaseURL+"/labelNoExplodeObject/:param", wrapper.GetLabelNoExplodeObject, options.OperationMiddlewares["getLabelNoExplodeObject"]...)
+ router.GET(options.BaseURL+"/labelPrimitive/:param", wrapper.GetLabelPrimitive, options.OperationMiddlewares["getLabelPrimitive"]...)
+ router.GET(options.BaseURL+"/matrixExplodeArray/:id", wrapper.GetMatrixExplodeArray, options.OperationMiddlewares["getMatrixExplodeArray"]...)
+ router.GET(options.BaseURL+"/matrixExplodeObject/:id", wrapper.GetMatrixExplodeObject, options.OperationMiddlewares["getMatrixExplodeObject"]...)
+ router.GET(options.BaseURL+"/matrixExplodePrimitive/:id", wrapper.GetMatrixExplodePrimitive, options.OperationMiddlewares["getMatrixExplodePrimitive"]...)
+ router.GET(options.BaseURL+"/matrixNoExplodeArray/:id", wrapper.GetMatrixNoExplodeArray, options.OperationMiddlewares["getMatrixNoExplodeArray"]...)
+ router.GET(options.BaseURL+"/matrixNoExplodeObject/:id", wrapper.GetMatrixNoExplodeObject, options.OperationMiddlewares["getMatrixNoExplodeObject"]...)
+ router.GET(options.BaseURL+"/matrixPrimitive/:id", wrapper.GetMatrixPrimitive, options.OperationMiddlewares["getMatrixPrimitive"]...)
+ router.GET(options.BaseURL+"/passThrough/:param", wrapper.GetPassThrough, options.OperationMiddlewares["getPassThrough"]...)
+ router.GET(options.BaseURL+"/queryDeepObject", wrapper.GetDeepObject, options.OperationMiddlewares["getDeepObject"]...)
+ router.GET(options.BaseURL+"/queryDelimited", wrapper.GetQueryDelimited, options.OperationMiddlewares["getQueryDelimited"]...)
+ router.GET(options.BaseURL+"/queryForm", wrapper.GetQueryForm, options.OperationMiddlewares["getQueryForm"]...)
+ router.GET(options.BaseURL+"/simpleExplodeArray/:param", wrapper.GetSimpleExplodeArray, options.OperationMiddlewares["getSimpleExplodeArray"]...)
+ router.GET(options.BaseURL+"/simpleExplodeObject/:param", wrapper.GetSimpleExplodeObject, options.OperationMiddlewares["getSimpleExplodeObject"]...)
+ router.GET(options.BaseURL+"/simpleExplodePrimitive/:param", wrapper.GetSimpleExplodePrimitive, options.OperationMiddlewares["getSimpleExplodePrimitive"]...)
+ router.GET(options.BaseURL+"/simpleNoExplodeArray/:param", wrapper.GetSimpleNoExplodeArray, options.OperationMiddlewares["getSimpleNoExplodeArray"]...)
+ router.GET(options.BaseURL+"/simpleNoExplodeObject/:param", wrapper.GetSimpleNoExplodeObject, options.OperationMiddlewares["getSimpleNoExplodeObject"]...)
+ router.GET(options.BaseURL+"/simplePrimitive/:param", wrapper.GetSimplePrimitive, options.OperationMiddlewares["getSimplePrimitive"]...)
+ router.GET(options.BaseURL+"/startingWithNumber/:1param", wrapper.GetStartingWithNumber, options.OperationMiddlewares["getStartingWithNumber"]...)
+
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "3FpLb+M2F/0rwv2+VaFYdqYrdRVMp22ATiatA0yBIAtGuo44lUQOSacJDP33gpRkPa2HLeXRXWJd3sch",
+ "z6F4qR14LOIsxlhJcHcgUHIWSzT/rGnEQ/wz+0n/4rFYYaz0nwqflMNDQmP9n/QCjIj5/ZkjuCCVoPED",
+ "JElig4/SE5QrymJw4cKSxq+Vx7LY/Tf0FGjT1I+J/pFpq6cv6UN3B1wwjkLRNLlLvxSNxgofUEBiw6W8",
+ "8KM0qezhPWMhklg/LJz9X+AGXPifU9TvZMGdL0U+Ar9vqUAf3Nt8sK1DF3HuKm6rOW6okOqKRNgCjA2C",
+ "hW0PalGNlV1ydWcwpfGG6cEh9TCbnNgEgs+XN9q7okq7hxuUylqjeEQBNjyikOk0rBbLxVIbMo4x4RRc",
+ "+LBYLlZgAycqMPk72Xyn9Tk7TgSJEv3kAU25ulii51XPBvyK6mN5gHElSIQKhQT3trJ+COch9cxg55tk",
+ "tVXUNT3VhZGhAa5JG+wcBhMZylgqscXkzq6u8fPl8lC8vZ1TI0JiYjoeY39T7EbDWDRgqBKCCxpRRR+1",
+ "IT7xkPkI7oaEErPCvNxNXhrYJag2TEREpST4cA52gxOJPSiihudAQDw5YhbFt4gQ5HloWFIJSxVGclD8",
+ "/S9ptJZ8Gml04T1fGntYWE6YQbiwSkLDpKweuhmxC4LjIs5F92olXmpQYNhagcegCYJ+ZklFhKLxg/UP",
+ "VYEVb6N7I5WtXlayAkRduuvq4uOGbEN1rMJgvE2XWqvAfIq30bUWFtmnMNf5w7RE7dZ6JOEWZV7n9y2K",
+ "59IKM65VcJ2JaFGxfgLu7Wq5tM+Xyzt7gBg0JffHFJvKTDArXy1Z8QESH0WXvP6WWpwqr0HuJiv+r7Pr",
+ "0pBZhbYj9NmnTBteRHqbiVxo6/YkXkyID2T1ynLczCrVpnaw5lDnQxm8O5FuFpI5ygs6QrLrPldn68z6",
+ "7CtVwdlVbv1iMh6SewyzxWEWsLNbGMn6ofNd+vf6sKbStS3PIa/B0xDIBqmezSHDVAhTvlyXMcuPH2NB",
+ "O3QKmQK1Iex6KXz2e8Z4iMo73QwoDVhSM0N0xdqI149PdVwHOmVd/g9Rb19/lXwjgOtl3ynIvQn6NXjX",
+ "j84Qvp2Cy6sSLiJK0Kca36jfrUafG4OOkSLqz060tLr5ANsTbRRix+9xPZCNY9jc4JSo9tMofE7a4Hog",
+ "GkG22fBp7G/UHwDOBLvbe2Zcc3Mbh9oJW9v7YF2VbgOgOW1fe9M840TKm0Cw7UMw5AbkujDvvP8YcX/2",
+ "KrcbpiP4MyIvLrcOlVyy6unF+Yi8u7lSa0T6qeujOVPrSxQLxS9ynvq4nyEXakag3wXcH1XLHvAkJx5a",
+ "fm5udbbOajjKqe4wCgRNOkXyLc1Pyo9Nl0+frs6mlO3UTPmFiah3qo1RzywPatfW2/XTw6WHwsh2bS2r",
+ "F0tqWNu2jtn8l2i1iFME3Jfad7NQr3aeO+MuCk8W0Mr2wgNxum/kXrnBXUv2uEvImpORd5AnKFv6oU71",
+ "gDGgwbhuDHu7neu0RJgNtcqnMyNgezu967kRKp01+t+u160jX715PRtG9eP9UITeTft6fuSGf7y2bhv4",
+ "JhrYs6F0BPk6WPceaZbtu1+pCtKbYWe3GgBFY9iMh/3VzKd9jbD5QDTNeytCcCFQiruOk30dqlCqhT4z",
+ "R4QvCIXkLvk3AAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/parameters/echov5/gen/types.gen.go b/internal/test/parameters/echov5/gen/types.gen.go
new file mode 100644
index 0000000000..f9ac88c94a
--- /dev/null
+++ b/internal/test/parameters/echov5/gen/types.gen.go
@@ -0,0 +1,143 @@
+// Package echov5paramsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package echov5paramsgen
+
+// Defines values for EnumParamsParamsEnumPathParam.
+const (
+ N100 EnumParamsParamsEnumPathParam = 100
+ N200 EnumParamsParamsEnumPathParam = 200
+)
+
+// Valid indicates whether the value is a known member of the EnumParamsParamsEnumPathParam enum.
+func (e EnumParamsParamsEnumPathParam) Valid() bool {
+ switch e {
+ case N100:
+ return true
+ case N200:
+ return true
+ default:
+ return false
+ }
+}
+
+// ComplexObject defines model for ComplexObject.
+type ComplexObject struct {
+ Id int `json:"Id"`
+ IsAdmin bool `json:"IsAdmin"`
+ Object Object `json:"Object"`
+}
+
+// Object defines model for Object.
+type Object struct {
+ FirstName string `json:"firstName"`
+ Role string `json:"role"`
+}
+
+// GetCookieParams defines parameters for GetCookie.
+type GetCookieParams struct {
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ep primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
+
+// EnumParamsParams defines parameters for EnumParams.
+type EnumParamsParams struct {
+ // EnumPathParam Parameter with enum values
+ EnumPathParam *EnumParamsParamsEnumPathParam `form:"enumPathParam,omitempty" json:"enumPathParam,omitempty"`
+}
+
+// EnumParamsParamsEnumPathParam defines parameters for EnumParams.
+type EnumParamsParamsEnumPathParam int32
+
+// GetHeaderParams defines parameters for GetHeader.
+type GetHeaderParams struct {
+ // XPrimitive primitive
+ XPrimitive *int32 `json:"X-Primitive,omitempty"`
+
+ // XPrimitiveExploded primitive
+ XPrimitiveExploded *int32 `json:"X-Primitive-Exploded,omitempty"`
+
+ // XArrayExploded exploded array
+ XArrayExploded *[]int32 `json:"X-Array-Exploded,omitempty"`
+
+ // XArray array
+ XArray *[]int32 `json:"X-Array,omitempty"`
+
+ // XObjectExploded exploded object
+ XObjectExploded *Object `json:"X-Object-Exploded,omitempty"`
+
+ // XObject object
+ XObject *Object `json:"X-Object,omitempty"`
+
+ // XComplexObject complex object
+ XComplexObject *ComplexObject `json:"X-Complex-Object,omitempty"`
+
+ // N1StartingWithNumber name starting with number
+ N1StartingWithNumber *string `json:"1-Starting-With-Number,omitempty"`
+}
+
+// GetDeepObjectParams defines parameters for GetDeepObject.
+type GetDeepObjectParams struct {
+ // DeepObj deep object
+ DeepObj ComplexObject `json:"deepObj"`
+}
+
+// GetQueryDelimitedParams defines parameters for GetQueryDelimited.
+type GetQueryDelimitedParams struct {
+ // Sa space delimited array
+ Sa *[]int32 `json:"sa,omitempty"`
+
+ // Pa pipe delimited array
+ Pa *[]int32 `json:"pa,omitempty"`
+}
+
+// GetQueryFormParams defines parameters for GetQueryForm.
+type GetQueryFormParams struct {
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Ep exploded primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ps primitive string
+ Ps *string `form:"ps,omitempty" json:"ps,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
diff --git a/internal/test/parameters/echov5/server.cfg.yaml b/internal/test/parameters/echov5/server.cfg.yaml
new file mode 100644
index 0000000000..6df3ac93c1
--- /dev/null
+++ b/internal/test/parameters/echov5/server.cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: echov5paramsgen
+generate:
+ echo5-server: true
+ embedded-spec: true
+output: gen/server.gen.go
diff --git a/internal/test/parameters/echov5/server.go b/internal/test/parameters/echov5/server.go
new file mode 100644
index 0000000000..c14531f150
--- /dev/null
+++ b/internal/test/parameters/echov5/server.go
@@ -0,0 +1,44 @@
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../parameters.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../parameters.yaml
+
+package echov5params
+
+import (
+ "net/http"
+
+ "github.com/labstack/echo/v5"
+
+ gen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/echov5/gen"
+)
+
+type Server struct{}
+
+var _ gen.ServerInterface = (*Server)(nil)
+
+func (s *Server) GetContentObject(ctx *echo.Context, param gen.ComplexObject) error { return (*ctx).JSON(http.StatusOK, param) }
+func (s *Server) GetCookie(ctx *echo.Context, params gen.GetCookieParams) error { return (*ctx).JSON(http.StatusOK, params) }
+func (s *Server) EnumParams(ctx *echo.Context, params gen.EnumParamsParams) error { return (*ctx).NoContent(http.StatusNoContent) }
+func (s *Server) GetHeader(ctx *echo.Context, params gen.GetHeaderParams) error { return (*ctx).JSON(http.StatusOK, params) }
+func (s *Server) GetLabelExplodeArray(ctx *echo.Context, param []int32) error { return (*ctx).JSON(http.StatusOK, param) }
+func (s *Server) GetLabelExplodeObject(ctx *echo.Context, param gen.Object) error { return (*ctx).JSON(http.StatusOK, param) }
+func (s *Server) GetLabelExplodePrimitive(ctx *echo.Context, param int32) error { return (*ctx).JSON(http.StatusOK, param) }
+func (s *Server) GetLabelNoExplodeArray(ctx *echo.Context, param []int32) error { return (*ctx).JSON(http.StatusOK, param) }
+func (s *Server) GetLabelNoExplodeObject(ctx *echo.Context, param gen.Object) error { return (*ctx).JSON(http.StatusOK, param) }
+func (s *Server) GetLabelPrimitive(ctx *echo.Context, param int32) error { return (*ctx).JSON(http.StatusOK, param) }
+func (s *Server) GetMatrixExplodeArray(ctx *echo.Context, id []int32) error { return (*ctx).JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixExplodeObject(ctx *echo.Context, id gen.Object) error { return (*ctx).JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixExplodePrimitive(ctx *echo.Context, id int32) error { return (*ctx).JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixNoExplodeArray(ctx *echo.Context, id []int32) error { return (*ctx).JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixNoExplodeObject(ctx *echo.Context, id gen.Object) error { return (*ctx).JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixPrimitive(ctx *echo.Context, id int32) error { return (*ctx).JSON(http.StatusOK, id) }
+func (s *Server) GetPassThrough(ctx *echo.Context, param string) error { return (*ctx).JSON(http.StatusOK, param) }
+func (s *Server) GetDeepObject(ctx *echo.Context, params gen.GetDeepObjectParams) error { return (*ctx).JSON(http.StatusOK, params) }
+func (s *Server) GetQueryDelimited(ctx *echo.Context, params gen.GetQueryDelimitedParams) error { return (*ctx).JSON(http.StatusOK, params) }
+func (s *Server) GetQueryForm(ctx *echo.Context, params gen.GetQueryFormParams) error { return (*ctx).JSON(http.StatusOK, params) }
+func (s *Server) GetSimpleExplodeArray(ctx *echo.Context, param []int32) error { return (*ctx).JSON(http.StatusOK, param) }
+func (s *Server) GetSimpleExplodeObject(ctx *echo.Context, param gen.Object) error { return (*ctx).JSON(http.StatusOK, param) }
+func (s *Server) GetSimpleExplodePrimitive(ctx *echo.Context, param int32) error { return (*ctx).JSON(http.StatusOK, param) }
+func (s *Server) GetSimpleNoExplodeArray(ctx *echo.Context, param []int32) error { return (*ctx).JSON(http.StatusOK, param) }
+func (s *Server) GetSimpleNoExplodeObject(ctx *echo.Context, param gen.Object) error { return (*ctx).JSON(http.StatusOK, param) }
+func (s *Server) GetSimplePrimitive(ctx *echo.Context, param int32) error { return (*ctx).JSON(http.StatusOK, param) }
+func (s *Server) GetStartingWithNumber(ctx *echo.Context, n1param string) error { return (*ctx).JSON(http.StatusOK, n1param) }
diff --git a/internal/test/parameters/echov5/types.cfg.yaml b/internal/test/parameters/echov5/types.cfg.yaml
new file mode 100644
index 0000000000..97fafeae65
--- /dev/null
+++ b/internal/test/parameters/echov5/types.cfg.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: echov5paramsgen
+generate:
+ models: true
+output: gen/types.gen.go
diff --git a/internal/test/parameters/fiber/gen/server.gen.go b/internal/test/parameters/fiber/gen/server.gen.go
new file mode 100644
index 0000000000..0557bc8fab
--- /dev/null
+++ b/internal/test/parameters/fiber/gen/server.gen.go
@@ -0,0 +1,1451 @@
+// Package fiberparamsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package fiberparamsgen
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gofiber/fiber/v2"
+ "github.com/oapi-codegen/runtime"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /contentObject/{param})
+ GetContentObject(c *fiber.Ctx, param ComplexObject) error
+
+ // (GET /cookie)
+ GetCookie(c *fiber.Ctx, params GetCookieParams) error
+
+ // (GET /enums)
+ EnumParams(c *fiber.Ctx, params EnumParamsParams) error
+
+ // (GET /header)
+ GetHeader(c *fiber.Ctx, params GetHeaderParams) error
+
+ // (GET /labelExplodeArray/{.param*})
+ GetLabelExplodeArray(c *fiber.Ctx, param []int32) error
+
+ // (GET /labelExplodeObject/{.param*})
+ GetLabelExplodeObject(c *fiber.Ctx, param Object) error
+
+ // (GET /labelExplodePrimitive/{.param*})
+ GetLabelExplodePrimitive(c *fiber.Ctx, param int32) error
+
+ // (GET /labelNoExplodeArray/{.param})
+ GetLabelNoExplodeArray(c *fiber.Ctx, param []int32) error
+
+ // (GET /labelNoExplodeObject/{.param})
+ GetLabelNoExplodeObject(c *fiber.Ctx, param Object) error
+
+ // (GET /labelPrimitive/{.param})
+ GetLabelPrimitive(c *fiber.Ctx, param int32) error
+
+ // (GET /matrixExplodeArray/{.id*})
+ GetMatrixExplodeArray(c *fiber.Ctx, id []int32) error
+
+ // (GET /matrixExplodeObject/{.id*})
+ GetMatrixExplodeObject(c *fiber.Ctx, id Object) error
+
+ // (GET /matrixExplodePrimitive/{;id*})
+ GetMatrixExplodePrimitive(c *fiber.Ctx, id int32) error
+
+ // (GET /matrixNoExplodeArray/{.id})
+ GetMatrixNoExplodeArray(c *fiber.Ctx, id []int32) error
+
+ // (GET /matrixNoExplodeObject/{.id})
+ GetMatrixNoExplodeObject(c *fiber.Ctx, id Object) error
+
+ // (GET /matrixPrimitive/{;id})
+ GetMatrixPrimitive(c *fiber.Ctx, id int32) error
+
+ // (GET /passThrough/{param})
+ GetPassThrough(c *fiber.Ctx, param string) error
+
+ // (GET /queryDeepObject)
+ GetDeepObject(c *fiber.Ctx, params GetDeepObjectParams) error
+
+ // (GET /queryDelimited)
+ GetQueryDelimited(c *fiber.Ctx, params GetQueryDelimitedParams) error
+
+ // (GET /queryForm)
+ GetQueryForm(c *fiber.Ctx, params GetQueryFormParams) error
+
+ // (GET /simpleExplodeArray/{param*})
+ GetSimpleExplodeArray(c *fiber.Ctx, param []int32) error
+
+ // (GET /simpleExplodeObject/{param*})
+ GetSimpleExplodeObject(c *fiber.Ctx, param Object) error
+
+ // (GET /simpleExplodePrimitive/{param})
+ GetSimpleExplodePrimitive(c *fiber.Ctx, param int32) error
+
+ // (GET /simpleNoExplodeArray/{param})
+ GetSimpleNoExplodeArray(c *fiber.Ctx, param []int32) error
+
+ // (GET /simpleNoExplodeObject/{param})
+ GetSimpleNoExplodeObject(c *fiber.Ctx, param Object) error
+
+ // (GET /simplePrimitive/{param})
+ GetSimplePrimitive(c *fiber.Ctx, param int32) error
+
+ // (GET /startingWithNumber/{1param})
+ GetStartingWithNumber(c *fiber.Ctx, n1param string) error
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []HandlerMiddlewareFunc
+}
+
+type MiddlewareFunc fiber.Handler
+type HandlerMiddlewareFunc func(c *fiber.Ctx, next fiber.Handler) error
+
+// GetContentObject operation middleware
+func (siw *ServerInterfaceWrapper) GetContentObject(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param ComplexObject
+
+ {
+ paramValue, decErr := url.PathUnescape(c.Params("param"))
+ if decErr != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unescaping path parameter 'param': %w", decErr).Error())
+ }
+ err = json.Unmarshal([]byte(paramValue), ¶m)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshaling parameter 'param' as JSON: %w", err).Error())
+ }
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetContentObject(c, param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetCookie operation middleware
+func (siw *ServerInterfaceWrapper) GetCookie(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetCookieParams
+
+ {
+ cookie := c.Cookies("p")
+
+ if cookie != "" {
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "p", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter p: %w", err).Error())
+ }
+ params.P = &value
+
+ }
+ }
+
+ {
+ cookie := c.Cookies("ep")
+
+ if cookie != "" {
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ep", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter ep: %w", err).Error())
+ }
+ params.Ep = &value
+
+ }
+ }
+
+ {
+ cookie := c.Cookies("ea")
+
+ if cookie != "" {
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ea", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter ea: %w", err).Error())
+ }
+ params.Ea = &value
+
+ }
+ }
+
+ {
+ cookie := c.Cookies("a")
+
+ if cookie != "" {
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "a", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter a: %w", err).Error())
+ }
+ params.A = &value
+
+ }
+ }
+
+ {
+ cookie := c.Cookies("eo")
+
+ if cookie != "" {
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "eo", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter eo: %w", err).Error())
+ }
+ params.Eo = &value
+
+ }
+ }
+
+ {
+ cookie := c.Cookies("o")
+
+ if cookie != "" {
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "o", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter o: %w", err).Error())
+ }
+ params.O = &value
+
+ }
+ }
+
+ {
+ cookie := c.Cookies("co")
+
+ if cookie != "" {
+ var value ComplexObject
+ var decoded string
+ decoded, err := url.QueryUnescape(cookie)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unescaping cookie parameter 'co': %w", err).Error())
+ }
+
+ err = json.Unmarshal([]byte(decoded), &value)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshaling parameter 'co' as JSON: %w", err).Error())
+ }
+
+ params.Co = &value
+
+ }
+ }
+
+ {
+ cookie := c.Cookies("1s")
+
+ if cookie != "" {
+ var value string
+ err = runtime.BindStyledParameterWithOptions("simple", "1s", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter 1s: %w", err).Error())
+ }
+ params.N1s = &value
+
+ }
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetCookie(c, params)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// EnumParams operation middleware
+func (siw *ServerInterfaceWrapper) EnumParams(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params EnumParamsParams
+
+ var query url.Values
+ query, err = url.ParseQuery(string(c.Request().URI().QueryString()))
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for query string: %w", err).Error())
+ }
+
+ // ------------- Optional query parameter "enumPathParam" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "enumPathParam", query, ¶ms.EnumPathParam, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter enumPathParam: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.EnumParams(c, params)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetHeader operation middleware
+func (siw *ServerInterfaceWrapper) GetHeader(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetHeaderParams
+
+ headers := c.GetReqHeaders()
+
+ // ------------- Optional header parameter "X-Primitive" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive")]; found {
+ var XPrimitive int32
+ n := len(valueList)
+ if n != 1 {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Too many values for ParamName X-Primitive, 1 is required, but %d found", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive", valueList[0], &XPrimitive, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter X-Primitive: %w", err).Error())
+ }
+
+ params.XPrimitive = &XPrimitive
+
+ }
+
+ // ------------- Optional header parameter "X-Primitive-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive-Exploded")]; found {
+ var XPrimitiveExploded int32
+ n := len(valueList)
+ if n != 1 {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Too many values for ParamName X-Primitive-Exploded, 1 is required, but %d found", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive-Exploded", valueList[0], &XPrimitiveExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter X-Primitive-Exploded: %w", err).Error())
+ }
+
+ params.XPrimitiveExploded = &XPrimitiveExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Array-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array-Exploded")]; found {
+ var XArrayExploded []int32
+ n := len(valueList)
+ if n != 1 {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Too many values for ParamName X-Array-Exploded, 1 is required, but %d found", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array-Exploded", valueList[0], &XArrayExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter X-Array-Exploded: %w", err).Error())
+ }
+
+ params.XArrayExploded = &XArrayExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Array" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array")]; found {
+ var XArray []int32
+ n := len(valueList)
+ if n != 1 {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Too many values for ParamName X-Array, 1 is required, but %d found", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array", valueList[0], &XArray, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter X-Array: %w", err).Error())
+ }
+
+ params.XArray = &XArray
+
+ }
+
+ // ------------- Optional header parameter "X-Object-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object-Exploded")]; found {
+ var XObjectExploded Object
+ n := len(valueList)
+ if n != 1 {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Too many values for ParamName X-Object-Exploded, 1 is required, but %d found", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object-Exploded", valueList[0], &XObjectExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter X-Object-Exploded: %w", err).Error())
+ }
+
+ params.XObjectExploded = &XObjectExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object")]; found {
+ var XObject Object
+ n := len(valueList)
+ if n != 1 {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Too many values for ParamName X-Object, 1 is required, but %d found", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object", valueList[0], &XObject, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter X-Object: %w", err).Error())
+ }
+
+ params.XObject = &XObject
+
+ }
+
+ // ------------- Optional header parameter "X-Complex-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Complex-Object")]; found {
+ var XComplexObject ComplexObject
+ n := len(valueList)
+ if n != 1 {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Too many values for ParamName X-Complex-Object, 1 is required, but %d found", n))
+ }
+
+ err = json.Unmarshal([]byte(valueList[0]), &XComplexObject)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshaling parameter 'X-Complex-Object' as JSON: %w", err).Error())
+ }
+
+ params.XComplexObject = &XComplexObject
+
+ }
+
+ // ------------- Optional header parameter "1-Starting-With-Number" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("1-Starting-With-Number")]; found {
+ var N1StartingWithNumber string
+ n := len(valueList)
+ if n != 1 {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Too many values for ParamName 1-Starting-With-Number, 1 is required, but %d found", n))
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "1-Starting-With-Number", valueList[0], &N1StartingWithNumber, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter 1-Starting-With-Number: %w", err).Error())
+ }
+
+ params.N1StartingWithNumber = &N1StartingWithNumber
+
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetHeader(c, params)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetLabelExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodeArray(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", c.Params("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter param: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetLabelExplodeArray(c, param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetLabelExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodeObject(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", c.Params("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter param: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetLabelExplodeObject(c, param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetLabelExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodePrimitive(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", c.Params("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter param: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetLabelExplodePrimitive(c, param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetLabelNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelNoExplodeArray(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", c.Params("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter param: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetLabelNoExplodeArray(c, param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetLabelNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelNoExplodeObject(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", c.Params("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter param: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetLabelNoExplodeObject(c, param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetLabelPrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelPrimitive(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", c.Params("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter param: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetLabelPrimitive(c, param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetMatrixExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodeArray(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", c.Params("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetMatrixExplodeArray(c, id)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetMatrixExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodeObject(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", c.Params("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetMatrixExplodeObject(c, id)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetMatrixExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodePrimitive(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", c.Params("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetMatrixExplodePrimitive(c, id)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetMatrixNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixNoExplodeArray(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", c.Params("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetMatrixNoExplodeArray(c, id)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetMatrixNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixNoExplodeObject(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", c.Params("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetMatrixNoExplodeObject(c, id)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetMatrixPrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixPrimitive(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", c.Params("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter id: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetMatrixPrimitive(c, id)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetPassThrough operation middleware
+func (siw *ServerInterfaceWrapper) GetPassThrough(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param string
+
+ param, err = url.PathUnescape(c.Params("param"))
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unescaping path parameter 'param': %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetPassThrough(c, param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetDeepObject operation middleware
+func (siw *ServerInterfaceWrapper) GetDeepObject(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetDeepObjectParams
+
+ var query url.Values
+ query, err = url.ParseQuery(string(c.Request().URI().QueryString()))
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for query string: %w", err).Error())
+ }
+
+ // ------------- Required query parameter "deepObj" -------------
+
+ err = runtime.BindQueryParameterWithOptions("deepObject", true, true, "deepObj", query, ¶ms.DeepObj, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter deepObj: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetDeepObject(c, params)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetQueryDelimited operation middleware
+func (siw *ServerInterfaceWrapper) GetQueryDelimited(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryDelimitedParams
+
+ var query url.Values
+ query, err = url.ParseQuery(string(c.Request().URI().QueryString()))
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for query string: %w", err).Error())
+ }
+
+ // ------------- Optional query parameter "sa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("spaceDelimited", false, false, "sa", query, ¶ms.Sa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter sa: %w", err).Error())
+ }
+
+ // ------------- Optional query parameter "pa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("pipeDelimited", false, false, "pa", query, ¶ms.Pa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter pa: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetQueryDelimited(c, params)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetQueryForm operation middleware
+func (siw *ServerInterfaceWrapper) GetQueryForm(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryFormParams
+
+ var query url.Values
+ query, err = url.ParseQuery(string(c.Request().URI().QueryString()))
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for query string: %w", err).Error())
+ }
+
+ // ------------- Optional query parameter "ea" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ea", query, ¶ms.Ea, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter ea: %w", err).Error())
+ }
+
+ // ------------- Optional query parameter "a" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "a", query, ¶ms.A, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter a: %w", err).Error())
+ }
+
+ // ------------- Optional query parameter "eo" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "eo", query, ¶ms.Eo, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter eo: %w", err).Error())
+ }
+
+ // ------------- Optional query parameter "o" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "o", query, ¶ms.O, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter o: %w", err).Error())
+ }
+
+ // ------------- Optional query parameter "ep" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ep", query, ¶ms.Ep, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter ep: %w", err).Error())
+ }
+
+ // ------------- Optional query parameter "p" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "p", query, ¶ms.P, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter p: %w", err).Error())
+ }
+
+ // ------------- Optional query parameter "ps" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ps", query, ¶ms.Ps, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter ps: %w", err).Error())
+ }
+
+ // ------------- Optional query parameter "co" -------------
+
+ if paramValue := c.Query("co"); paramValue != "" {
+
+ var value ComplexObject
+ err = json.Unmarshal([]byte(paramValue), &value)
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshaling parameter 'co' as JSON: %w", err).Error())
+ }
+
+ params.Co = &value
+
+ }
+
+ // ------------- Optional query parameter "1s" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "1s", query, ¶ms.N1s, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter 1s: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetQueryForm(c, params)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetSimpleExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodeArray(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", c.Params("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter param: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetSimpleExplodeArray(c, param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetSimpleExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodeObject(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", c.Params("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter param: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetSimpleExplodeObject(c, param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetSimpleExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodePrimitive(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", c.Params("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter param: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetSimpleExplodePrimitive(c, param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetSimpleNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleNoExplodeArray(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", c.Params("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter param: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetSimpleNoExplodeArray(c, param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetSimpleNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleNoExplodeObject(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", c.Params("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter param: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetSimpleNoExplodeObject(c, param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetSimplePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetSimplePrimitive(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", c.Params("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter param: %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetSimplePrimitive(c, param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// GetStartingWithNumber operation middleware
+func (siw *ServerInterfaceWrapper) GetStartingWithNumber(c *fiber.Ctx) error {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "1param" -------------
+ var n1param string
+
+ n1param, err = url.PathUnescape(c.Params("1param"))
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unescaping path parameter '1param': %w", err).Error())
+ }
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.GetStartingWithNumber(c, n1param)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// FiberServerOptions provides options for the Fiber server.
+type FiberServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ HandlerMiddlewares []HandlerMiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router fiber.Router, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, FiberServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.HandlerMiddlewares,
+ }
+
+ for _, m := range options.Middlewares {
+ router.Use(fiber.Handler(m))
+ }
+
+ router.Get(options.BaseURL+"/contentObject/:param", wrapper.GetContentObject)
+
+ router.Get(options.BaseURL+"/cookie", wrapper.GetCookie)
+
+ router.Get(options.BaseURL+"/enums", wrapper.EnumParams)
+
+ router.Get(options.BaseURL+"/header", wrapper.GetHeader)
+
+ router.Get(options.BaseURL+"/labelExplodeArray/:param", wrapper.GetLabelExplodeArray)
+
+ router.Get(options.BaseURL+"/labelExplodeObject/:param", wrapper.GetLabelExplodeObject)
+
+ router.Get(options.BaseURL+"/labelExplodePrimitive/:param", wrapper.GetLabelExplodePrimitive)
+
+ router.Get(options.BaseURL+"/labelNoExplodeArray/:param", wrapper.GetLabelNoExplodeArray)
+
+ router.Get(options.BaseURL+"/labelNoExplodeObject/:param", wrapper.GetLabelNoExplodeObject)
+
+ router.Get(options.BaseURL+"/labelPrimitive/:param", wrapper.GetLabelPrimitive)
+
+ router.Get(options.BaseURL+"/matrixExplodeArray/:id", wrapper.GetMatrixExplodeArray)
+
+ router.Get(options.BaseURL+"/matrixExplodeObject/:id", wrapper.GetMatrixExplodeObject)
+
+ router.Get(options.BaseURL+"/matrixExplodePrimitive/:id", wrapper.GetMatrixExplodePrimitive)
+
+ router.Get(options.BaseURL+"/matrixNoExplodeArray/:id", wrapper.GetMatrixNoExplodeArray)
+
+ router.Get(options.BaseURL+"/matrixNoExplodeObject/:id", wrapper.GetMatrixNoExplodeObject)
+
+ router.Get(options.BaseURL+"/matrixPrimitive/:id", wrapper.GetMatrixPrimitive)
+
+ router.Get(options.BaseURL+"/passThrough/:param", wrapper.GetPassThrough)
+
+ router.Get(options.BaseURL+"/queryDeepObject", wrapper.GetDeepObject)
+
+ router.Get(options.BaseURL+"/queryDelimited", wrapper.GetQueryDelimited)
+
+ router.Get(options.BaseURL+"/queryForm", wrapper.GetQueryForm)
+
+ router.Get(options.BaseURL+"/simpleExplodeArray/:param", wrapper.GetSimpleExplodeArray)
+
+ router.Get(options.BaseURL+"/simpleExplodeObject/:param", wrapper.GetSimpleExplodeObject)
+
+ router.Get(options.BaseURL+"/simpleExplodePrimitive/:param", wrapper.GetSimpleExplodePrimitive)
+
+ router.Get(options.BaseURL+"/simpleNoExplodeArray/:param", wrapper.GetSimpleNoExplodeArray)
+
+ router.Get(options.BaseURL+"/simpleNoExplodeObject/:param", wrapper.GetSimpleNoExplodeObject)
+
+ router.Get(options.BaseURL+"/simplePrimitive/:param", wrapper.GetSimplePrimitive)
+
+ router.Get(options.BaseURL+"/startingWithNumber/:1param", wrapper.GetStartingWithNumber)
+
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "3FpLb+M2F/0rwv2+VaFYdqYrdRVMp22ATiatA0yBIAtGuo44lUQOSacJDP33gpRkPa2HLeXRXWJd3sch",
+ "z6F4qR14LOIsxlhJcHcgUHIWSzT/rGnEQ/wz+0n/4rFYYaz0nwqflMNDQmP9n/QCjIj5/ZkjuCCVoPED",
+ "JElig4/SE5QrymJw4cKSxq+Vx7LY/Tf0FGjT1I+J/pFpq6cv6UN3B1wwjkLRNLlLvxSNxgofUEBiw6W8",
+ "8KM0qezhPWMhklg/LJz9X+AGXPifU9TvZMGdL0U+Ar9vqUAf3Nt8sK1DF3HuKm6rOW6okOqKRNgCjA2C",
+ "hW0PalGNlV1ydWcwpfGG6cEh9TCbnNgEgs+XN9q7okq7hxuUylqjeEQBNjyikOk0rBbLxVIbMo4x4RRc",
+ "+LBYLlZgAycqMPk72Xyn9Tk7TgSJEv3kAU25ulii51XPBvyK6mN5gHElSIQKhQT3trJ+COch9cxg55tk",
+ "tVXUNT3VhZGhAa5JG+wcBhMZylgqscXkzq6u8fPl8lC8vZ1TI0JiYjoeY39T7EbDWDRgqBKCCxpRRR+1",
+ "IT7xkPkI7oaEErPCvNxNXhrYJag2TEREpST4cA52gxOJPSiihudAQDw5YhbFt4gQ5HloWFIJSxVGclD8",
+ "/S9ptJZ8Gml04T1fGntYWE6YQbiwSkLDpKweuhmxC4LjIs5F92olXmpQYNhagcegCYJ+ZklFhKLxg/UP",
+ "VYEVb6N7I5WtXlayAkRduuvq4uOGbEN1rMJgvE2XWqvAfIq30bUWFtmnMNf5w7RE7dZ6JOEWZV7n9y2K",
+ "59IKM65VcJ2JaFGxfgLu7Wq5tM+Xyzt7gBg0JffHFJvKTDArXy1Z8QESH0WXvP6WWpwqr0HuJiv+r7Pr",
+ "0pBZhbYj9NmnTBteRHqbiVxo6/YkXkyID2T1ynLczCrVpnaw5lDnQxm8O5FuFpI5ygs6QrLrPldn68z6",
+ "7CtVwdlVbv1iMh6SewyzxWEWsLNbGMn6ofNd+vf6sKbStS3PIa/B0xDIBqmezSHDVAhTvlyXMcuPH2NB",
+ "O3QKmQK1Iex6KXz2e8Z4iMo73QwoDVhSM0N0xdqI149PdVwHOmVd/g9Rb19/lXwjgOtl3ynIvQn6NXjX",
+ "j84Qvp2Cy6sSLiJK0Kca36jfrUafG4OOkSLqz060tLr5ANsTbRRix+9xPZCNY9jc4JSo9tMofE7a4Hog",
+ "GkG22fBp7G/UHwDOBLvbe2Zcc3Mbh9oJW9v7YF2VbgOgOW1fe9M840TKm0Cw7UMw5AbkujDvvP8YcX/2",
+ "KrcbpiP4MyIvLrcOlVyy6unF+Yi8u7lSa0T6qeujOVPrSxQLxS9ynvq4nyEXakag3wXcH1XLHvAkJx5a",
+ "fm5udbbOajjKqe4wCgRNOkXyLc1Pyo9Nl0+frs6mlO3UTPmFiah3qo1RzywPatfW2/XTw6WHwsh2bS2r",
+ "F0tqWNu2jtn8l2i1iFME3Jfad7NQr3aeO+MuCk8W0Mr2wgNxum/kXrnBXUv2uEvImpORd5AnKFv6oU71",
+ "gDGgwbhuDHu7neu0RJgNtcqnMyNgezu967kRKp01+t+u160jX715PRtG9eP9UITeTft6fuSGf7y2bhv4",
+ "JhrYs6F0BPk6WPceaZbtu1+pCtKbYWe3GgBFY9iMh/3VzKd9jbD5QDTNeytCcCFQiruOk30dqlCqhT4z",
+ "R4QvCIXkLvk3AAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/parameters/fiber/gen/types.gen.go b/internal/test/parameters/fiber/gen/types.gen.go
new file mode 100644
index 0000000000..c7b09599fb
--- /dev/null
+++ b/internal/test/parameters/fiber/gen/types.gen.go
@@ -0,0 +1,143 @@
+// Package fiberparamsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package fiberparamsgen
+
+// Defines values for EnumParamsParamsEnumPathParam.
+const (
+ N100 EnumParamsParamsEnumPathParam = 100
+ N200 EnumParamsParamsEnumPathParam = 200
+)
+
+// Valid indicates whether the value is a known member of the EnumParamsParamsEnumPathParam enum.
+func (e EnumParamsParamsEnumPathParam) Valid() bool {
+ switch e {
+ case N100:
+ return true
+ case N200:
+ return true
+ default:
+ return false
+ }
+}
+
+// ComplexObject defines model for ComplexObject.
+type ComplexObject struct {
+ Id int `json:"Id"`
+ IsAdmin bool `json:"IsAdmin"`
+ Object Object `json:"Object"`
+}
+
+// Object defines model for Object.
+type Object struct {
+ FirstName string `json:"firstName"`
+ Role string `json:"role"`
+}
+
+// GetCookieParams defines parameters for GetCookie.
+type GetCookieParams struct {
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ep primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
+
+// EnumParamsParams defines parameters for EnumParams.
+type EnumParamsParams struct {
+ // EnumPathParam Parameter with enum values
+ EnumPathParam *EnumParamsParamsEnumPathParam `form:"enumPathParam,omitempty" json:"enumPathParam,omitempty"`
+}
+
+// EnumParamsParamsEnumPathParam defines parameters for EnumParams.
+type EnumParamsParamsEnumPathParam int32
+
+// GetHeaderParams defines parameters for GetHeader.
+type GetHeaderParams struct {
+ // XPrimitive primitive
+ XPrimitive *int32 `json:"X-Primitive,omitempty"`
+
+ // XPrimitiveExploded primitive
+ XPrimitiveExploded *int32 `json:"X-Primitive-Exploded,omitempty"`
+
+ // XArrayExploded exploded array
+ XArrayExploded *[]int32 `json:"X-Array-Exploded,omitempty"`
+
+ // XArray array
+ XArray *[]int32 `json:"X-Array,omitempty"`
+
+ // XObjectExploded exploded object
+ XObjectExploded *Object `json:"X-Object-Exploded,omitempty"`
+
+ // XObject object
+ XObject *Object `json:"X-Object,omitempty"`
+
+ // XComplexObject complex object
+ XComplexObject *ComplexObject `json:"X-Complex-Object,omitempty"`
+
+ // N1StartingWithNumber name starting with number
+ N1StartingWithNumber *string `json:"1-Starting-With-Number,omitempty"`
+}
+
+// GetDeepObjectParams defines parameters for GetDeepObject.
+type GetDeepObjectParams struct {
+ // DeepObj deep object
+ DeepObj ComplexObject `json:"deepObj"`
+}
+
+// GetQueryDelimitedParams defines parameters for GetQueryDelimited.
+type GetQueryDelimitedParams struct {
+ // Sa space delimited array
+ Sa *[]int32 `json:"sa,omitempty"`
+
+ // Pa pipe delimited array
+ Pa *[]int32 `json:"pa,omitempty"`
+}
+
+// GetQueryFormParams defines parameters for GetQueryForm.
+type GetQueryFormParams struct {
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Ep exploded primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ps primitive string
+ Ps *string `form:"ps,omitempty" json:"ps,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
diff --git a/internal/test/parameters/fiber/server.cfg.yaml b/internal/test/parameters/fiber/server.cfg.yaml
new file mode 100644
index 0000000000..02818417f9
--- /dev/null
+++ b/internal/test/parameters/fiber/server.cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: fiberparamsgen
+generate:
+ fiber-server: true
+ embedded-spec: true
+output: gen/server.gen.go
diff --git a/internal/test/parameters/fiber/server.go b/internal/test/parameters/fiber/server.go
new file mode 100644
index 0000000000..23431a9fe4
--- /dev/null
+++ b/internal/test/parameters/fiber/server.go
@@ -0,0 +1,44 @@
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../parameters.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../parameters.yaml
+
+package fiberparams
+
+import (
+ "net/http"
+
+ "github.com/gofiber/fiber/v2"
+
+ gen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/fiber/gen"
+)
+
+type Server struct{}
+
+var _ gen.ServerInterface = (*Server)(nil)
+
+func (s *Server) GetContentObject(c *fiber.Ctx, param gen.ComplexObject) error { return c.JSON(param) }
+func (s *Server) GetCookie(c *fiber.Ctx, params gen.GetCookieParams) error { return c.JSON(params) }
+func (s *Server) EnumParams(c *fiber.Ctx, params gen.EnumParamsParams) error { return c.SendStatus(http.StatusNoContent) }
+func (s *Server) GetHeader(c *fiber.Ctx, params gen.GetHeaderParams) error { return c.JSON(params) }
+func (s *Server) GetLabelExplodeArray(c *fiber.Ctx, param []int32) error { return c.JSON(param) }
+func (s *Server) GetLabelExplodeObject(c *fiber.Ctx, param gen.Object) error { return c.JSON(param) }
+func (s *Server) GetLabelExplodePrimitive(c *fiber.Ctx, param int32) error { return c.JSON(param) }
+func (s *Server) GetLabelNoExplodeArray(c *fiber.Ctx, param []int32) error { return c.JSON(param) }
+func (s *Server) GetLabelNoExplodeObject(c *fiber.Ctx, param gen.Object) error { return c.JSON(param) }
+func (s *Server) GetLabelPrimitive(c *fiber.Ctx, param int32) error { return c.JSON(param) }
+func (s *Server) GetMatrixExplodeArray(c *fiber.Ctx, id []int32) error { return c.JSON(id) }
+func (s *Server) GetMatrixExplodeObject(c *fiber.Ctx, id gen.Object) error { return c.JSON(id) }
+func (s *Server) GetMatrixExplodePrimitive(c *fiber.Ctx, id int32) error { return c.JSON(id) }
+func (s *Server) GetMatrixNoExplodeArray(c *fiber.Ctx, id []int32) error { return c.JSON(id) }
+func (s *Server) GetMatrixNoExplodeObject(c *fiber.Ctx, id gen.Object) error { return c.JSON(id) }
+func (s *Server) GetMatrixPrimitive(c *fiber.Ctx, id int32) error { return c.JSON(id) }
+func (s *Server) GetPassThrough(c *fiber.Ctx, param string) error { return c.JSON(param) }
+func (s *Server) GetDeepObject(c *fiber.Ctx, params gen.GetDeepObjectParams) error { return c.JSON(params) }
+func (s *Server) GetQueryDelimited(c *fiber.Ctx, params gen.GetQueryDelimitedParams) error { return c.JSON(params) }
+func (s *Server) GetQueryForm(c *fiber.Ctx, params gen.GetQueryFormParams) error { return c.JSON(params) }
+func (s *Server) GetSimpleExplodeArray(c *fiber.Ctx, param []int32) error { return c.JSON(param) }
+func (s *Server) GetSimpleExplodeObject(c *fiber.Ctx, param gen.Object) error { return c.JSON(param) }
+func (s *Server) GetSimpleExplodePrimitive(c *fiber.Ctx, param int32) error { return c.JSON(param) }
+func (s *Server) GetSimpleNoExplodeArray(c *fiber.Ctx, param []int32) error { return c.JSON(param) }
+func (s *Server) GetSimpleNoExplodeObject(c *fiber.Ctx, param gen.Object) error { return c.JSON(param) }
+func (s *Server) GetSimplePrimitive(c *fiber.Ctx, param int32) error { return c.JSON(param) }
+func (s *Server) GetStartingWithNumber(c *fiber.Ctx, n1param string) error { return c.JSON(n1param) }
diff --git a/internal/test/parameters/fiber/types.cfg.yaml b/internal/test/parameters/fiber/types.cfg.yaml
new file mode 100644
index 0000000000..4f12092b04
--- /dev/null
+++ b/internal/test/parameters/fiber/types.cfg.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: fiberparamsgen
+generate:
+ models: true
+output: gen/types.gen.go
diff --git a/internal/test/parameters/gin/gen/server.gen.go b/internal/test/parameters/gin/gen/server.gen.go
new file mode 100644
index 0000000000..5bf8e4232f
--- /dev/null
+++ b/internal/test/parameters/gin/gen/server.gen.go
@@ -0,0 +1,1314 @@
+// Package ginparamsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package ginparamsgen
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gin-gonic/gin"
+ "github.com/oapi-codegen/runtime"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /contentObject/{param})
+ GetContentObject(c *gin.Context, param ComplexObject)
+
+ // (GET /cookie)
+ GetCookie(c *gin.Context, params GetCookieParams)
+
+ // (GET /enums)
+ EnumParams(c *gin.Context, params EnumParamsParams)
+
+ // (GET /header)
+ GetHeader(c *gin.Context, params GetHeaderParams)
+
+ // (GET /labelExplodeArray/{.param*})
+ GetLabelExplodeArray(c *gin.Context, param []int32)
+
+ // (GET /labelExplodeObject/{.param*})
+ GetLabelExplodeObject(c *gin.Context, param Object)
+
+ // (GET /labelExplodePrimitive/{.param*})
+ GetLabelExplodePrimitive(c *gin.Context, param int32)
+
+ // (GET /labelNoExplodeArray/{.param})
+ GetLabelNoExplodeArray(c *gin.Context, param []int32)
+
+ // (GET /labelNoExplodeObject/{.param})
+ GetLabelNoExplodeObject(c *gin.Context, param Object)
+
+ // (GET /labelPrimitive/{.param})
+ GetLabelPrimitive(c *gin.Context, param int32)
+
+ // (GET /matrixExplodeArray/{.id*})
+ GetMatrixExplodeArray(c *gin.Context, id []int32)
+
+ // (GET /matrixExplodeObject/{.id*})
+ GetMatrixExplodeObject(c *gin.Context, id Object)
+
+ // (GET /matrixExplodePrimitive/{;id*})
+ GetMatrixExplodePrimitive(c *gin.Context, id int32)
+
+ // (GET /matrixNoExplodeArray/{.id})
+ GetMatrixNoExplodeArray(c *gin.Context, id []int32)
+
+ // (GET /matrixNoExplodeObject/{.id})
+ GetMatrixNoExplodeObject(c *gin.Context, id Object)
+
+ // (GET /matrixPrimitive/{;id})
+ GetMatrixPrimitive(c *gin.Context, id int32)
+
+ // (GET /passThrough/{param})
+ GetPassThrough(c *gin.Context, param string)
+
+ // (GET /queryDeepObject)
+ GetDeepObject(c *gin.Context, params GetDeepObjectParams)
+
+ // (GET /queryDelimited)
+ GetQueryDelimited(c *gin.Context, params GetQueryDelimitedParams)
+
+ // (GET /queryForm)
+ GetQueryForm(c *gin.Context, params GetQueryFormParams)
+
+ // (GET /simpleExplodeArray/{param*})
+ GetSimpleExplodeArray(c *gin.Context, param []int32)
+
+ // (GET /simpleExplodeObject/{param*})
+ GetSimpleExplodeObject(c *gin.Context, param Object)
+
+ // (GET /simpleExplodePrimitive/{param})
+ GetSimpleExplodePrimitive(c *gin.Context, param int32)
+
+ // (GET /simpleNoExplodeArray/{param})
+ GetSimpleNoExplodeArray(c *gin.Context, param []int32)
+
+ // (GET /simpleNoExplodeObject/{param})
+ GetSimpleNoExplodeObject(c *gin.Context, param Object)
+
+ // (GET /simplePrimitive/{param})
+ GetSimplePrimitive(c *gin.Context, param int32)
+
+ // (GET /startingWithNumber/{1param})
+ GetStartingWithNumber(c *gin.Context, n1param string)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandler func(*gin.Context, error, int)
+}
+
+type MiddlewareFunc func(c *gin.Context)
+
+// GetContentObject operation middleware
+func (siw *ServerInterfaceWrapper) GetContentObject(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param ComplexObject
+
+ err = json.Unmarshal([]byte(c.Param("param")), ¶m)
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter 'param' as JSON"), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetContentObject(c, param)
+}
+
+// GetCookie operation middleware
+func (siw *ServerInterfaceWrapper) GetCookie(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetCookieParams
+
+ {
+ var cookie string
+
+ if cookie, err = c.Cookie("p"); err == nil {
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "p", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter p: %w", err), http.StatusBadRequest)
+ return
+ }
+ params.P = &value
+
+ }
+ }
+
+ {
+ var cookie string
+
+ if cookie, err = c.Cookie("ep"); err == nil {
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ep", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter ep: %w", err), http.StatusBadRequest)
+ return
+ }
+ params.Ep = &value
+
+ }
+ }
+
+ {
+ var cookie string
+
+ if cookie, err = c.Cookie("ea"); err == nil {
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ea", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter ea: %w", err), http.StatusBadRequest)
+ return
+ }
+ params.Ea = &value
+
+ }
+ }
+
+ {
+ var cookie string
+
+ if cookie, err = c.Cookie("a"); err == nil {
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "a", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter a: %w", err), http.StatusBadRequest)
+ return
+ }
+ params.A = &value
+
+ }
+ }
+
+ {
+ var cookie string
+
+ if cookie, err = c.Cookie("eo"); err == nil {
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "eo", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter eo: %w", err), http.StatusBadRequest)
+ return
+ }
+ params.Eo = &value
+
+ }
+ }
+
+ {
+ var cookie string
+
+ if cookie, err = c.Cookie("o"); err == nil {
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "o", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter o: %w", err), http.StatusBadRequest)
+ return
+ }
+ params.O = &value
+
+ }
+ }
+
+ {
+ var cookie string
+
+ if cookie, err = c.Cookie("co"); err == nil {
+ var value ComplexObject
+ var decoded string
+ decoded, err := url.QueryUnescape(cookie)
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Error unescaping cookie parameter 'co'"), http.StatusBadRequest)
+ return
+ }
+
+ err = json.Unmarshal([]byte(decoded), &value)
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter 'co' as JSON"), http.StatusBadRequest)
+ return
+ }
+
+ params.Co = &value
+
+ }
+ }
+
+ {
+ var cookie string
+
+ if cookie, err = c.Cookie("1s"); err == nil {
+ var value string
+ err = runtime.BindStyledParameterWithOptions("simple", "1s", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter 1s: %w", err), http.StatusBadRequest)
+ return
+ }
+ params.N1s = &value
+
+ }
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetCookie(c, params)
+}
+
+// EnumParams operation middleware
+func (siw *ServerInterfaceWrapper) EnumParams(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params EnumParamsParams
+
+ // ------------- Optional query parameter "enumPathParam" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "enumPathParam", c.Request.URL.Query(), ¶ms.EnumPathParam, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter enumPathParam: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.EnumParams(c, params)
+}
+
+// GetHeader operation middleware
+func (siw *ServerInterfaceWrapper) GetHeader(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetHeaderParams
+
+ headers := c.Request.Header
+
+ // ------------- Optional header parameter "X-Primitive" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive")]; found {
+ var XPrimitive int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandler(c, fmt.Errorf("Expected one value for X-Primitive, got %d", n), http.StatusBadRequest)
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive", valueList[0], &XPrimitive, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter X-Primitive: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ params.XPrimitive = &XPrimitive
+
+ }
+
+ // ------------- Optional header parameter "X-Primitive-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive-Exploded")]; found {
+ var XPrimitiveExploded int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandler(c, fmt.Errorf("Expected one value for X-Primitive-Exploded, got %d", n), http.StatusBadRequest)
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive-Exploded", valueList[0], &XPrimitiveExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter X-Primitive-Exploded: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ params.XPrimitiveExploded = &XPrimitiveExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Array-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array-Exploded")]; found {
+ var XArrayExploded []int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandler(c, fmt.Errorf("Expected one value for X-Array-Exploded, got %d", n), http.StatusBadRequest)
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array-Exploded", valueList[0], &XArrayExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter X-Array-Exploded: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ params.XArrayExploded = &XArrayExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Array" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array")]; found {
+ var XArray []int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandler(c, fmt.Errorf("Expected one value for X-Array, got %d", n), http.StatusBadRequest)
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array", valueList[0], &XArray, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter X-Array: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ params.XArray = &XArray
+
+ }
+
+ // ------------- Optional header parameter "X-Object-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object-Exploded")]; found {
+ var XObjectExploded Object
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandler(c, fmt.Errorf("Expected one value for X-Object-Exploded, got %d", n), http.StatusBadRequest)
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object-Exploded", valueList[0], &XObjectExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter X-Object-Exploded: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ params.XObjectExploded = &XObjectExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object")]; found {
+ var XObject Object
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandler(c, fmt.Errorf("Expected one value for X-Object, got %d", n), http.StatusBadRequest)
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object", valueList[0], &XObject, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter X-Object: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ params.XObject = &XObject
+
+ }
+
+ // ------------- Optional header parameter "X-Complex-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Complex-Object")]; found {
+ var XComplexObject ComplexObject
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandler(c, fmt.Errorf("Expected one value for X-Complex-Object, got %d", n), http.StatusBadRequest)
+ return
+ }
+
+ err = json.Unmarshal([]byte(valueList[0]), &XComplexObject)
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter 'X-Complex-Object' as JSON"), http.StatusBadRequest)
+ return
+ }
+
+ params.XComplexObject = &XComplexObject
+
+ }
+
+ // ------------- Optional header parameter "1-Starting-With-Number" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("1-Starting-With-Number")]; found {
+ var N1StartingWithNumber string
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandler(c, fmt.Errorf("Expected one value for 1-Starting-With-Number, got %d", n), http.StatusBadRequest)
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "1-Starting-With-Number", valueList[0], &N1StartingWithNumber, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter 1-Starting-With-Number: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ params.N1StartingWithNumber = &N1StartingWithNumber
+
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetHeader(c, params)
+}
+
+// GetLabelExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodeArray(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", c.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter param: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetLabelExplodeArray(c, param)
+}
+
+// GetLabelExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodeObject(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", c.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter param: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetLabelExplodeObject(c, param)
+}
+
+// GetLabelExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodePrimitive(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", c.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter param: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetLabelExplodePrimitive(c, param)
+}
+
+// GetLabelNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelNoExplodeArray(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", c.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter param: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetLabelNoExplodeArray(c, param)
+}
+
+// GetLabelNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelNoExplodeObject(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", c.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter param: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetLabelNoExplodeObject(c, param)
+}
+
+// GetLabelPrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelPrimitive(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", c.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter param: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetLabelPrimitive(c, param)
+}
+
+// GetMatrixExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodeArray(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetMatrixExplodeArray(c, id)
+}
+
+// GetMatrixExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodeObject(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetMatrixExplodeObject(c, id)
+}
+
+// GetMatrixExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodePrimitive(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetMatrixExplodePrimitive(c, id)
+}
+
+// GetMatrixNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixNoExplodeArray(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetMatrixNoExplodeArray(c, id)
+}
+
+// GetMatrixNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixNoExplodeObject(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetMatrixNoExplodeObject(c, id)
+}
+
+// GetMatrixPrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixPrimitive(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter id: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetMatrixPrimitive(c, id)
+}
+
+// GetPassThrough operation middleware
+func (siw *ServerInterfaceWrapper) GetPassThrough(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param string
+
+ param = c.Param("param")
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetPassThrough(c, param)
+}
+
+// GetDeepObject operation middleware
+func (siw *ServerInterfaceWrapper) GetDeepObject(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetDeepObjectParams
+
+ // ------------- Required query parameter "deepObj" -------------
+
+ err = runtime.BindQueryParameterWithOptions("deepObject", true, true, "deepObj", c.Request.URL.Query(), ¶ms.DeepObj, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter deepObj: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetDeepObject(c, params)
+}
+
+// GetQueryDelimited operation middleware
+func (siw *ServerInterfaceWrapper) GetQueryDelimited(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryDelimitedParams
+
+ // ------------- Optional query parameter "sa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("spaceDelimited", false, false, "sa", c.Request.URL.Query(), ¶ms.Sa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter sa: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ // ------------- Optional query parameter "pa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("pipeDelimited", false, false, "pa", c.Request.URL.Query(), ¶ms.Pa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter pa: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetQueryDelimited(c, params)
+}
+
+// GetQueryForm operation middleware
+func (siw *ServerInterfaceWrapper) GetQueryForm(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryFormParams
+
+ // ------------- Optional query parameter "ea" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ea", c.Request.URL.Query(), ¶ms.Ea, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter ea: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ // ------------- Optional query parameter "a" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "a", c.Request.URL.Query(), ¶ms.A, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter a: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ // ------------- Optional query parameter "eo" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "eo", c.Request.URL.Query(), ¶ms.Eo, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter eo: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ // ------------- Optional query parameter "o" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "o", c.Request.URL.Query(), ¶ms.O, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter o: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ // ------------- Optional query parameter "ep" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ep", c.Request.URL.Query(), ¶ms.Ep, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter ep: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ // ------------- Optional query parameter "p" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "p", c.Request.URL.Query(), ¶ms.P, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter p: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ // ------------- Optional query parameter "ps" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ps", c.Request.URL.Query(), ¶ms.Ps, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter ps: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ // ------------- Optional query parameter "co" -------------
+
+ if paramValue := c.Query("co"); paramValue != "" {
+
+ var value ComplexObject
+ err = json.Unmarshal([]byte(paramValue), &value)
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter 'co' as JSON: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ params.Co = &value
+
+ }
+
+ // ------------- Optional query parameter "1s" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "1s", c.Request.URL.Query(), ¶ms.N1s, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter 1s: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetQueryForm(c, params)
+}
+
+// GetSimpleExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodeArray(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", c.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter param: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetSimpleExplodeArray(c, param)
+}
+
+// GetSimpleExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodeObject(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", c.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter param: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetSimpleExplodeObject(c, param)
+}
+
+// GetSimpleExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodePrimitive(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", c.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter param: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetSimpleExplodePrimitive(c, param)
+}
+
+// GetSimpleNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleNoExplodeArray(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", c.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter param: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetSimpleNoExplodeArray(c, param)
+}
+
+// GetSimpleNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleNoExplodeObject(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", c.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter param: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetSimpleNoExplodeObject(c, param)
+}
+
+// GetSimplePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetSimplePrimitive(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", c.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter param: %w", err), http.StatusBadRequest)
+ return
+ }
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetSimplePrimitive(c, param)
+}
+
+// GetStartingWithNumber operation middleware
+func (siw *ServerInterfaceWrapper) GetStartingWithNumber(c *gin.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "1param" -------------
+ var n1param string
+
+ n1param = c.Param("1param")
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.GetStartingWithNumber(c, n1param)
+}
+
+// GinServerOptions provides options for the Gin server.
+type GinServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ ErrorHandler func(*gin.Context, error, int)
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router gin.IRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, GinServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options GinServerOptions) {
+ errorHandler := options.ErrorHandler
+ if errorHandler == nil {
+ errorHandler = func(c *gin.Context, err error, statusCode int) {
+ c.JSON(statusCode, gin.H{"msg": err.Error()})
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandler: errorHandler,
+ }
+
+ router.GET(options.BaseURL+"/contentObject/:param", wrapper.GetContentObject)
+ router.GET(options.BaseURL+"/cookie", wrapper.GetCookie)
+ router.GET(options.BaseURL+"/enums", wrapper.EnumParams)
+ router.GET(options.BaseURL+"/header", wrapper.GetHeader)
+ router.GET(options.BaseURL+"/labelExplodeArray/:param", wrapper.GetLabelExplodeArray)
+ router.GET(options.BaseURL+"/labelExplodeObject/:param", wrapper.GetLabelExplodeObject)
+ router.GET(options.BaseURL+"/labelExplodePrimitive/:param", wrapper.GetLabelExplodePrimitive)
+ router.GET(options.BaseURL+"/labelNoExplodeArray/:param", wrapper.GetLabelNoExplodeArray)
+ router.GET(options.BaseURL+"/labelNoExplodeObject/:param", wrapper.GetLabelNoExplodeObject)
+ router.GET(options.BaseURL+"/labelPrimitive/:param", wrapper.GetLabelPrimitive)
+ router.GET(options.BaseURL+"/matrixExplodeArray/:id", wrapper.GetMatrixExplodeArray)
+ router.GET(options.BaseURL+"/matrixExplodeObject/:id", wrapper.GetMatrixExplodeObject)
+ router.GET(options.BaseURL+"/matrixExplodePrimitive/:id", wrapper.GetMatrixExplodePrimitive)
+ router.GET(options.BaseURL+"/matrixNoExplodeArray/:id", wrapper.GetMatrixNoExplodeArray)
+ router.GET(options.BaseURL+"/matrixNoExplodeObject/:id", wrapper.GetMatrixNoExplodeObject)
+ router.GET(options.BaseURL+"/matrixPrimitive/:id", wrapper.GetMatrixPrimitive)
+ router.GET(options.BaseURL+"/passThrough/:param", wrapper.GetPassThrough)
+ router.GET(options.BaseURL+"/queryDeepObject", wrapper.GetDeepObject)
+ router.GET(options.BaseURL+"/queryDelimited", wrapper.GetQueryDelimited)
+ router.GET(options.BaseURL+"/queryForm", wrapper.GetQueryForm)
+ router.GET(options.BaseURL+"/simpleExplodeArray/:param", wrapper.GetSimpleExplodeArray)
+ router.GET(options.BaseURL+"/simpleExplodeObject/:param", wrapper.GetSimpleExplodeObject)
+ router.GET(options.BaseURL+"/simpleExplodePrimitive/:param", wrapper.GetSimpleExplodePrimitive)
+ router.GET(options.BaseURL+"/simpleNoExplodeArray/:param", wrapper.GetSimpleNoExplodeArray)
+ router.GET(options.BaseURL+"/simpleNoExplodeObject/:param", wrapper.GetSimpleNoExplodeObject)
+ router.GET(options.BaseURL+"/simplePrimitive/:param", wrapper.GetSimplePrimitive)
+ router.GET(options.BaseURL+"/startingWithNumber/:1param", wrapper.GetStartingWithNumber)
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "3FpLb+M2F/0rwv2+VaFYdqYrdRVMp22ATiatA0yBIAtGuo44lUQOSacJDP33gpRkPa2HLeXRXWJd3sch",
+ "z6F4qR14LOIsxlhJcHcgUHIWSzT/rGnEQ/wz+0n/4rFYYaz0nwqflMNDQmP9n/QCjIj5/ZkjuCCVoPED",
+ "JElig4/SE5QrymJw4cKSxq+Vx7LY/Tf0FGjT1I+J/pFpq6cv6UN3B1wwjkLRNLlLvxSNxgofUEBiw6W8",
+ "8KM0qezhPWMhklg/LJz9X+AGXPifU9TvZMGdL0U+Ar9vqUAf3Nt8sK1DF3HuKm6rOW6okOqKRNgCjA2C",
+ "hW0PalGNlV1ydWcwpfGG6cEh9TCbnNgEgs+XN9q7okq7hxuUylqjeEQBNjyikOk0rBbLxVIbMo4x4RRc",
+ "+LBYLlZgAycqMPk72Xyn9Tk7TgSJEv3kAU25ulii51XPBvyK6mN5gHElSIQKhQT3trJ+COch9cxg55tk",
+ "tVXUNT3VhZGhAa5JG+wcBhMZylgqscXkzq6u8fPl8lC8vZ1TI0JiYjoeY39T7EbDWDRgqBKCCxpRRR+1",
+ "IT7xkPkI7oaEErPCvNxNXhrYJag2TEREpST4cA52gxOJPSiihudAQDw5YhbFt4gQ5HloWFIJSxVGclD8",
+ "/S9ptJZ8Gml04T1fGntYWE6YQbiwSkLDpKweuhmxC4LjIs5F92olXmpQYNhagcegCYJ+ZklFhKLxg/UP",
+ "VYEVb6N7I5WtXlayAkRduuvq4uOGbEN1rMJgvE2XWqvAfIq30bUWFtmnMNf5w7RE7dZ6JOEWZV7n9y2K",
+ "59IKM65VcJ2JaFGxfgLu7Wq5tM+Xyzt7gBg0JffHFJvKTDArXy1Z8QESH0WXvP6WWpwqr0HuJiv+r7Pr",
+ "0pBZhbYj9NmnTBteRHqbiVxo6/YkXkyID2T1ynLczCrVpnaw5lDnQxm8O5FuFpI5ygs6QrLrPldn68z6",
+ "7CtVwdlVbv1iMh6SewyzxWEWsLNbGMn6ofNd+vf6sKbStS3PIa/B0xDIBqmezSHDVAhTvlyXMcuPH2NB",
+ "O3QKmQK1Iex6KXz2e8Z4iMo73QwoDVhSM0N0xdqI149PdVwHOmVd/g9Rb19/lXwjgOtl3ynIvQn6NXjX",
+ "j84Qvp2Cy6sSLiJK0Kca36jfrUafG4OOkSLqz060tLr5ANsTbRRix+9xPZCNY9jc4JSo9tMofE7a4Hog",
+ "GkG22fBp7G/UHwDOBLvbe2Zcc3Mbh9oJW9v7YF2VbgOgOW1fe9M840TKm0Cw7UMw5AbkujDvvP8YcX/2",
+ "KrcbpiP4MyIvLrcOlVyy6unF+Yi8u7lSa0T6qeujOVPrSxQLxS9ynvq4nyEXakag3wXcH1XLHvAkJx5a",
+ "fm5udbbOajjKqe4wCgRNOkXyLc1Pyo9Nl0+frs6mlO3UTPmFiah3qo1RzywPatfW2/XTw6WHwsh2bS2r",
+ "F0tqWNu2jtn8l2i1iFME3Jfad7NQr3aeO+MuCk8W0Mr2wgNxum/kXrnBXUv2uEvImpORd5AnKFv6oU71",
+ "gDGgwbhuDHu7neu0RJgNtcqnMyNgezu967kRKp01+t+u160jX715PRtG9eP9UITeTft6fuSGf7y2bhv4",
+ "JhrYs6F0BPk6WPceaZbtu1+pCtKbYWe3GgBFY9iMh/3VzKd9jbD5QDTNeytCcCFQiruOk30dqlCqhT4z",
+ "R4QvCIXkLvk3AAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/parameters/gin/gen/types.gen.go b/internal/test/parameters/gin/gen/types.gen.go
new file mode 100644
index 0000000000..e73bcb5083
--- /dev/null
+++ b/internal/test/parameters/gin/gen/types.gen.go
@@ -0,0 +1,143 @@
+// Package ginparamsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package ginparamsgen
+
+// Defines values for EnumParamsParamsEnumPathParam.
+const (
+ N100 EnumParamsParamsEnumPathParam = 100
+ N200 EnumParamsParamsEnumPathParam = 200
+)
+
+// Valid indicates whether the value is a known member of the EnumParamsParamsEnumPathParam enum.
+func (e EnumParamsParamsEnumPathParam) Valid() bool {
+ switch e {
+ case N100:
+ return true
+ case N200:
+ return true
+ default:
+ return false
+ }
+}
+
+// ComplexObject defines model for ComplexObject.
+type ComplexObject struct {
+ Id int `json:"Id"`
+ IsAdmin bool `json:"IsAdmin"`
+ Object Object `json:"Object"`
+}
+
+// Object defines model for Object.
+type Object struct {
+ FirstName string `json:"firstName"`
+ Role string `json:"role"`
+}
+
+// GetCookieParams defines parameters for GetCookie.
+type GetCookieParams struct {
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ep primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
+
+// EnumParamsParams defines parameters for EnumParams.
+type EnumParamsParams struct {
+ // EnumPathParam Parameter with enum values
+ EnumPathParam *EnumParamsParamsEnumPathParam `form:"enumPathParam,omitempty" json:"enumPathParam,omitempty"`
+}
+
+// EnumParamsParamsEnumPathParam defines parameters for EnumParams.
+type EnumParamsParamsEnumPathParam int32
+
+// GetHeaderParams defines parameters for GetHeader.
+type GetHeaderParams struct {
+ // XPrimitive primitive
+ XPrimitive *int32 `json:"X-Primitive,omitempty"`
+
+ // XPrimitiveExploded primitive
+ XPrimitiveExploded *int32 `json:"X-Primitive-Exploded,omitempty"`
+
+ // XArrayExploded exploded array
+ XArrayExploded *[]int32 `json:"X-Array-Exploded,omitempty"`
+
+ // XArray array
+ XArray *[]int32 `json:"X-Array,omitempty"`
+
+ // XObjectExploded exploded object
+ XObjectExploded *Object `json:"X-Object-Exploded,omitempty"`
+
+ // XObject object
+ XObject *Object `json:"X-Object,omitempty"`
+
+ // XComplexObject complex object
+ XComplexObject *ComplexObject `json:"X-Complex-Object,omitempty"`
+
+ // N1StartingWithNumber name starting with number
+ N1StartingWithNumber *string `json:"1-Starting-With-Number,omitempty"`
+}
+
+// GetDeepObjectParams defines parameters for GetDeepObject.
+type GetDeepObjectParams struct {
+ // DeepObj deep object
+ DeepObj ComplexObject `json:"deepObj"`
+}
+
+// GetQueryDelimitedParams defines parameters for GetQueryDelimited.
+type GetQueryDelimitedParams struct {
+ // Sa space delimited array
+ Sa *[]int32 `json:"sa,omitempty"`
+
+ // Pa pipe delimited array
+ Pa *[]int32 `json:"pa,omitempty"`
+}
+
+// GetQueryFormParams defines parameters for GetQueryForm.
+type GetQueryFormParams struct {
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Ep exploded primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ps primitive string
+ Ps *string `form:"ps,omitempty" json:"ps,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
diff --git a/internal/test/parameters/gin/server.cfg.yaml b/internal/test/parameters/gin/server.cfg.yaml
new file mode 100644
index 0000000000..66fa6608ba
--- /dev/null
+++ b/internal/test/parameters/gin/server.cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: ginparamsgen
+generate:
+ gin-server: true
+ embedded-spec: true
+output: gen/server.gen.go
diff --git a/internal/test/parameters/gin/server.go b/internal/test/parameters/gin/server.go
new file mode 100644
index 0000000000..4f4184a0a9
--- /dev/null
+++ b/internal/test/parameters/gin/server.go
@@ -0,0 +1,44 @@
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../parameters.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../parameters.yaml
+
+package ginparams
+
+import (
+ "net/http"
+
+ "github.com/gin-gonic/gin"
+
+ gen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/gin/gen"
+)
+
+type Server struct{}
+
+var _ gen.ServerInterface = (*Server)(nil)
+
+func (s *Server) GetContentObject(c *gin.Context, param gen.ComplexObject) { c.JSON(http.StatusOK, param) }
+func (s *Server) GetCookie(c *gin.Context, params gen.GetCookieParams) { c.JSON(http.StatusOK, params) }
+func (s *Server) EnumParams(c *gin.Context, params gen.EnumParamsParams) { c.Status(http.StatusNoContent) }
+func (s *Server) GetHeader(c *gin.Context, params gen.GetHeaderParams) { c.JSON(http.StatusOK, params) }
+func (s *Server) GetLabelExplodeArray(c *gin.Context, param []int32) { c.JSON(http.StatusOK, param) }
+func (s *Server) GetLabelExplodeObject(c *gin.Context, param gen.Object) { c.JSON(http.StatusOK, param) }
+func (s *Server) GetLabelExplodePrimitive(c *gin.Context, param int32) { c.JSON(http.StatusOK, param) }
+func (s *Server) GetLabelNoExplodeArray(c *gin.Context, param []int32) { c.JSON(http.StatusOK, param) }
+func (s *Server) GetLabelNoExplodeObject(c *gin.Context, param gen.Object) { c.JSON(http.StatusOK, param) }
+func (s *Server) GetLabelPrimitive(c *gin.Context, param int32) { c.JSON(http.StatusOK, param) }
+func (s *Server) GetMatrixExplodeArray(c *gin.Context, id []int32) { c.JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixExplodeObject(c *gin.Context, id gen.Object) { c.JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixExplodePrimitive(c *gin.Context, id int32) { c.JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixNoExplodeArray(c *gin.Context, id []int32) { c.JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixNoExplodeObject(c *gin.Context, id gen.Object) { c.JSON(http.StatusOK, id) }
+func (s *Server) GetMatrixPrimitive(c *gin.Context, id int32) { c.JSON(http.StatusOK, id) }
+func (s *Server) GetPassThrough(c *gin.Context, param string) { c.JSON(http.StatusOK, param) }
+func (s *Server) GetDeepObject(c *gin.Context, params gen.GetDeepObjectParams) { c.JSON(http.StatusOK, params) }
+func (s *Server) GetQueryDelimited(c *gin.Context, params gen.GetQueryDelimitedParams) { c.JSON(http.StatusOK, params) }
+func (s *Server) GetQueryForm(c *gin.Context, params gen.GetQueryFormParams) { c.JSON(http.StatusOK, params) }
+func (s *Server) GetSimpleExplodeArray(c *gin.Context, param []int32) { c.JSON(http.StatusOK, param) }
+func (s *Server) GetSimpleExplodeObject(c *gin.Context, param gen.Object) { c.JSON(http.StatusOK, param) }
+func (s *Server) GetSimpleExplodePrimitive(c *gin.Context, param int32) { c.JSON(http.StatusOK, param) }
+func (s *Server) GetSimpleNoExplodeArray(c *gin.Context, param []int32) { c.JSON(http.StatusOK, param) }
+func (s *Server) GetSimpleNoExplodeObject(c *gin.Context, param gen.Object) { c.JSON(http.StatusOK, param) }
+func (s *Server) GetSimplePrimitive(c *gin.Context, param int32) { c.JSON(http.StatusOK, param) }
+func (s *Server) GetStartingWithNumber(c *gin.Context, n1param string) { c.JSON(http.StatusOK, n1param) }
diff --git a/internal/test/parameters/gin/types.cfg.yaml b/internal/test/parameters/gin/types.cfg.yaml
new file mode 100644
index 0000000000..3f7932b307
--- /dev/null
+++ b/internal/test/parameters/gin/types.cfg.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: ginparamsgen
+generate:
+ models: true
+output: gen/types.gen.go
diff --git a/internal/test/parameters/gorilla/gen/server.gen.go b/internal/test/parameters/gorilla/gen/server.gen.go
new file mode 100644
index 0000000000..489209ea0a
--- /dev/null
+++ b/internal/test/parameters/gorilla/gen/server.gen.go
@@ -0,0 +1,1517 @@
+// Package gorillaparamsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package gorillaparamsgen
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/gorilla/mux"
+ "github.com/oapi-codegen/runtime"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /contentObject/{param})
+ GetContentObject(w http.ResponseWriter, r *http.Request, param ComplexObject)
+
+ // (GET /cookie)
+ GetCookie(w http.ResponseWriter, r *http.Request, params GetCookieParams)
+
+ // (GET /enums)
+ EnumParams(w http.ResponseWriter, r *http.Request, params EnumParamsParams)
+
+ // (GET /header)
+ GetHeader(w http.ResponseWriter, r *http.Request, params GetHeaderParams)
+
+ // (GET /labelExplodeArray/{.param*})
+ GetLabelExplodeArray(w http.ResponseWriter, r *http.Request, param []int32)
+
+ // (GET /labelExplodeObject/{.param*})
+ GetLabelExplodeObject(w http.ResponseWriter, r *http.Request, param Object)
+
+ // (GET /labelExplodePrimitive/{.param*})
+ GetLabelExplodePrimitive(w http.ResponseWriter, r *http.Request, param int32)
+
+ // (GET /labelNoExplodeArray/{.param})
+ GetLabelNoExplodeArray(w http.ResponseWriter, r *http.Request, param []int32)
+
+ // (GET /labelNoExplodeObject/{.param})
+ GetLabelNoExplodeObject(w http.ResponseWriter, r *http.Request, param Object)
+
+ // (GET /labelPrimitive/{.param})
+ GetLabelPrimitive(w http.ResponseWriter, r *http.Request, param int32)
+
+ // (GET /matrixExplodeArray/{.id*})
+ GetMatrixExplodeArray(w http.ResponseWriter, r *http.Request, id []int32)
+
+ // (GET /matrixExplodeObject/{.id*})
+ GetMatrixExplodeObject(w http.ResponseWriter, r *http.Request, id Object)
+
+ // (GET /matrixExplodePrimitive/{;id*})
+ GetMatrixExplodePrimitive(w http.ResponseWriter, r *http.Request, id int32)
+
+ // (GET /matrixNoExplodeArray/{.id})
+ GetMatrixNoExplodeArray(w http.ResponseWriter, r *http.Request, id []int32)
+
+ // (GET /matrixNoExplodeObject/{.id})
+ GetMatrixNoExplodeObject(w http.ResponseWriter, r *http.Request, id Object)
+
+ // (GET /matrixPrimitive/{;id})
+ GetMatrixPrimitive(w http.ResponseWriter, r *http.Request, id int32)
+
+ // (GET /passThrough/{param})
+ GetPassThrough(w http.ResponseWriter, r *http.Request, param string)
+
+ // (GET /queryDeepObject)
+ GetDeepObject(w http.ResponseWriter, r *http.Request, params GetDeepObjectParams)
+
+ // (GET /queryDelimited)
+ GetQueryDelimited(w http.ResponseWriter, r *http.Request, params GetQueryDelimitedParams)
+
+ // (GET /queryForm)
+ GetQueryForm(w http.ResponseWriter, r *http.Request, params GetQueryFormParams)
+
+ // (GET /simpleExplodeArray/{param*})
+ GetSimpleExplodeArray(w http.ResponseWriter, r *http.Request, param []int32)
+
+ // (GET /simpleExplodeObject/{param*})
+ GetSimpleExplodeObject(w http.ResponseWriter, r *http.Request, param Object)
+
+ // (GET /simpleExplodePrimitive/{param})
+ GetSimpleExplodePrimitive(w http.ResponseWriter, r *http.Request, param int32)
+
+ // (GET /simpleNoExplodeArray/{param})
+ GetSimpleNoExplodeArray(w http.ResponseWriter, r *http.Request, param []int32)
+
+ // (GET /simpleNoExplodeObject/{param})
+ GetSimpleNoExplodeObject(w http.ResponseWriter, r *http.Request, param Object)
+
+ // (GET /simplePrimitive/{param})
+ GetSimplePrimitive(w http.ResponseWriter, r *http.Request, param int32)
+
+ // (GET /startingWithNumber/{1param})
+ GetStartingWithNumber(w http.ResponseWriter, r *http.Request, n1param string)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetContentObject operation middleware
+func (siw *ServerInterfaceWrapper) GetContentObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param ComplexObject
+
+ err = json.Unmarshal([]byte(mux.Vars(r)["param"]), ¶m)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetContentObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetCookie operation middleware
+func (siw *ServerInterfaceWrapper) GetCookie(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetCookieParams
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("p"); err == nil {
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "p", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "p", Err: err})
+ return
+ }
+ params.P = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("ep"); err == nil {
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ep", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ep", Err: err})
+ return
+ }
+ params.Ep = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("ea"); err == nil {
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ea", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ea", Err: err})
+ return
+ }
+ params.Ea = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("a"); err == nil {
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "a", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "a", Err: err})
+ return
+ }
+ params.A = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("eo"); err == nil {
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "eo", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "eo", Err: err})
+ return
+ }
+ params.Eo = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("o"); err == nil {
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "o", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "o", Err: err})
+ return
+ }
+ params.O = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("co"); err == nil {
+ var value ComplexObject
+ var decoded string
+ decoded, err := url.QueryUnescape(cookie.Value)
+ if err != nil {
+ err = fmt.Errorf("Error unescaping cookie parameter 'co'")
+ siw.ErrorHandlerFunc(w, r, &UnescapedCookieParamError{ParamName: "co", Err: err})
+ return
+ }
+
+ err = json.Unmarshal([]byte(decoded), &value)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "co", Err: err})
+ return
+ }
+
+ params.Co = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("1s"); err == nil {
+ var value string
+ err = runtime.BindStyledParameterWithOptions("simple", "1s", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "1s", Err: err})
+ return
+ }
+ params.N1s = &value
+
+ }
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetCookie(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// EnumParams operation middleware
+func (siw *ServerInterfaceWrapper) EnumParams(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params EnumParamsParams
+
+ // ------------- Optional query parameter "enumPathParam" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "enumPathParam", r.URL.Query(), ¶ms.EnumPathParam, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "enumPathParam"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "enumPathParam", Err: err})
+ }
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.EnumParams(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetHeader operation middleware
+func (siw *ServerInterfaceWrapper) GetHeader(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetHeaderParams
+
+ headers := r.Header
+
+ // ------------- Optional header parameter "X-Primitive" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive")]; found {
+ var XPrimitive int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Primitive", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive", valueList[0], &XPrimitive, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Primitive", Err: err})
+ return
+ }
+
+ params.XPrimitive = &XPrimitive
+
+ }
+
+ // ------------- Optional header parameter "X-Primitive-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive-Exploded")]; found {
+ var XPrimitiveExploded int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Primitive-Exploded", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive-Exploded", valueList[0], &XPrimitiveExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Primitive-Exploded", Err: err})
+ return
+ }
+
+ params.XPrimitiveExploded = &XPrimitiveExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Array-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array-Exploded")]; found {
+ var XArrayExploded []int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Array-Exploded", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array-Exploded", valueList[0], &XArrayExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Array-Exploded", Err: err})
+ return
+ }
+
+ params.XArrayExploded = &XArrayExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Array" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array")]; found {
+ var XArray []int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Array", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array", valueList[0], &XArray, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Array", Err: err})
+ return
+ }
+
+ params.XArray = &XArray
+
+ }
+
+ // ------------- Optional header parameter "X-Object-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object-Exploded")]; found {
+ var XObjectExploded Object
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Object-Exploded", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object-Exploded", valueList[0], &XObjectExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Object-Exploded", Err: err})
+ return
+ }
+
+ params.XObjectExploded = &XObjectExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object")]; found {
+ var XObject Object
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Object", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object", valueList[0], &XObject, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Object", Err: err})
+ return
+ }
+
+ params.XObject = &XObject
+
+ }
+
+ // ------------- Optional header parameter "X-Complex-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Complex-Object")]; found {
+ var XComplexObject ComplexObject
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Complex-Object", Count: n})
+ return
+ }
+
+ err = json.Unmarshal([]byte(valueList[0]), &XComplexObject)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "X-Complex-Object", Err: err})
+ return
+ }
+
+ params.XComplexObject = &XComplexObject
+
+ }
+
+ // ------------- Optional header parameter "1-Starting-With-Number" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("1-Starting-With-Number")]; found {
+ var N1StartingWithNumber string
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "1-Starting-With-Number", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "1-Starting-With-Number", valueList[0], &N1StartingWithNumber, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "1-Starting-With-Number", Err: err})
+ return
+ }
+
+ params.N1StartingWithNumber = &N1StartingWithNumber
+
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetHeader(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", mux.Vars(r)["param"], ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelExplodeArray(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", mux.Vars(r)["param"], ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelExplodeObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodePrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", mux.Vars(r)["param"], ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelExplodePrimitive(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelNoExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", mux.Vars(r)["param"], ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelNoExplodeArray(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelNoExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", mux.Vars(r)["param"], ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelNoExplodeObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelPrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelPrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", mux.Vars(r)["param"], ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelPrimitive(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", mux.Vars(r)["id"], &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixExplodeArray(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", mux.Vars(r)["id"], &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixExplodeObject(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodePrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", mux.Vars(r)["id"], &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixExplodePrimitive(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixNoExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", mux.Vars(r)["id"], &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixNoExplodeArray(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixNoExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", mux.Vars(r)["id"], &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixNoExplodeObject(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixPrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixPrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", mux.Vars(r)["id"], &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixPrimitive(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetPassThrough operation middleware
+func (siw *ServerInterfaceWrapper) GetPassThrough(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param string
+
+ param = mux.Vars(r)["param"]
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetPassThrough(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetDeepObject operation middleware
+func (siw *ServerInterfaceWrapper) GetDeepObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetDeepObjectParams
+
+ // ------------- Required query parameter "deepObj" -------------
+
+ err = runtime.BindQueryParameterWithOptions("deepObject", true, true, "deepObj", r.URL.Query(), ¶ms.DeepObj, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "deepObj"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "deepObj", Err: err})
+ }
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetDeepObject(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetQueryDelimited operation middleware
+func (siw *ServerInterfaceWrapper) GetQueryDelimited(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryDelimitedParams
+
+ // ------------- Optional query parameter "sa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("spaceDelimited", false, false, "sa", r.URL.Query(), ¶ms.Sa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "sa"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "sa", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "pa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("pipeDelimited", false, false, "pa", r.URL.Query(), ¶ms.Pa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "pa"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "pa", Err: err})
+ }
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetQueryDelimited(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetQueryForm operation middleware
+func (siw *ServerInterfaceWrapper) GetQueryForm(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryFormParams
+
+ // ------------- Optional query parameter "ea" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ea", r.URL.Query(), ¶ms.Ea, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "ea"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ea", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "a" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "a", r.URL.Query(), ¶ms.A, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "a"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "a", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "eo" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "eo", r.URL.Query(), ¶ms.Eo, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "eo"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "eo", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "o" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "o", r.URL.Query(), ¶ms.O, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "o"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "o", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "ep" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ep", r.URL.Query(), ¶ms.Ep, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "ep"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ep", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "p" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "p", r.URL.Query(), ¶ms.P, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "p"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "p", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "ps" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ps", r.URL.Query(), ¶ms.Ps, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "ps"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ps", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "co" -------------
+
+ if paramValue := r.URL.Query().Get("co"); paramValue != "" {
+
+ var value ComplexObject
+ err = json.Unmarshal([]byte(paramValue), &value)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "co", Err: err})
+ return
+ }
+
+ params.Co = &value
+
+ }
+
+ // ------------- Optional query parameter "1s" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "1s", r.URL.Query(), ¶ms.N1s, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "1s"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "1s", Err: err})
+ }
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetQueryForm(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", mux.Vars(r)["param"], ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleExplodeArray(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", mux.Vars(r)["param"], ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleExplodeObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodePrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", mux.Vars(r)["param"], ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleExplodePrimitive(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleNoExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", mux.Vars(r)["param"], ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleNoExplodeArray(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleNoExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", mux.Vars(r)["param"], ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleNoExplodeObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimplePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetSimplePrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", mux.Vars(r)["param"], ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimplePrimitive(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetStartingWithNumber operation middleware
+func (siw *ServerInterfaceWrapper) GetStartingWithNumber(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "1param" -------------
+ var n1param string
+
+ n1param = mux.Vars(r)["1param"]
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetStartingWithNumber(w, r, n1param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{})
+}
+
+type GorillaServerOptions struct {
+ BaseURL string
+ BaseRouter *mux.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r *mux.Router) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r *mux.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, GorillaServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = mux.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.HandleFunc(options.BaseURL+"/contentObject/{param}", wrapper.GetContentObject).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/cookie", wrapper.GetCookie).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/enums", wrapper.EnumParams).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/header", wrapper.GetHeader).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/labelExplodeArray/{param}", wrapper.GetLabelExplodeArray).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/labelExplodeObject/{param}", wrapper.GetLabelExplodeObject).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/labelExplodePrimitive/{param}", wrapper.GetLabelExplodePrimitive).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/labelNoExplodeArray/{param}", wrapper.GetLabelNoExplodeArray).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/labelNoExplodeObject/{param}", wrapper.GetLabelNoExplodeObject).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/labelPrimitive/{param}", wrapper.GetLabelPrimitive).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/matrixExplodeArray/{id}", wrapper.GetMatrixExplodeArray).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/matrixExplodeObject/{id}", wrapper.GetMatrixExplodeObject).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/matrixExplodePrimitive/{id}", wrapper.GetMatrixExplodePrimitive).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/matrixNoExplodeArray/{id}", wrapper.GetMatrixNoExplodeArray).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/matrixNoExplodeObject/{id}", wrapper.GetMatrixNoExplodeObject).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/matrixPrimitive/{id}", wrapper.GetMatrixPrimitive).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/passThrough/{param}", wrapper.GetPassThrough).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/queryDeepObject", wrapper.GetDeepObject).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/queryDelimited", wrapper.GetQueryDelimited).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/queryForm", wrapper.GetQueryForm).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/simpleExplodeArray/{param}", wrapper.GetSimpleExplodeArray).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/simpleExplodeObject/{param}", wrapper.GetSimpleExplodeObject).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/simpleExplodePrimitive/{param}", wrapper.GetSimpleExplodePrimitive).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/simpleNoExplodeArray/{param}", wrapper.GetSimpleNoExplodeArray).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/simpleNoExplodeObject/{param}", wrapper.GetSimpleNoExplodeObject).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/simplePrimitive/{param}", wrapper.GetSimplePrimitive).Methods(http.MethodGet)
+
+ r.HandleFunc(options.BaseURL+"/startingWithNumber/{1param}", wrapper.GetStartingWithNumber).Methods(http.MethodGet)
+
+ return r
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "3FpLb+M2F/0rwv2+VaFYdqYrdRVMp22ATiatA0yBIAtGuo44lUQOSacJDP33gpRkPa2HLeXRXWJd3sch",
+ "z6F4qR14LOIsxlhJcHcgUHIWSzT/rGnEQ/wz+0n/4rFYYaz0nwqflMNDQmP9n/QCjIj5/ZkjuCCVoPED",
+ "JElig4/SE5QrymJw4cKSxq+Vx7LY/Tf0FGjT1I+J/pFpq6cv6UN3B1wwjkLRNLlLvxSNxgofUEBiw6W8",
+ "8KM0qezhPWMhklg/LJz9X+AGXPifU9TvZMGdL0U+Ar9vqUAf3Nt8sK1DF3HuKm6rOW6okOqKRNgCjA2C",
+ "hW0PalGNlV1ydWcwpfGG6cEh9TCbnNgEgs+XN9q7okq7hxuUylqjeEQBNjyikOk0rBbLxVIbMo4x4RRc",
+ "+LBYLlZgAycqMPk72Xyn9Tk7TgSJEv3kAU25ulii51XPBvyK6mN5gHElSIQKhQT3trJ+COch9cxg55tk",
+ "tVXUNT3VhZGhAa5JG+wcBhMZylgqscXkzq6u8fPl8lC8vZ1TI0JiYjoeY39T7EbDWDRgqBKCCxpRRR+1",
+ "IT7xkPkI7oaEErPCvNxNXhrYJag2TEREpST4cA52gxOJPSiihudAQDw5YhbFt4gQ5HloWFIJSxVGclD8",
+ "/S9ptJZ8Gml04T1fGntYWE6YQbiwSkLDpKweuhmxC4LjIs5F92olXmpQYNhagcegCYJ+ZklFhKLxg/UP",
+ "VYEVb6N7I5WtXlayAkRduuvq4uOGbEN1rMJgvE2XWqvAfIq30bUWFtmnMNf5w7RE7dZ6JOEWZV7n9y2K",
+ "59IKM65VcJ2JaFGxfgLu7Wq5tM+Xyzt7gBg0JffHFJvKTDArXy1Z8QESH0WXvP6WWpwqr0HuJiv+r7Pr",
+ "0pBZhbYj9NmnTBteRHqbiVxo6/YkXkyID2T1ynLczCrVpnaw5lDnQxm8O5FuFpI5ygs6QrLrPldn68z6",
+ "7CtVwdlVbv1iMh6SewyzxWEWsLNbGMn6ofNd+vf6sKbStS3PIa/B0xDIBqmezSHDVAhTvlyXMcuPH2NB",
+ "O3QKmQK1Iex6KXz2e8Z4iMo73QwoDVhSM0N0xdqI149PdVwHOmVd/g9Rb19/lXwjgOtl3ynIvQn6NXjX",
+ "j84Qvp2Cy6sSLiJK0Kca36jfrUafG4OOkSLqz060tLr5ANsTbRRix+9xPZCNY9jc4JSo9tMofE7a4Hog",
+ "GkG22fBp7G/UHwDOBLvbe2Zcc3Mbh9oJW9v7YF2VbgOgOW1fe9M840TKm0Cw7UMw5AbkujDvvP8YcX/2",
+ "KrcbpiP4MyIvLrcOlVyy6unF+Yi8u7lSa0T6qeujOVPrSxQLxS9ynvq4nyEXakag3wXcH1XLHvAkJx5a",
+ "fm5udbbOajjKqe4wCgRNOkXyLc1Pyo9Nl0+frs6mlO3UTPmFiah3qo1RzywPatfW2/XTw6WHwsh2bS2r",
+ "F0tqWNu2jtn8l2i1iFME3Jfad7NQr3aeO+MuCk8W0Mr2wgNxum/kXrnBXUv2uEvImpORd5AnKFv6oU71",
+ "gDGgwbhuDHu7neu0RJgNtcqnMyNgezu967kRKp01+t+u160jX715PRtG9eP9UITeTft6fuSGf7y2bhv4",
+ "JhrYs6F0BPk6WPceaZbtu1+pCtKbYWe3GgBFY9iMh/3VzKd9jbD5QDTNeytCcCFQiruOk30dqlCqhT4z",
+ "R4QvCIXkLvk3AAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/parameters/gorilla/gen/types.gen.go b/internal/test/parameters/gorilla/gen/types.gen.go
new file mode 100644
index 0000000000..b7a27e4096
--- /dev/null
+++ b/internal/test/parameters/gorilla/gen/types.gen.go
@@ -0,0 +1,143 @@
+// Package gorillaparamsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package gorillaparamsgen
+
+// Defines values for EnumParamsParamsEnumPathParam.
+const (
+ N100 EnumParamsParamsEnumPathParam = 100
+ N200 EnumParamsParamsEnumPathParam = 200
+)
+
+// Valid indicates whether the value is a known member of the EnumParamsParamsEnumPathParam enum.
+func (e EnumParamsParamsEnumPathParam) Valid() bool {
+ switch e {
+ case N100:
+ return true
+ case N200:
+ return true
+ default:
+ return false
+ }
+}
+
+// ComplexObject defines model for ComplexObject.
+type ComplexObject struct {
+ Id int `json:"Id"`
+ IsAdmin bool `json:"IsAdmin"`
+ Object Object `json:"Object"`
+}
+
+// Object defines model for Object.
+type Object struct {
+ FirstName string `json:"firstName"`
+ Role string `json:"role"`
+}
+
+// GetCookieParams defines parameters for GetCookie.
+type GetCookieParams struct {
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ep primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
+
+// EnumParamsParams defines parameters for EnumParams.
+type EnumParamsParams struct {
+ // EnumPathParam Parameter with enum values
+ EnumPathParam *EnumParamsParamsEnumPathParam `form:"enumPathParam,omitempty" json:"enumPathParam,omitempty"`
+}
+
+// EnumParamsParamsEnumPathParam defines parameters for EnumParams.
+type EnumParamsParamsEnumPathParam int32
+
+// GetHeaderParams defines parameters for GetHeader.
+type GetHeaderParams struct {
+ // XPrimitive primitive
+ XPrimitive *int32 `json:"X-Primitive,omitempty"`
+
+ // XPrimitiveExploded primitive
+ XPrimitiveExploded *int32 `json:"X-Primitive-Exploded,omitempty"`
+
+ // XArrayExploded exploded array
+ XArrayExploded *[]int32 `json:"X-Array-Exploded,omitempty"`
+
+ // XArray array
+ XArray *[]int32 `json:"X-Array,omitempty"`
+
+ // XObjectExploded exploded object
+ XObjectExploded *Object `json:"X-Object-Exploded,omitempty"`
+
+ // XObject object
+ XObject *Object `json:"X-Object,omitempty"`
+
+ // XComplexObject complex object
+ XComplexObject *ComplexObject `json:"X-Complex-Object,omitempty"`
+
+ // N1StartingWithNumber name starting with number
+ N1StartingWithNumber *string `json:"1-Starting-With-Number,omitempty"`
+}
+
+// GetDeepObjectParams defines parameters for GetDeepObject.
+type GetDeepObjectParams struct {
+ // DeepObj deep object
+ DeepObj ComplexObject `json:"deepObj"`
+}
+
+// GetQueryDelimitedParams defines parameters for GetQueryDelimited.
+type GetQueryDelimitedParams struct {
+ // Sa space delimited array
+ Sa *[]int32 `json:"sa,omitempty"`
+
+ // Pa pipe delimited array
+ Pa *[]int32 `json:"pa,omitempty"`
+}
+
+// GetQueryFormParams defines parameters for GetQueryForm.
+type GetQueryFormParams struct {
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Ep exploded primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ps primitive string
+ Ps *string `form:"ps,omitempty" json:"ps,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
diff --git a/internal/test/parameters/gorilla/server.cfg.yaml b/internal/test/parameters/gorilla/server.cfg.yaml
new file mode 100644
index 0000000000..cf492d30ec
--- /dev/null
+++ b/internal/test/parameters/gorilla/server.cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: gorillaparamsgen
+generate:
+ gorilla-server: true
+ embedded-spec: true
+output: gen/server.gen.go
diff --git a/internal/test/parameters/gorilla/server.go b/internal/test/parameters/gorilla/server.go
new file mode 100644
index 0000000000..afdde25e25
--- /dev/null
+++ b/internal/test/parameters/gorilla/server.go
@@ -0,0 +1,48 @@
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../parameters.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../parameters.yaml
+
+package gorillaparams
+
+import (
+ "encoding/json"
+ "net/http"
+
+ gen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/gorilla/gen"
+)
+
+type Server struct{}
+
+var _ gen.ServerInterface = (*Server)(nil)
+
+func writeJSON(w http.ResponseWriter, v interface{}) {
+ w.Header().Set("Content-Type", "application/json")
+ _ = json.NewEncoder(w).Encode(v)
+}
+
+func (s *Server) GetContentObject(w http.ResponseWriter, r *http.Request, param gen.ComplexObject) { writeJSON(w, param) }
+func (s *Server) GetCookie(w http.ResponseWriter, r *http.Request, params gen.GetCookieParams) { writeJSON(w, params) }
+func (s *Server) EnumParams(w http.ResponseWriter, r *http.Request, params gen.EnumParamsParams) { w.WriteHeader(http.StatusNoContent) }
+func (s *Server) GetHeader(w http.ResponseWriter, r *http.Request, params gen.GetHeaderParams) { writeJSON(w, params) }
+func (s *Server) GetLabelExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) { writeJSON(w, param) }
+func (s *Server) GetLabelExplodeObject(w http.ResponseWriter, r *http.Request, param gen.Object) { writeJSON(w, param) }
+func (s *Server) GetLabelExplodePrimitive(w http.ResponseWriter, r *http.Request, param int32) { writeJSON(w, param) }
+func (s *Server) GetLabelNoExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) { writeJSON(w, param) }
+func (s *Server) GetLabelNoExplodeObject(w http.ResponseWriter, r *http.Request, param gen.Object) { writeJSON(w, param) }
+func (s *Server) GetLabelPrimitive(w http.ResponseWriter, r *http.Request, param int32) { writeJSON(w, param) }
+func (s *Server) GetMatrixExplodeArray(w http.ResponseWriter, r *http.Request, id []int32) { writeJSON(w, id) }
+func (s *Server) GetMatrixExplodeObject(w http.ResponseWriter, r *http.Request, id gen.Object) { writeJSON(w, id) }
+func (s *Server) GetMatrixExplodePrimitive(w http.ResponseWriter, r *http.Request, id int32) { writeJSON(w, id) }
+func (s *Server) GetMatrixNoExplodeArray(w http.ResponseWriter, r *http.Request, id []int32) { writeJSON(w, id) }
+func (s *Server) GetMatrixNoExplodeObject(w http.ResponseWriter, r *http.Request, id gen.Object) { writeJSON(w, id) }
+func (s *Server) GetMatrixPrimitive(w http.ResponseWriter, r *http.Request, id int32) { writeJSON(w, id) }
+func (s *Server) GetPassThrough(w http.ResponseWriter, r *http.Request, param string) { writeJSON(w, param) }
+func (s *Server) GetDeepObject(w http.ResponseWriter, r *http.Request, params gen.GetDeepObjectParams) { writeJSON(w, params) }
+func (s *Server) GetQueryDelimited(w http.ResponseWriter, r *http.Request, params gen.GetQueryDelimitedParams) { writeJSON(w, params) }
+func (s *Server) GetQueryForm(w http.ResponseWriter, r *http.Request, params gen.GetQueryFormParams) { writeJSON(w, params) }
+func (s *Server) GetSimpleExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) { writeJSON(w, param) }
+func (s *Server) GetSimpleExplodeObject(w http.ResponseWriter, r *http.Request, param gen.Object) { writeJSON(w, param) }
+func (s *Server) GetSimpleExplodePrimitive(w http.ResponseWriter, r *http.Request, param int32) { writeJSON(w, param) }
+func (s *Server) GetSimpleNoExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) { writeJSON(w, param) }
+func (s *Server) GetSimpleNoExplodeObject(w http.ResponseWriter, r *http.Request, param gen.Object) { writeJSON(w, param) }
+func (s *Server) GetSimplePrimitive(w http.ResponseWriter, r *http.Request, param int32) { writeJSON(w, param) }
+func (s *Server) GetStartingWithNumber(w http.ResponseWriter, r *http.Request, n1param string) { writeJSON(w, n1param) }
diff --git a/internal/test/parameters/gorilla/types.cfg.yaml b/internal/test/parameters/gorilla/types.cfg.yaml
new file mode 100644
index 0000000000..9e2fcd7c3b
--- /dev/null
+++ b/internal/test/parameters/gorilla/types.cfg.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: gorillaparamsgen
+generate:
+ models: true
+output: gen/types.gen.go
diff --git a/internal/test/parameters/iris/gen/server.gen.go b/internal/test/parameters/iris/gen/server.gen.go
new file mode 100644
index 0000000000..2da66aeedf
--- /dev/null
+++ b/internal/test/parameters/iris/gen/server.gen.go
@@ -0,0 +1,1153 @@
+// Package irisparamsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package irisparamsgen
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/kataras/iris/v12"
+ "github.com/oapi-codegen/runtime"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /contentObject/{param})
+ GetContentObject(ctx iris.Context, param ComplexObject)
+
+ // (GET /cookie)
+ GetCookie(ctx iris.Context, params GetCookieParams)
+
+ // (GET /enums)
+ EnumParams(ctx iris.Context, params EnumParamsParams)
+
+ // (GET /header)
+ GetHeader(ctx iris.Context, params GetHeaderParams)
+
+ // (GET /labelExplodeArray/{.param*})
+ GetLabelExplodeArray(ctx iris.Context, param []int32)
+
+ // (GET /labelExplodeObject/{.param*})
+ GetLabelExplodeObject(ctx iris.Context, param Object)
+
+ // (GET /labelExplodePrimitive/{.param*})
+ GetLabelExplodePrimitive(ctx iris.Context, param int32)
+
+ // (GET /labelNoExplodeArray/{.param})
+ GetLabelNoExplodeArray(ctx iris.Context, param []int32)
+
+ // (GET /labelNoExplodeObject/{.param})
+ GetLabelNoExplodeObject(ctx iris.Context, param Object)
+
+ // (GET /labelPrimitive/{.param})
+ GetLabelPrimitive(ctx iris.Context, param int32)
+
+ // (GET /matrixExplodeArray/{.id*})
+ GetMatrixExplodeArray(ctx iris.Context, id []int32)
+
+ // (GET /matrixExplodeObject/{.id*})
+ GetMatrixExplodeObject(ctx iris.Context, id Object)
+
+ // (GET /matrixExplodePrimitive/{;id*})
+ GetMatrixExplodePrimitive(ctx iris.Context, id int32)
+
+ // (GET /matrixNoExplodeArray/{.id})
+ GetMatrixNoExplodeArray(ctx iris.Context, id []int32)
+
+ // (GET /matrixNoExplodeObject/{.id})
+ GetMatrixNoExplodeObject(ctx iris.Context, id Object)
+
+ // (GET /matrixPrimitive/{;id})
+ GetMatrixPrimitive(ctx iris.Context, id int32)
+
+ // (GET /passThrough/{param})
+ GetPassThrough(ctx iris.Context, param string)
+
+ // (GET /queryDeepObject)
+ GetDeepObject(ctx iris.Context, params GetDeepObjectParams)
+
+ // (GET /queryDelimited)
+ GetQueryDelimited(ctx iris.Context, params GetQueryDelimitedParams)
+
+ // (GET /queryForm)
+ GetQueryForm(ctx iris.Context, params GetQueryFormParams)
+
+ // (GET /simpleExplodeArray/{param*})
+ GetSimpleExplodeArray(ctx iris.Context, param []int32)
+
+ // (GET /simpleExplodeObject/{param*})
+ GetSimpleExplodeObject(ctx iris.Context, param Object)
+
+ // (GET /simpleExplodePrimitive/{param})
+ GetSimpleExplodePrimitive(ctx iris.Context, param int32)
+
+ // (GET /simpleNoExplodeArray/{param})
+ GetSimpleNoExplodeArray(ctx iris.Context, param []int32)
+
+ // (GET /simpleNoExplodeObject/{param})
+ GetSimpleNoExplodeObject(ctx iris.Context, param Object)
+
+ // (GET /simplePrimitive/{param})
+ GetSimplePrimitive(ctx iris.Context, param int32)
+
+ // (GET /startingWithNumber/{1param})
+ GetStartingWithNumber(ctx iris.Context, n1param string)
+}
+
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+type MiddlewareFunc iris.Handler
+
+// GetContentObject converts iris context to params.
+func (w *ServerInterfaceWrapper) GetContentObject(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param ComplexObject
+
+ err = json.Unmarshal([]byte(ctx.Params().Get("param")), ¶m)
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.WriteString("Error unmarshaling parameter 'param' as JSON")
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetContentObject(ctx, param)
+}
+
+// GetCookie converts iris context to params.
+func (w *ServerInterfaceWrapper) GetCookie(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetCookieParams
+
+ if cookie := ctx.GetCookie("p"); cookie != "" {
+
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "p", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter p: %s", err)
+ return
+ }
+ params.P = &value
+
+ }
+
+ if cookie := ctx.GetCookie("ep"); cookie != "" {
+
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ep", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter ep: %s", err)
+ return
+ }
+ params.Ep = &value
+
+ }
+
+ if cookie := ctx.GetCookie("ea"); cookie != "" {
+
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ea", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter ea: %s", err)
+ return
+ }
+ params.Ea = &value
+
+ }
+
+ if cookie := ctx.GetCookie("a"); cookie != "" {
+
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "a", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter a: %s", err)
+ return
+ }
+ params.A = &value
+
+ }
+
+ if cookie := ctx.GetCookie("eo"); cookie != "" {
+
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "eo", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter eo: %s", err)
+ return
+ }
+ params.Eo = &value
+
+ }
+
+ if cookie := ctx.GetCookie("o"); cookie != "" {
+
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "o", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter o: %s", err)
+ return
+ }
+ params.O = &value
+
+ }
+
+ if cookie := ctx.GetCookie("co"); cookie != "" {
+
+ var value ComplexObject
+ var decoded string
+ decoded, err := url.QueryUnescape(cookie)
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.WriteString("Error unescaping cookie parameter 'co'")
+ return
+ }
+ err = json.Unmarshal([]byte(decoded), &value)
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.WriteString("Error unmarshaling parameter 'co' as JSON")
+ return
+ }
+ params.Co = &value
+
+ }
+
+ if cookie := ctx.GetCookie("1s"); cookie != "" {
+
+ var value string
+ err = runtime.BindStyledParameterWithOptions("simple", "1s", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter 1s: %s", err)
+ return
+ }
+ params.N1s = &value
+
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetCookie(ctx, params)
+}
+
+// EnumParams converts iris context to params.
+func (w *ServerInterfaceWrapper) EnumParams(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params EnumParamsParams
+ // ------------- Optional query parameter "enumPathParam" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "enumPathParam", ctx.Request().URL.Query(), ¶ms.EnumPathParam, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter enumPathParam: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.EnumParams(ctx, params)
+}
+
+// GetHeader converts iris context to params.
+func (w *ServerInterfaceWrapper) GetHeader(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetHeaderParams
+
+ headers := ctx.Request().Header
+ // ------------- Optional header parameter "X-Primitive" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive")]; found {
+ var XPrimitive int32
+ n := len(valueList)
+ if n != 1 {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Expected one value for X-Primitive, got %d", n)
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive", valueList[0], &XPrimitive, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter X-Primitive: %s", err)
+ return
+ }
+
+ params.XPrimitive = &XPrimitive
+ }
+ // ------------- Optional header parameter "X-Primitive-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive-Exploded")]; found {
+ var XPrimitiveExploded int32
+ n := len(valueList)
+ if n != 1 {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Expected one value for X-Primitive-Exploded, got %d", n)
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive-Exploded", valueList[0], &XPrimitiveExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter X-Primitive-Exploded: %s", err)
+ return
+ }
+
+ params.XPrimitiveExploded = &XPrimitiveExploded
+ }
+ // ------------- Optional header parameter "X-Array-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array-Exploded")]; found {
+ var XArrayExploded []int32
+ n := len(valueList)
+ if n != 1 {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Expected one value for X-Array-Exploded, got %d", n)
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array-Exploded", valueList[0], &XArrayExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter X-Array-Exploded: %s", err)
+ return
+ }
+
+ params.XArrayExploded = &XArrayExploded
+ }
+ // ------------- Optional header parameter "X-Array" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array")]; found {
+ var XArray []int32
+ n := len(valueList)
+ if n != 1 {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Expected one value for X-Array, got %d", n)
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array", valueList[0], &XArray, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter X-Array: %s", err)
+ return
+ }
+
+ params.XArray = &XArray
+ }
+ // ------------- Optional header parameter "X-Object-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object-Exploded")]; found {
+ var XObjectExploded Object
+ n := len(valueList)
+ if n != 1 {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Expected one value for X-Object-Exploded, got %d", n)
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object-Exploded", valueList[0], &XObjectExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter X-Object-Exploded: %s", err)
+ return
+ }
+
+ params.XObjectExploded = &XObjectExploded
+ }
+ // ------------- Optional header parameter "X-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object")]; found {
+ var XObject Object
+ n := len(valueList)
+ if n != 1 {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Expected one value for X-Object, got %d", n)
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object", valueList[0], &XObject, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter X-Object: %s", err)
+ return
+ }
+
+ params.XObject = &XObject
+ }
+ // ------------- Optional header parameter "X-Complex-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Complex-Object")]; found {
+ var XComplexObject ComplexObject
+ n := len(valueList)
+ if n != 1 {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Expected one value for X-Complex-Object, got %d", n)
+ return
+ }
+
+ err = json.Unmarshal([]byte(valueList[0]), &XComplexObject)
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.WriteString("Error unmarshaling parameter 'X-Complex-Object' as JSON")
+ return
+ }
+
+ params.XComplexObject = &XComplexObject
+ }
+ // ------------- Optional header parameter "1-Starting-With-Number" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("1-Starting-With-Number")]; found {
+ var N1StartingWithNumber string
+ n := len(valueList)
+ if n != 1 {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Expected one value for 1-Starting-With-Number, got %d", n)
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "1-Starting-With-Number", valueList[0], &N1StartingWithNumber, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter 1-Starting-With-Number: %s", err)
+ return
+ }
+
+ params.N1StartingWithNumber = &N1StartingWithNumber
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetHeader(ctx, params)
+}
+
+// GetLabelExplodeArray converts iris context to params.
+func (w *ServerInterfaceWrapper) GetLabelExplodeArray(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Params().Get("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter param: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetLabelExplodeArray(ctx, param)
+}
+
+// GetLabelExplodeObject converts iris context to params.
+func (w *ServerInterfaceWrapper) GetLabelExplodeObject(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Params().Get("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter param: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetLabelExplodeObject(ctx, param)
+}
+
+// GetLabelExplodePrimitive converts iris context to params.
+func (w *ServerInterfaceWrapper) GetLabelExplodePrimitive(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Params().Get("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter param: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetLabelExplodePrimitive(ctx, param)
+}
+
+// GetLabelNoExplodeArray converts iris context to params.
+func (w *ServerInterfaceWrapper) GetLabelNoExplodeArray(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Params().Get("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter param: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetLabelNoExplodeArray(ctx, param)
+}
+
+// GetLabelNoExplodeObject converts iris context to params.
+func (w *ServerInterfaceWrapper) GetLabelNoExplodeObject(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Params().Get("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter param: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetLabelNoExplodeObject(ctx, param)
+}
+
+// GetLabelPrimitive converts iris context to params.
+func (w *ServerInterfaceWrapper) GetLabelPrimitive(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", ctx.Params().Get("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter param: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetLabelPrimitive(ctx, param)
+}
+
+// GetMatrixExplodeArray converts iris context to params.
+func (w *ServerInterfaceWrapper) GetMatrixExplodeArray(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Params().Get("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter id: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetMatrixExplodeArray(ctx, id)
+}
+
+// GetMatrixExplodeObject converts iris context to params.
+func (w *ServerInterfaceWrapper) GetMatrixExplodeObject(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Params().Get("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter id: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetMatrixExplodeObject(ctx, id)
+}
+
+// GetMatrixExplodePrimitive converts iris context to params.
+func (w *ServerInterfaceWrapper) GetMatrixExplodePrimitive(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Params().Get("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter id: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetMatrixExplodePrimitive(ctx, id)
+}
+
+// GetMatrixNoExplodeArray converts iris context to params.
+func (w *ServerInterfaceWrapper) GetMatrixNoExplodeArray(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Params().Get("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter id: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetMatrixNoExplodeArray(ctx, id)
+}
+
+// GetMatrixNoExplodeObject converts iris context to params.
+func (w *ServerInterfaceWrapper) GetMatrixNoExplodeObject(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Params().Get("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter id: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetMatrixNoExplodeObject(ctx, id)
+}
+
+// GetMatrixPrimitive converts iris context to params.
+func (w *ServerInterfaceWrapper) GetMatrixPrimitive(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", ctx.Params().Get("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter id: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetMatrixPrimitive(ctx, id)
+}
+
+// GetPassThrough converts iris context to params.
+func (w *ServerInterfaceWrapper) GetPassThrough(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param string
+
+ param = ctx.Params().Get("param")
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetPassThrough(ctx, param)
+}
+
+// GetDeepObject converts iris context to params.
+func (w *ServerInterfaceWrapper) GetDeepObject(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetDeepObjectParams
+ // ------------- Required query parameter "deepObj" -------------
+
+ err = runtime.BindQueryParameterWithOptions("deepObject", true, true, "deepObj", ctx.Request().URL.Query(), ¶ms.DeepObj, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter deepObj: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetDeepObject(ctx, params)
+}
+
+// GetQueryDelimited converts iris context to params.
+func (w *ServerInterfaceWrapper) GetQueryDelimited(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryDelimitedParams
+ // ------------- Optional query parameter "sa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("spaceDelimited", false, false, "sa", ctx.Request().URL.Query(), ¶ms.Sa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter sa: %s", err)
+ return
+ }
+
+ // ------------- Optional query parameter "pa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("pipeDelimited", false, false, "pa", ctx.Request().URL.Query(), ¶ms.Pa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter pa: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetQueryDelimited(ctx, params)
+}
+
+// GetQueryForm converts iris context to params.
+func (w *ServerInterfaceWrapper) GetQueryForm(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryFormParams
+ // ------------- Optional query parameter "ea" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ea", ctx.Request().URL.Query(), ¶ms.Ea, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter ea: %s", err)
+ return
+ }
+
+ // ------------- Optional query parameter "a" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "a", ctx.Request().URL.Query(), ¶ms.A, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter a: %s", err)
+ return
+ }
+
+ // ------------- Optional query parameter "eo" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "eo", ctx.Request().URL.Query(), ¶ms.Eo, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter eo: %s", err)
+ return
+ }
+
+ // ------------- Optional query parameter "o" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "o", ctx.Request().URL.Query(), ¶ms.O, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter o: %s", err)
+ return
+ }
+
+ // ------------- Optional query parameter "ep" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ep", ctx.Request().URL.Query(), ¶ms.Ep, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter ep: %s", err)
+ return
+ }
+
+ // ------------- Optional query parameter "p" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "p", ctx.Request().URL.Query(), ¶ms.P, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter p: %s", err)
+ return
+ }
+
+ // ------------- Optional query parameter "ps" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ps", ctx.Request().URL.Query(), ¶ms.Ps, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter ps: %s", err)
+ return
+ }
+
+ // ------------- Optional query parameter "co" -------------
+
+ if paramValue := ctx.URLParam("co"); paramValue != "" {
+
+ var value ComplexObject
+ err = json.Unmarshal([]byte(paramValue), &value)
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.WriteString("Error unmarshaling parameter 'co' as JSON")
+ return
+ }
+ params.Co = &value
+
+ }
+
+ // ------------- Optional query parameter "1s" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "1s", ctx.Request().URL.Query(), ¶ms.N1s, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter 1s: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetQueryForm(ctx, params)
+}
+
+// GetSimpleExplodeArray converts iris context to params.
+func (w *ServerInterfaceWrapper) GetSimpleExplodeArray(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Params().Get("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter param: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetSimpleExplodeArray(ctx, param)
+}
+
+// GetSimpleExplodeObject converts iris context to params.
+func (w *ServerInterfaceWrapper) GetSimpleExplodeObject(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Params().Get("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter param: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetSimpleExplodeObject(ctx, param)
+}
+
+// GetSimpleExplodePrimitive converts iris context to params.
+func (w *ServerInterfaceWrapper) GetSimpleExplodePrimitive(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Params().Get("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter param: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetSimpleExplodePrimitive(ctx, param)
+}
+
+// GetSimpleNoExplodeArray converts iris context to params.
+func (w *ServerInterfaceWrapper) GetSimpleNoExplodeArray(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Params().Get("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter param: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetSimpleNoExplodeArray(ctx, param)
+}
+
+// GetSimpleNoExplodeObject converts iris context to params.
+func (w *ServerInterfaceWrapper) GetSimpleNoExplodeObject(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Params().Get("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter param: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetSimpleNoExplodeObject(ctx, param)
+}
+
+// GetSimplePrimitive converts iris context to params.
+func (w *ServerInterfaceWrapper) GetSimplePrimitive(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", ctx.Params().Get("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ ctx.StatusCode(http.StatusBadRequest)
+ ctx.Writef("Invalid format for parameter param: %s", err)
+ return
+ }
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetSimplePrimitive(ctx, param)
+}
+
+// GetStartingWithNumber converts iris context to params.
+func (w *ServerInterfaceWrapper) GetStartingWithNumber(ctx iris.Context) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "1param" -------------
+ var n1param string
+
+ n1param = ctx.Params().Get("1param")
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.GetStartingWithNumber(ctx, n1param)
+}
+
+// IrisServerOption is the option for iris server
+type IrisServerOptions struct {
+ BaseURL string
+ Middlewares []MiddlewareFunc
+}
+
+// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
+func RegisterHandlers(router *iris.Application, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, IrisServerOptions{})
+}
+
+// RegisterHandlersWithOptions creates http.Handler with additional options
+func RegisterHandlersWithOptions(router *iris.Application, si ServerInterface, options IrisServerOptions) {
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+
+ router.Get(options.BaseURL+"/contentObject/:param", wrapper.GetContentObject)
+ router.Get(options.BaseURL+"/cookie", wrapper.GetCookie)
+ router.Get(options.BaseURL+"/enums", wrapper.EnumParams)
+ router.Get(options.BaseURL+"/header", wrapper.GetHeader)
+ router.Get(options.BaseURL+"/labelExplodeArray/:param", wrapper.GetLabelExplodeArray)
+ router.Get(options.BaseURL+"/labelExplodeObject/:param", wrapper.GetLabelExplodeObject)
+ router.Get(options.BaseURL+"/labelExplodePrimitive/:param", wrapper.GetLabelExplodePrimitive)
+ router.Get(options.BaseURL+"/labelNoExplodeArray/:param", wrapper.GetLabelNoExplodeArray)
+ router.Get(options.BaseURL+"/labelNoExplodeObject/:param", wrapper.GetLabelNoExplodeObject)
+ router.Get(options.BaseURL+"/labelPrimitive/:param", wrapper.GetLabelPrimitive)
+ router.Get(options.BaseURL+"/matrixExplodeArray/:id", wrapper.GetMatrixExplodeArray)
+ router.Get(options.BaseURL+"/matrixExplodeObject/:id", wrapper.GetMatrixExplodeObject)
+ router.Get(options.BaseURL+"/matrixExplodePrimitive/:id", wrapper.GetMatrixExplodePrimitive)
+ router.Get(options.BaseURL+"/matrixNoExplodeArray/:id", wrapper.GetMatrixNoExplodeArray)
+ router.Get(options.BaseURL+"/matrixNoExplodeObject/:id", wrapper.GetMatrixNoExplodeObject)
+ router.Get(options.BaseURL+"/matrixPrimitive/:id", wrapper.GetMatrixPrimitive)
+ router.Get(options.BaseURL+"/passThrough/:param", wrapper.GetPassThrough)
+ router.Get(options.BaseURL+"/queryDeepObject", wrapper.GetDeepObject)
+ router.Get(options.BaseURL+"/queryDelimited", wrapper.GetQueryDelimited)
+ router.Get(options.BaseURL+"/queryForm", wrapper.GetQueryForm)
+ router.Get(options.BaseURL+"/simpleExplodeArray/:param", wrapper.GetSimpleExplodeArray)
+ router.Get(options.BaseURL+"/simpleExplodeObject/:param", wrapper.GetSimpleExplodeObject)
+ router.Get(options.BaseURL+"/simpleExplodePrimitive/:param", wrapper.GetSimpleExplodePrimitive)
+ router.Get(options.BaseURL+"/simpleNoExplodeArray/:param", wrapper.GetSimpleNoExplodeArray)
+ router.Get(options.BaseURL+"/simpleNoExplodeObject/:param", wrapper.GetSimpleNoExplodeObject)
+ router.Get(options.BaseURL+"/simplePrimitive/:param", wrapper.GetSimplePrimitive)
+ router.Get(options.BaseURL+"/startingWithNumber/:1param", wrapper.GetStartingWithNumber)
+
+ router.Build()
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "3FpLb+M2F/0rwv2+VaFYdqYrdRVMp22ATiatA0yBIAtGuo44lUQOSacJDP33gpRkPa2HLeXRXWJd3sch",
+ "z6F4qR14LOIsxlhJcHcgUHIWSzT/rGnEQ/wz+0n/4rFYYaz0nwqflMNDQmP9n/QCjIj5/ZkjuCCVoPED",
+ "JElig4/SE5QrymJw4cKSxq+Vx7LY/Tf0FGjT1I+J/pFpq6cv6UN3B1wwjkLRNLlLvxSNxgofUEBiw6W8",
+ "8KM0qezhPWMhklg/LJz9X+AGXPifU9TvZMGdL0U+Ar9vqUAf3Nt8sK1DF3HuKm6rOW6okOqKRNgCjA2C",
+ "hW0PalGNlV1ydWcwpfGG6cEh9TCbnNgEgs+XN9q7okq7hxuUylqjeEQBNjyikOk0rBbLxVIbMo4x4RRc",
+ "+LBYLlZgAycqMPk72Xyn9Tk7TgSJEv3kAU25ulii51XPBvyK6mN5gHElSIQKhQT3trJ+COch9cxg55tk",
+ "tVXUNT3VhZGhAa5JG+wcBhMZylgqscXkzq6u8fPl8lC8vZ1TI0JiYjoeY39T7EbDWDRgqBKCCxpRRR+1",
+ "IT7xkPkI7oaEErPCvNxNXhrYJag2TEREpST4cA52gxOJPSiihudAQDw5YhbFt4gQ5HloWFIJSxVGclD8",
+ "/S9ptJZ8Gml04T1fGntYWE6YQbiwSkLDpKweuhmxC4LjIs5F92olXmpQYNhagcegCYJ+ZklFhKLxg/UP",
+ "VYEVb6N7I5WtXlayAkRduuvq4uOGbEN1rMJgvE2XWqvAfIq30bUWFtmnMNf5w7RE7dZ6JOEWZV7n9y2K",
+ "59IKM65VcJ2JaFGxfgLu7Wq5tM+Xyzt7gBg0JffHFJvKTDArXy1Z8QESH0WXvP6WWpwqr0HuJiv+r7Pr",
+ "0pBZhbYj9NmnTBteRHqbiVxo6/YkXkyID2T1ynLczCrVpnaw5lDnQxm8O5FuFpI5ygs6QrLrPldn68z6",
+ "7CtVwdlVbv1iMh6SewyzxWEWsLNbGMn6ofNd+vf6sKbStS3PIa/B0xDIBqmezSHDVAhTvlyXMcuPH2NB",
+ "O3QKmQK1Iex6KXz2e8Z4iMo73QwoDVhSM0N0xdqI149PdVwHOmVd/g9Rb19/lXwjgOtl3ynIvQn6NXjX",
+ "j84Qvp2Cy6sSLiJK0Kca36jfrUafG4OOkSLqz060tLr5ANsTbRRix+9xPZCNY9jc4JSo9tMofE7a4Hog",
+ "GkG22fBp7G/UHwDOBLvbe2Zcc3Mbh9oJW9v7YF2VbgOgOW1fe9M840TKm0Cw7UMw5AbkujDvvP8YcX/2",
+ "KrcbpiP4MyIvLrcOlVyy6unF+Yi8u7lSa0T6qeujOVPrSxQLxS9ynvq4nyEXakag3wXcH1XLHvAkJx5a",
+ "fm5udbbOajjKqe4wCgRNOkXyLc1Pyo9Nl0+frs6mlO3UTPmFiah3qo1RzywPatfW2/XTw6WHwsh2bS2r",
+ "F0tqWNu2jtn8l2i1iFME3Jfad7NQr3aeO+MuCk8W0Mr2wgNxum/kXrnBXUv2uEvImpORd5AnKFv6oU71",
+ "gDGgwbhuDHu7neu0RJgNtcqnMyNgezu967kRKp01+t+u160jX715PRtG9eP9UITeTft6fuSGf7y2bhv4",
+ "JhrYs6F0BPk6WPceaZbtu1+pCtKbYWe3GgBFY9iMh/3VzKd9jbD5QDTNeytCcCFQiruOk30dqlCqhT4z",
+ "R4QvCIXkLvk3AAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/parameters/iris/gen/types.gen.go b/internal/test/parameters/iris/gen/types.gen.go
new file mode 100644
index 0000000000..b075b62ba0
--- /dev/null
+++ b/internal/test/parameters/iris/gen/types.gen.go
@@ -0,0 +1,143 @@
+// Package irisparamsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package irisparamsgen
+
+// Defines values for EnumParamsParamsEnumPathParam.
+const (
+ N100 EnumParamsParamsEnumPathParam = 100
+ N200 EnumParamsParamsEnumPathParam = 200
+)
+
+// Valid indicates whether the value is a known member of the EnumParamsParamsEnumPathParam enum.
+func (e EnumParamsParamsEnumPathParam) Valid() bool {
+ switch e {
+ case N100:
+ return true
+ case N200:
+ return true
+ default:
+ return false
+ }
+}
+
+// ComplexObject defines model for ComplexObject.
+type ComplexObject struct {
+ Id int `json:"Id"`
+ IsAdmin bool `json:"IsAdmin"`
+ Object Object `json:"Object"`
+}
+
+// Object defines model for Object.
+type Object struct {
+ FirstName string `json:"firstName"`
+ Role string `json:"role"`
+}
+
+// GetCookieParams defines parameters for GetCookie.
+type GetCookieParams struct {
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ep primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
+
+// EnumParamsParams defines parameters for EnumParams.
+type EnumParamsParams struct {
+ // EnumPathParam Parameter with enum values
+ EnumPathParam *EnumParamsParamsEnumPathParam `form:"enumPathParam,omitempty" json:"enumPathParam,omitempty"`
+}
+
+// EnumParamsParamsEnumPathParam defines parameters for EnumParams.
+type EnumParamsParamsEnumPathParam int32
+
+// GetHeaderParams defines parameters for GetHeader.
+type GetHeaderParams struct {
+ // XPrimitive primitive
+ XPrimitive *int32 `json:"X-Primitive,omitempty"`
+
+ // XPrimitiveExploded primitive
+ XPrimitiveExploded *int32 `json:"X-Primitive-Exploded,omitempty"`
+
+ // XArrayExploded exploded array
+ XArrayExploded *[]int32 `json:"X-Array-Exploded,omitempty"`
+
+ // XArray array
+ XArray *[]int32 `json:"X-Array,omitempty"`
+
+ // XObjectExploded exploded object
+ XObjectExploded *Object `json:"X-Object-Exploded,omitempty"`
+
+ // XObject object
+ XObject *Object `json:"X-Object,omitempty"`
+
+ // XComplexObject complex object
+ XComplexObject *ComplexObject `json:"X-Complex-Object,omitempty"`
+
+ // N1StartingWithNumber name starting with number
+ N1StartingWithNumber *string `json:"1-Starting-With-Number,omitempty"`
+}
+
+// GetDeepObjectParams defines parameters for GetDeepObject.
+type GetDeepObjectParams struct {
+ // DeepObj deep object
+ DeepObj ComplexObject `json:"deepObj"`
+}
+
+// GetQueryDelimitedParams defines parameters for GetQueryDelimited.
+type GetQueryDelimitedParams struct {
+ // Sa space delimited array
+ Sa *[]int32 `json:"sa,omitempty"`
+
+ // Pa pipe delimited array
+ Pa *[]int32 `json:"pa,omitempty"`
+}
+
+// GetQueryFormParams defines parameters for GetQueryForm.
+type GetQueryFormParams struct {
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Ep exploded primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ps primitive string
+ Ps *string `form:"ps,omitempty" json:"ps,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
diff --git a/internal/test/parameters/iris/server.cfg.yaml b/internal/test/parameters/iris/server.cfg.yaml
new file mode 100644
index 0000000000..3b1099ea5b
--- /dev/null
+++ b/internal/test/parameters/iris/server.cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: irisparamsgen
+generate:
+ iris-server: true
+ embedded-spec: true
+output: gen/server.gen.go
diff --git a/internal/test/parameters/iris/server.go b/internal/test/parameters/iris/server.go
new file mode 100644
index 0000000000..4d63b96242
--- /dev/null
+++ b/internal/test/parameters/iris/server.go
@@ -0,0 +1,44 @@
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../parameters.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../parameters.yaml
+
+package irisparams
+
+import (
+ "net/http"
+
+ "github.com/kataras/iris/v12"
+
+ gen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/iris/gen"
+)
+
+type Server struct{}
+
+var _ gen.ServerInterface = (*Server)(nil)
+
+func (s *Server) GetContentObject(ctx iris.Context, param gen.ComplexObject) { _ = ctx.JSON(param) }
+func (s *Server) GetCookie(ctx iris.Context, params gen.GetCookieParams) { _ = ctx.JSON(params) }
+func (s *Server) EnumParams(ctx iris.Context, params gen.EnumParamsParams) { ctx.StatusCode(http.StatusNoContent) }
+func (s *Server) GetHeader(ctx iris.Context, params gen.GetHeaderParams) { _ = ctx.JSON(params) }
+func (s *Server) GetLabelExplodeArray(ctx iris.Context, param []int32) { _ = ctx.JSON(param) }
+func (s *Server) GetLabelExplodeObject(ctx iris.Context, param gen.Object) { _ = ctx.JSON(param) }
+func (s *Server) GetLabelExplodePrimitive(ctx iris.Context, param int32) { _ = ctx.JSON(param) }
+func (s *Server) GetLabelNoExplodeArray(ctx iris.Context, param []int32) { _ = ctx.JSON(param) }
+func (s *Server) GetLabelNoExplodeObject(ctx iris.Context, param gen.Object) { _ = ctx.JSON(param) }
+func (s *Server) GetLabelPrimitive(ctx iris.Context, param int32) { _ = ctx.JSON(param) }
+func (s *Server) GetMatrixExplodeArray(ctx iris.Context, id []int32) { _ = ctx.JSON(id) }
+func (s *Server) GetMatrixExplodeObject(ctx iris.Context, id gen.Object) { _ = ctx.JSON(id) }
+func (s *Server) GetMatrixExplodePrimitive(ctx iris.Context, id int32) { _ = ctx.JSON(id) }
+func (s *Server) GetMatrixNoExplodeArray(ctx iris.Context, id []int32) { _ = ctx.JSON(id) }
+func (s *Server) GetMatrixNoExplodeObject(ctx iris.Context, id gen.Object) { _ = ctx.JSON(id) }
+func (s *Server) GetMatrixPrimitive(ctx iris.Context, id int32) { _ = ctx.JSON(id) }
+func (s *Server) GetPassThrough(ctx iris.Context, param string) { _ = ctx.JSON(param) }
+func (s *Server) GetDeepObject(ctx iris.Context, params gen.GetDeepObjectParams) { _ = ctx.JSON(params) }
+func (s *Server) GetQueryDelimited(ctx iris.Context, params gen.GetQueryDelimitedParams) { _ = ctx.JSON(params) }
+func (s *Server) GetQueryForm(ctx iris.Context, params gen.GetQueryFormParams) { _ = ctx.JSON(params) }
+func (s *Server) GetSimpleExplodeArray(ctx iris.Context, param []int32) { _ = ctx.JSON(param) }
+func (s *Server) GetSimpleExplodeObject(ctx iris.Context, param gen.Object) { _ = ctx.JSON(param) }
+func (s *Server) GetSimpleExplodePrimitive(ctx iris.Context, param int32) { _ = ctx.JSON(param) }
+func (s *Server) GetSimpleNoExplodeArray(ctx iris.Context, param []int32) { _ = ctx.JSON(param) }
+func (s *Server) GetSimpleNoExplodeObject(ctx iris.Context, param gen.Object) { _ = ctx.JSON(param) }
+func (s *Server) GetSimplePrimitive(ctx iris.Context, param int32) { _ = ctx.JSON(param) }
+func (s *Server) GetStartingWithNumber(ctx iris.Context, n1param string) { _ = ctx.JSON(n1param) }
diff --git a/internal/test/parameters/iris/types.cfg.yaml b/internal/test/parameters/iris/types.cfg.yaml
new file mode 100644
index 0000000000..ffb12605ab
--- /dev/null
+++ b/internal/test/parameters/iris/types.cfg.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: irisparamsgen
+generate:
+ models: true
+output: gen/types.gen.go
diff --git a/internal/test/parameters/param_roundtrip_test.go b/internal/test/parameters/param_roundtrip_test.go
new file mode 100644
index 0000000000..6a64a99040
--- /dev/null
+++ b/internal/test/parameters/param_roundtrip_test.go
@@ -0,0 +1,550 @@
+package parameters_test
+
+import (
+ "encoding/json"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/gin-gonic/gin"
+ "github.com/go-chi/chi/v5"
+ "github.com/gofiber/fiber/v2"
+ "github.com/gofiber/fiber/v2/middleware/adaptor"
+ "github.com/gorilla/mux"
+ "github.com/kataras/iris/v12"
+ "github.com/labstack/echo/v4"
+ echov5 "github.com/labstack/echo/v5"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+
+ chiparams "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/chi"
+ chigen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/chi/gen"
+ paramclient "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/client/gen"
+ echoparams "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/echo"
+ echogen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/echo/gen"
+ echov5params "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/echov5"
+ echov5gen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/echov5/gen"
+ fiberparams "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/fiber"
+ fibergen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/fiber/gen"
+ ginparams "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/gin"
+ gingen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/gin/gen"
+ gorillaparams "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/gorilla"
+ gorillgen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/gorilla/gen"
+ irisparams "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/iris"
+ irisgen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/iris/gen"
+ stdhttpparams "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/stdhttp"
+ stdhttpgen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/stdhttp/gen"
+)
+
+func TestEchoParameterRoundTrip(t *testing.T) {
+ var s echoparams.Server
+ e := echo.New()
+ echogen.RegisterHandlers(e, &s)
+ testImpl(t, e)
+}
+
+func TestEchoV5ParameterRoundTrip(t *testing.T) {
+ var s echov5params.Server
+ e := echov5.New()
+ echov5gen.RegisterHandlers(e, &s)
+ testImpl(t, e)
+}
+
+func TestChiParameterRoundTrip(t *testing.T) {
+ var s chiparams.Server
+ r := chi.NewRouter()
+ handler := chigen.HandlerFromMux(&s, r)
+ testImpl(t, handler)
+}
+
+func TestGinParameterRoundTrip(t *testing.T) {
+ var s ginparams.Server
+ gin.SetMode(gin.ReleaseMode)
+ r := gin.New()
+ gingen.RegisterHandlers(r, &s)
+ testImpl(t, r)
+}
+
+func TestGorillaParameterRoundTrip(t *testing.T) {
+ var s gorillaparams.Server
+ r := mux.NewRouter()
+ handler := gorillgen.HandlerFromMux(&s, r)
+ testImpl(t, handler)
+}
+
+func TestIrisParameterRoundTrip(t *testing.T) {
+ var s irisparams.Server
+ app := iris.New()
+ irisgen.RegisterHandlers(app, &s)
+ testImpl(t, app)
+}
+
+func TestFiberParameterRoundTrip(t *testing.T) {
+ var s fiberparams.Server
+ app := fiber.New()
+ fibergen.RegisterHandlers(app, &s)
+ testImpl(t, adaptor.FiberApp(app))
+}
+
+func TestStdHttpParameterRoundTrip(t *testing.T) {
+ // The OpenAPI spec includes a path parameter named "1param" which starts
+ // with a digit. Go's stdlib ServeMux requires wildcard names to be valid
+ // Go identifiers, so registering this route panics. This is a known
+ // stdhttp panics because net/http.ServeMux rejects wildcard names
+ // starting with a digit ("1param"). Skip until codegen sanitizes the name.
+ t.Skip("stdhttp panics on path param name starting with digit (1param) — see #2306")
+ var s stdhttpparams.Server
+ handler := stdhttpgen.Handler(&s)
+ testImpl(t, handler)
+}
+
+// testImpl runs the full parameter roundtrip test suite against any http.Handler.
+// The generated client serializes Go values into an HTTP request, the server
+// deserializes them and echoes them back as JSON, and we compare the response
+// body against the original values.
+func testImpl(t *testing.T, handler http.Handler) {
+ t.Helper()
+
+ server := "http://example.com"
+
+ expectedObject := paramclient.Object{
+ FirstName: "Alex",
+ Role: "admin",
+ }
+
+ expectedComplexObject := paramclient.ComplexObject{
+ Object: expectedObject,
+ Id: 12345,
+ IsAdmin: true,
+ }
+
+ expectedArray := []int32{3, 4, 5}
+
+ var expectedPrimitive int32 = 5
+
+ // doRoundTrip sends a request to the handler, asserts 200, and decodes the JSON response.
+ doRoundTrip := func(t *testing.T, req *http.Request, target interface{}) {
+ t.Helper()
+ // The generated client produces requests via http.NewRequest which
+ // leaves RequestURI empty. Some adapters (notably Fiber) need it
+ // set to route correctly.
+ req.RequestURI = req.URL.RequestURI()
+ rec := httptest.NewRecorder()
+ handler.ServeHTTP(rec, req)
+ if !assert.Equal(t, http.StatusOK, rec.Code, "server returned %d; body: %s", rec.Code, rec.Body.String()) {
+ return
+ }
+ if target != nil {
+ require.NoError(t, json.NewDecoder(rec.Body).Decode(target), "failed to decode response body")
+ }
+ }
+
+ // =========================================================================
+ // Path Parameters
+ // =========================================================================
+ t.Run("path", func(t *testing.T) {
+ t.Run("simple", func(t *testing.T) {
+ t.Run("primitive", func(t *testing.T) {
+ req, err := paramclient.NewGetSimplePrimitiveRequest(server, expectedPrimitive)
+ require.NoError(t, err)
+ var got int32
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedPrimitive, got)
+ })
+
+ t.Run("primitive explode", func(t *testing.T) {
+ req, err := paramclient.NewGetSimpleExplodePrimitiveRequest(server, expectedPrimitive)
+ require.NoError(t, err)
+ var got int32
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedPrimitive, got)
+ })
+
+ t.Run("array noExplode", func(t *testing.T) {
+ req, err := paramclient.NewGetSimpleNoExplodeArrayRequest(server, expectedArray)
+ require.NoError(t, err)
+ var got []int32
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedArray, got)
+ })
+
+ t.Run("array explode", func(t *testing.T) {
+ req, err := paramclient.NewGetSimpleExplodeArrayRequest(server, expectedArray)
+ require.NoError(t, err)
+ var got []int32
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedArray, got)
+ })
+
+ t.Run("object noExplode", func(t *testing.T) {
+ req, err := paramclient.NewGetSimpleNoExplodeObjectRequest(server, expectedObject)
+ require.NoError(t, err)
+ var got paramclient.Object
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedObject, got)
+ })
+
+ t.Run("object explode", func(t *testing.T) {
+ req, err := paramclient.NewGetSimpleExplodeObjectRequest(server, expectedObject)
+ require.NoError(t, err)
+ var got paramclient.Object
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedObject, got)
+ })
+ })
+
+ t.Run("label", func(t *testing.T) {
+ t.Run("primitive", func(t *testing.T) {
+ req, err := paramclient.NewGetLabelPrimitiveRequest(server, expectedPrimitive)
+ require.NoError(t, err)
+ var got int32
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedPrimitive, got)
+ })
+
+ t.Run("primitive explode", func(t *testing.T) {
+ req, err := paramclient.NewGetLabelExplodePrimitiveRequest(server, expectedPrimitive)
+ require.NoError(t, err)
+ var got int32
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedPrimitive, got)
+ })
+
+ t.Run("array noExplode", func(t *testing.T) {
+ req, err := paramclient.NewGetLabelNoExplodeArrayRequest(server, expectedArray)
+ require.NoError(t, err)
+ var got []int32
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedArray, got)
+ })
+
+ t.Run("array explode", func(t *testing.T) {
+ req, err := paramclient.NewGetLabelExplodeArrayRequest(server, expectedArray)
+ require.NoError(t, err)
+ var got []int32
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedArray, got)
+ })
+
+ t.Run("object noExplode", func(t *testing.T) {
+ req, err := paramclient.NewGetLabelNoExplodeObjectRequest(server, expectedObject)
+ require.NoError(t, err)
+ var got paramclient.Object
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedObject, got)
+ })
+
+ t.Run("object explode", func(t *testing.T) {
+ req, err := paramclient.NewGetLabelExplodeObjectRequest(server, expectedObject)
+ require.NoError(t, err)
+ var got paramclient.Object
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedObject, got)
+ })
+ })
+
+ t.Run("matrix", func(t *testing.T) {
+ t.Run("primitive", func(t *testing.T) {
+ req, err := paramclient.NewGetMatrixPrimitiveRequest(server, expectedPrimitive)
+ require.NoError(t, err)
+ var got int32
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedPrimitive, got)
+ })
+
+ t.Run("primitive explode", func(t *testing.T) {
+ req, err := paramclient.NewGetMatrixExplodePrimitiveRequest(server, expectedPrimitive)
+ require.NoError(t, err)
+ var got int32
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedPrimitive, got)
+ })
+
+ t.Run("array noExplode", func(t *testing.T) {
+ req, err := paramclient.NewGetMatrixNoExplodeArrayRequest(server, expectedArray)
+ require.NoError(t, err)
+ var got []int32
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedArray, got)
+ })
+
+ t.Run("array explode", func(t *testing.T) {
+ req, err := paramclient.NewGetMatrixExplodeArrayRequest(server, expectedArray)
+ require.NoError(t, err)
+ var got []int32
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedArray, got)
+ })
+
+ t.Run("object noExplode", func(t *testing.T) {
+ req, err := paramclient.NewGetMatrixNoExplodeObjectRequest(server, expectedObject)
+ require.NoError(t, err)
+ var got paramclient.Object
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedObject, got)
+ })
+
+ t.Run("object explode", func(t *testing.T) {
+ req, err := paramclient.NewGetMatrixExplodeObjectRequest(server, expectedObject)
+ require.NoError(t, err)
+ var got paramclient.Object
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedObject, got)
+ })
+ })
+
+ t.Run("content-based", func(t *testing.T) {
+ t.Run("json complex object", func(t *testing.T) {
+ req, err := paramclient.NewGetContentObjectRequest(server, expectedComplexObject)
+ require.NoError(t, err)
+ var got paramclient.ComplexObject
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedComplexObject, got)
+ })
+
+ t.Run("passthrough string", func(t *testing.T) {
+ req, err := paramclient.NewGetPassThroughRequest(server, "hello world")
+ require.NoError(t, err)
+ var got string
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, "hello world", got)
+ })
+ })
+ })
+
+ // =========================================================================
+ // Query Parameters
+ // =========================================================================
+ t.Run("query", func(t *testing.T) {
+ t.Run("form", func(t *testing.T) {
+ expectedArray2 := []int32{6, 7, 8}
+ expectedObject2 := paramclient.Object{FirstName: "Marcin", Role: "annoyed_at_swagger"}
+ var expectedPrimitive2 int32 = 100
+ var expectedPrimitiveString = "123;456"
+ var expectedN1s = "111"
+
+ t.Run("all params at once", func(t *testing.T) {
+ params := paramclient.GetQueryFormParams{
+ Ea: &expectedArray,
+ A: &expectedArray2,
+ Eo: &expectedObject,
+ O: &expectedObject2,
+ Ep: &expectedPrimitive,
+ P: &expectedPrimitive2,
+ Ps: &expectedPrimitiveString,
+ Co: &expectedComplexObject,
+ N1s: &expectedN1s,
+ }
+ req, err := paramclient.NewGetQueryFormRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetQueryFormParams
+ doRoundTrip(t, req, &got)
+ assert.EqualValues(t, params, got)
+ })
+
+ t.Run("exploded array only", func(t *testing.T) {
+ params := paramclient.GetQueryFormParams{Ea: &expectedArray}
+ req, err := paramclient.NewGetQueryFormRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetQueryFormParams
+ doRoundTrip(t, req, &got)
+ require.NotNil(t, got.Ea)
+ assert.Equal(t, expectedArray, *got.Ea)
+ })
+
+ t.Run("unexploded array only", func(t *testing.T) {
+ params := paramclient.GetQueryFormParams{A: &expectedArray}
+ req, err := paramclient.NewGetQueryFormRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetQueryFormParams
+ doRoundTrip(t, req, &got)
+ require.NotNil(t, got.A)
+ assert.Equal(t, expectedArray, *got.A)
+ })
+
+ t.Run("exploded object only", func(t *testing.T) {
+ params := paramclient.GetQueryFormParams{Eo: &expectedObject}
+ req, err := paramclient.NewGetQueryFormRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetQueryFormParams
+ doRoundTrip(t, req, &got)
+ require.NotNil(t, got.Eo)
+ assert.Equal(t, expectedObject, *got.Eo)
+ })
+
+ t.Run("unexploded object only", func(t *testing.T) {
+ params := paramclient.GetQueryFormParams{O: &expectedObject}
+ req, err := paramclient.NewGetQueryFormRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetQueryFormParams
+ doRoundTrip(t, req, &got)
+ require.NotNil(t, got.O)
+ assert.Equal(t, expectedObject, *got.O)
+ })
+
+ t.Run("primitive with semicolon", func(t *testing.T) {
+ params := paramclient.GetQueryFormParams{Ps: &expectedPrimitiveString}
+ req, err := paramclient.NewGetQueryFormRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetQueryFormParams
+ doRoundTrip(t, req, &got)
+ require.NotNil(t, got.Ps)
+ assert.Equal(t, expectedPrimitiveString, *got.Ps)
+ })
+ })
+
+ t.Run("deepObject", func(t *testing.T) {
+ params := paramclient.GetDeepObjectParams{DeepObj: expectedComplexObject}
+ req, err := paramclient.NewGetDeepObjectRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetDeepObjectParams
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, expectedComplexObject, got.DeepObj)
+ })
+
+ // Regression for oapi-codegen/runtime#131: with the v2.7.0 client
+ // no longer re-encoding query fragments, the runtime marshaller must
+ // percent-encode reserved URI characters and non-ASCII bytes inside
+ // deepObject values. Without the fix, '&' splits the value into two
+ // query params (silent corruption) and non-ASCII bytes produce
+ // invalid URIs that strict servers reject.
+ t.Run("deepObject with unicode and reserved chars", func(t *testing.T) {
+ adversarial := paramclient.ComplexObject{
+ Object: paramclient.Object{
+ FirstName: "filter&q=こんにちは",
+ Role: "admin role+with spaces",
+ },
+ Id: 12345,
+ IsAdmin: true,
+ }
+ params := paramclient.GetDeepObjectParams{DeepObj: adversarial}
+ req, err := paramclient.NewGetDeepObjectRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetDeepObjectParams
+ doRoundTrip(t, req, &got)
+ assert.Equal(t, adversarial, got.DeepObj)
+ })
+
+ t.Run("spaceDelimited", func(t *testing.T) {
+ })
+
+ t.Run("pipeDelimited", func(t *testing.T) {
+ })
+ })
+
+ // =========================================================================
+ // Header Parameters
+ // =========================================================================
+ t.Run("header", func(t *testing.T) {
+ expectedArray2 := []int32{6, 7, 8}
+ expectedObject2 := paramclient.Object{FirstName: "Marcin", Role: "annoyed_at_swagger"}
+ var expectedPrimitive2 int32 = 100
+ var expectedN1s = "111"
+
+ t.Run("all params at once", func(t *testing.T) {
+ params := paramclient.GetHeaderParams{
+ XPrimitive: &expectedPrimitive2,
+ XPrimitiveExploded: &expectedPrimitive,
+ XArrayExploded: &expectedArray,
+ XArray: &expectedArray2,
+ XObjectExploded: &expectedObject,
+ XObject: &expectedObject2,
+ XComplexObject: &expectedComplexObject,
+ N1StartingWithNumber: &expectedN1s,
+ }
+ req, err := paramclient.NewGetHeaderRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetHeaderParams
+ doRoundTrip(t, req, &got)
+ assert.EqualValues(t, params, got)
+ })
+
+ t.Run("primitive only", func(t *testing.T) {
+ params := paramclient.GetHeaderParams{XPrimitive: &expectedPrimitive}
+ req, err := paramclient.NewGetHeaderRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetHeaderParams
+ doRoundTrip(t, req, &got)
+ require.NotNil(t, got.XPrimitive)
+ assert.Equal(t, expectedPrimitive, *got.XPrimitive)
+ })
+
+ t.Run("array only", func(t *testing.T) {
+ params := paramclient.GetHeaderParams{XArray: &expectedArray}
+ req, err := paramclient.NewGetHeaderRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetHeaderParams
+ doRoundTrip(t, req, &got)
+ require.NotNil(t, got.XArray)
+ assert.Equal(t, expectedArray, *got.XArray)
+ })
+
+ t.Run("object only", func(t *testing.T) {
+ params := paramclient.GetHeaderParams{XObject: &expectedObject}
+ req, err := paramclient.NewGetHeaderRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetHeaderParams
+ doRoundTrip(t, req, &got)
+ require.NotNil(t, got.XObject)
+ assert.Equal(t, expectedObject, *got.XObject)
+ })
+ })
+
+ // =========================================================================
+ // Cookie Parameters
+ // =========================================================================
+ t.Run("cookie", func(t *testing.T) {
+ expectedArray2 := []int32{6, 7, 8}
+ expectedObject2 := paramclient.Object{FirstName: "Marcin", Role: "annoyed_at_swagger"}
+ var expectedPrimitive2 int32 = 100
+ var expectedN1s = "111"
+
+ t.Run("all params at once", func(t *testing.T) {
+ params := paramclient.GetCookieParams{
+ P: &expectedPrimitive2,
+ Ep: &expectedPrimitive,
+ Ea: &expectedArray,
+ A: &expectedArray2,
+ Eo: &expectedObject,
+ O: &expectedObject2,
+ Co: &expectedComplexObject,
+ N1s: &expectedN1s,
+ }
+ req, err := paramclient.NewGetCookieRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetCookieParams
+ doRoundTrip(t, req, &got)
+ assert.EqualValues(t, params, got)
+ })
+
+ t.Run("primitive only", func(t *testing.T) {
+ params := paramclient.GetCookieParams{P: &expectedPrimitive}
+ req, err := paramclient.NewGetCookieRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetCookieParams
+ doRoundTrip(t, req, &got)
+ require.NotNil(t, got.P)
+ assert.Equal(t, expectedPrimitive, *got.P)
+ })
+
+ t.Run("array only", func(t *testing.T) {
+ params := paramclient.GetCookieParams{A: &expectedArray}
+ req, err := paramclient.NewGetCookieRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetCookieParams
+ doRoundTrip(t, req, &got)
+ require.NotNil(t, got.A)
+ assert.Equal(t, expectedArray, *got.A)
+ })
+
+ t.Run("object only", func(t *testing.T) {
+ params := paramclient.GetCookieParams{O: &expectedObject}
+ req, err := paramclient.NewGetCookieRequest(server, ¶ms)
+ require.NoError(t, err)
+ var got paramclient.GetCookieParams
+ doRoundTrip(t, req, &got)
+ require.NotNil(t, got.O)
+ assert.Equal(t, expectedObject, *got.O)
+ })
+ })
+}
diff --git a/internal/test/parameters/parameters.yaml b/internal/test/parameters/parameters.yaml
index 682af6ab17..7c09631965 100644
--- a/internal/test/parameters/parameters.yaml
+++ b/internal/test/parameters/parameters.yaml
@@ -207,6 +207,81 @@ paths:
responses:
'200':
$ref: "#/components/responses/SimpleResponse"
+ /simpleExplodePrimitive/{param}:
+ get:
+ operationId: getSimpleExplodePrimitive
+ parameters:
+ - name: param
+ in: path
+ required: true
+ style: simple
+ explode: true
+ schema:
+ type: integer
+ format: int32
+ responses:
+ '200':
+ $ref: "#/components/responses/SimpleResponse"
+ /labelPrimitive/{.param}:
+ get:
+ operationId: getLabelPrimitive
+ parameters:
+ - name: param
+ in: path
+ required: true
+ style: label
+ explode: false
+ schema:
+ type: integer
+ format: int32
+ responses:
+ '200':
+ $ref: "#/components/responses/SimpleResponse"
+ /labelExplodePrimitive/{.param*}:
+ get:
+ operationId: getLabelExplodePrimitive
+ parameters:
+ - name: param
+ in: path
+ required: true
+ style: label
+ explode: true
+ schema:
+ type: integer
+ format: int32
+ responses:
+ '200':
+ $ref: "#/components/responses/SimpleResponse"
+ /matrixPrimitive/{;id}:
+ get:
+ operationId: getMatrixPrimitive
+ parameters:
+ - name: id
+ in: path
+ required: true
+ style: matrix
+ explode: false
+ schema:
+ type: integer
+ format: int32
+ responses:
+ '200':
+ $ref: "#/components/responses/SimpleResponse"
+ /matrixExplodePrimitive/{;id*}:
+ get:
+ operationId: getMatrixExplodePrimitive
+ parameters:
+ - name: id
+ in: path
+ required: true
+ style: matrix
+ explode: true
+ schema:
+ type: integer
+ format: int32
+ responses:
+ '200':
+ $ref: "#/components/responses/SimpleResponse"
/contentObject/{param}:
get:
operationId: getContentObject
@@ -328,6 +403,35 @@ paths:
responses:
'200':
$ref: "#/components/responses/SimpleResponse"
+ /queryDelimited:
+ get:
+ operationId: getQueryDelimited
+ parameters:
+ - name: sa
+ description: space delimited array
+ in: query
+ required: false
+ style: spaceDelimited
+ explode: false
+ schema:
+ type: array
+ items:
+ type: integer
+ format: int32
+ - name: pa
+ description: pipe delimited array
+ in: query
+ required: false
+ style: pipeDelimited
+ explode: false
+ schema:
+ type: array
+ items:
+ type: integer
+ format: int32
+ responses:
+ '200':
+ $ref: "#/components/responses/SimpleResponse"
/queryDeepObject:
get:
operationId: getDeepObject
diff --git a/internal/test/parameters/stdhttp/gen/server.gen.go b/internal/test/parameters/stdhttp/gen/server.gen.go
new file mode 100644
index 0000000000..eda0976432
--- /dev/null
+++ b/internal/test/parameters/stdhttp/gen/server.gen.go
@@ -0,0 +1,1499 @@
+//go:build go1.22
+
+// Package stdhttpparamsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package stdhttpparamsgen
+
+import (
+ "bytes"
+ "compress/flate"
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/oapi-codegen/runtime"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /contentObject/{param})
+ GetContentObject(w http.ResponseWriter, r *http.Request, param ComplexObject)
+
+ // (GET /cookie)
+ GetCookie(w http.ResponseWriter, r *http.Request, params GetCookieParams)
+
+ // (GET /enums)
+ EnumParams(w http.ResponseWriter, r *http.Request, params EnumParamsParams)
+
+ // (GET /header)
+ GetHeader(w http.ResponseWriter, r *http.Request, params GetHeaderParams)
+
+ // (GET /labelExplodeArray/{.param*})
+ GetLabelExplodeArray(w http.ResponseWriter, r *http.Request, param []int32)
+
+ // (GET /labelExplodeObject/{.param*})
+ GetLabelExplodeObject(w http.ResponseWriter, r *http.Request, param Object)
+
+ // (GET /labelExplodePrimitive/{.param*})
+ GetLabelExplodePrimitive(w http.ResponseWriter, r *http.Request, param int32)
+
+ // (GET /labelNoExplodeArray/{.param})
+ GetLabelNoExplodeArray(w http.ResponseWriter, r *http.Request, param []int32)
+
+ // (GET /labelNoExplodeObject/{.param})
+ GetLabelNoExplodeObject(w http.ResponseWriter, r *http.Request, param Object)
+
+ // (GET /labelPrimitive/{.param})
+ GetLabelPrimitive(w http.ResponseWriter, r *http.Request, param int32)
+
+ // (GET /matrixExplodeArray/{.id*})
+ GetMatrixExplodeArray(w http.ResponseWriter, r *http.Request, id []int32)
+
+ // (GET /matrixExplodeObject/{.id*})
+ GetMatrixExplodeObject(w http.ResponseWriter, r *http.Request, id Object)
+
+ // (GET /matrixExplodePrimitive/{;id*})
+ GetMatrixExplodePrimitive(w http.ResponseWriter, r *http.Request, id int32)
+
+ // (GET /matrixNoExplodeArray/{.id})
+ GetMatrixNoExplodeArray(w http.ResponseWriter, r *http.Request, id []int32)
+
+ // (GET /matrixNoExplodeObject/{.id})
+ GetMatrixNoExplodeObject(w http.ResponseWriter, r *http.Request, id Object)
+
+ // (GET /matrixPrimitive/{;id})
+ GetMatrixPrimitive(w http.ResponseWriter, r *http.Request, id int32)
+
+ // (GET /passThrough/{param})
+ GetPassThrough(w http.ResponseWriter, r *http.Request, param string)
+
+ // (GET /queryDeepObject)
+ GetDeepObject(w http.ResponseWriter, r *http.Request, params GetDeepObjectParams)
+
+ // (GET /queryDelimited)
+ GetQueryDelimited(w http.ResponseWriter, r *http.Request, params GetQueryDelimitedParams)
+
+ // (GET /queryForm)
+ GetQueryForm(w http.ResponseWriter, r *http.Request, params GetQueryFormParams)
+
+ // (GET /simpleExplodeArray/{param*})
+ GetSimpleExplodeArray(w http.ResponseWriter, r *http.Request, param []int32)
+
+ // (GET /simpleExplodeObject/{param*})
+ GetSimpleExplodeObject(w http.ResponseWriter, r *http.Request, param Object)
+
+ // (GET /simpleExplodePrimitive/{param})
+ GetSimpleExplodePrimitive(w http.ResponseWriter, r *http.Request, param int32)
+
+ // (GET /simpleNoExplodeArray/{param})
+ GetSimpleNoExplodeArray(w http.ResponseWriter, r *http.Request, param []int32)
+
+ // (GET /simpleNoExplodeObject/{param})
+ GetSimpleNoExplodeObject(w http.ResponseWriter, r *http.Request, param Object)
+
+ // (GET /simplePrimitive/{param})
+ GetSimplePrimitive(w http.ResponseWriter, r *http.Request, param int32)
+
+ // (GET /startingWithNumber/{1param})
+ GetStartingWithNumber(w http.ResponseWriter, r *http.Request, n1param string)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetContentObject operation middleware
+func (siw *ServerInterfaceWrapper) GetContentObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param ComplexObject
+
+ err = json.Unmarshal([]byte(r.PathValue("param")), ¶m)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetContentObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetCookie operation middleware
+func (siw *ServerInterfaceWrapper) GetCookie(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetCookieParams
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("p"); err == nil {
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "p", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "p", Err: err})
+ return
+ }
+ params.P = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("ep"); err == nil {
+ var value int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ep", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ep", Err: err})
+ return
+ }
+ params.Ep = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("ea"); err == nil {
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "ea", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ea", Err: err})
+ return
+ }
+ params.Ea = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("a"); err == nil {
+ var value []int32
+ err = runtime.BindStyledParameterWithOptions("simple", "a", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "a", Err: err})
+ return
+ }
+ params.A = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("eo"); err == nil {
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "eo", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "eo", Err: err})
+ return
+ }
+ params.Eo = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("o"); err == nil {
+ var value Object
+ err = runtime.BindStyledParameterWithOptions("simple", "o", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "o", Err: err})
+ return
+ }
+ params.O = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("co"); err == nil {
+ var value ComplexObject
+ var decoded string
+ decoded, err := url.QueryUnescape(cookie.Value)
+ if err != nil {
+ err = fmt.Errorf("Error unescaping cookie parameter 'co'")
+ siw.ErrorHandlerFunc(w, r, &UnescapedCookieParamError{ParamName: "co", Err: err})
+ return
+ }
+
+ err = json.Unmarshal([]byte(decoded), &value)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "co", Err: err})
+ return
+ }
+
+ params.Co = &value
+
+ }
+ }
+
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("1s"); err == nil {
+ var value string
+ err = runtime.BindStyledParameterWithOptions("simple", "1s", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: true, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "1s", Err: err})
+ return
+ }
+ params.N1s = &value
+
+ }
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetCookie(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// EnumParams operation middleware
+func (siw *ServerInterfaceWrapper) EnumParams(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params EnumParamsParams
+
+ // ------------- Optional query parameter "enumPathParam" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "enumPathParam", r.URL.Query(), ¶ms.EnumPathParam, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "enumPathParam"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "enumPathParam", Err: err})
+ }
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.EnumParams(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetHeader operation middleware
+func (siw *ServerInterfaceWrapper) GetHeader(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetHeaderParams
+
+ headers := r.Header
+
+ // ------------- Optional header parameter "X-Primitive" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive")]; found {
+ var XPrimitive int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Primitive", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive", valueList[0], &XPrimitive, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Primitive", Err: err})
+ return
+ }
+
+ params.XPrimitive = &XPrimitive
+
+ }
+
+ // ------------- Optional header parameter "X-Primitive-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Primitive-Exploded")]; found {
+ var XPrimitiveExploded int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Primitive-Exploded", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Primitive-Exploded", valueList[0], &XPrimitiveExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Primitive-Exploded", Err: err})
+ return
+ }
+
+ params.XPrimitiveExploded = &XPrimitiveExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Array-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array-Exploded")]; found {
+ var XArrayExploded []int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Array-Exploded", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array-Exploded", valueList[0], &XArrayExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Array-Exploded", Err: err})
+ return
+ }
+
+ params.XArrayExploded = &XArrayExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Array" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Array")]; found {
+ var XArray []int32
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Array", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Array", valueList[0], &XArray, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Array", Err: err})
+ return
+ }
+
+ params.XArray = &XArray
+
+ }
+
+ // ------------- Optional header parameter "X-Object-Exploded" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object-Exploded")]; found {
+ var XObjectExploded Object
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Object-Exploded", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object-Exploded", valueList[0], &XObjectExploded, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: true, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Object-Exploded", Err: err})
+ return
+ }
+
+ params.XObjectExploded = &XObjectExploded
+
+ }
+
+ // ------------- Optional header parameter "X-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Object")]; found {
+ var XObject Object
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Object", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "X-Object", valueList[0], &XObject, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "X-Object", Err: err})
+ return
+ }
+
+ params.XObject = &XObject
+
+ }
+
+ // ------------- Optional header parameter "X-Complex-Object" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("X-Complex-Object")]; found {
+ var XComplexObject ComplexObject
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "X-Complex-Object", Count: n})
+ return
+ }
+
+ err = json.Unmarshal([]byte(valueList[0]), &XComplexObject)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "X-Complex-Object", Err: err})
+ return
+ }
+
+ params.XComplexObject = &XComplexObject
+
+ }
+
+ // ------------- Optional header parameter "1-Starting-With-Number" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("1-Starting-With-Number")]; found {
+ var N1StartingWithNumber string
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "1-Starting-With-Number", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "1-Starting-With-Number", valueList[0], &N1StartingWithNumber, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "1-Starting-With-Number", Err: err})
+ return
+ }
+
+ params.N1StartingWithNumber = &N1StartingWithNumber
+
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetHeader(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", r.PathValue("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelExplodeArray(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", r.PathValue("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelExplodeObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelExplodePrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", r.PathValue("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelExplodePrimitive(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelNoExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", r.PathValue("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelNoExplodeArray(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelNoExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", r.PathValue("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelNoExplodeObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetLabelPrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetLabelPrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("label", "param", r.PathValue("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetLabelPrimitive(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixExplodeArray(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixExplodeObject(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixExplodePrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixExplodePrimitive(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixNoExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id []int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixNoExplodeArray(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixNoExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id Object
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixNoExplodeObject(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetMatrixPrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetMatrixPrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "id" -------------
+ var id int32
+
+ err = runtime.BindStyledParameterWithOptions("matrix", "id", r.PathValue("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "id", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetMatrixPrimitive(w, r, id)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetPassThrough operation middleware
+func (siw *ServerInterfaceWrapper) GetPassThrough(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param string
+
+ param = r.PathValue("param")
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetPassThrough(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetDeepObject operation middleware
+func (siw *ServerInterfaceWrapper) GetDeepObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetDeepObjectParams
+
+ // ------------- Required query parameter "deepObj" -------------
+
+ err = runtime.BindQueryParameterWithOptions("deepObject", true, true, "deepObj", r.URL.Query(), ¶ms.DeepObj, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "deepObj"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "deepObj", Err: err})
+ }
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetDeepObject(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetQueryDelimited operation middleware
+func (siw *ServerInterfaceWrapper) GetQueryDelimited(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryDelimitedParams
+
+ // ------------- Optional query parameter "sa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("spaceDelimited", false, false, "sa", r.URL.Query(), ¶ms.Sa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "sa"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "sa", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "pa" -------------
+
+ err = runtime.BindQueryParameterWithOptions("pipeDelimited", false, false, "pa", r.URL.Query(), ¶ms.Pa, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "pa"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "pa", Err: err})
+ }
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetQueryDelimited(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetQueryForm operation middleware
+func (siw *ServerInterfaceWrapper) GetQueryForm(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params GetQueryFormParams
+
+ // ------------- Optional query parameter "ea" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ea", r.URL.Query(), ¶ms.Ea, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "ea"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ea", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "a" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "a", r.URL.Query(), ¶ms.A, runtime.BindQueryParameterOptions{Type: "array", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "a"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "a", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "eo" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "eo", r.URL.Query(), ¶ms.Eo, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "eo"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "eo", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "o" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "o", r.URL.Query(), ¶ms.O, runtime.BindQueryParameterOptions{Type: "", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "o"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "o", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "ep" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ep", r.URL.Query(), ¶ms.Ep, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "ep"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ep", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "p" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", false, false, "p", r.URL.Query(), ¶ms.P, runtime.BindQueryParameterOptions{Type: "integer", Format: "int32"})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "p"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "p", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "ps" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "ps", r.URL.Query(), ¶ms.Ps, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "ps"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "ps", Err: err})
+ }
+ return
+ }
+
+ // ------------- Optional query parameter "co" -------------
+
+ if paramValue := r.URL.Query().Get("co"); paramValue != "" {
+
+ var value ComplexObject
+ err = json.Unmarshal([]byte(paramValue), &value)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "co", Err: err})
+ return
+ }
+
+ params.Co = &value
+
+ }
+
+ // ------------- Optional query parameter "1s" -------------
+
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "1s", r.URL.Query(), ¶ms.N1s, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "1s"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "1s", Err: err})
+ }
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetQueryForm(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", r.PathValue("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleExplodeArray(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", r.PathValue("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleExplodeObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleExplodePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleExplodePrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", r.PathValue("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleExplodePrimitive(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleNoExplodeArray operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleNoExplodeArray(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param []int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", r.PathValue("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "array", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleNoExplodeArray(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimpleNoExplodeObject operation middleware
+func (siw *ServerInterfaceWrapper) GetSimpleNoExplodeObject(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param Object
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", r.PathValue("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimpleNoExplodeObject(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetSimplePrimitive operation middleware
+func (siw *ServerInterfaceWrapper) GetSimplePrimitive(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "param" -------------
+ var param int32
+
+ err = runtime.BindStyledParameterWithOptions("simple", "param", r.PathValue("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int32"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "param", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetSimplePrimitive(w, r, param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// GetStartingWithNumber operation middleware
+func (siw *ServerInterfaceWrapper) GetStartingWithNumber(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "1param" -------------
+ var n1param string
+
+ n1param = r.PathValue("_param")
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetStartingWithNumber(w, r, n1param)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{})
+}
+
+// ServeMux is an abstraction of [http.ServeMux].
+type ServeMux interface {
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+ http.Handler
+}
+
+type StdHTTPServerOptions struct {
+ BaseURL string
+ BaseRouter ServeMux
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/contentObject/{param}", wrapper.GetContentObject)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/cookie", wrapper.GetCookie)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/enums", wrapper.EnumParams)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/header", wrapper.GetHeader)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/labelExplodeArray/{param}", wrapper.GetLabelExplodeArray)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/labelExplodeObject/{param}", wrapper.GetLabelExplodeObject)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/labelExplodePrimitive/{param}", wrapper.GetLabelExplodePrimitive)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/labelNoExplodeArray/{param}", wrapper.GetLabelNoExplodeArray)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/labelNoExplodeObject/{param}", wrapper.GetLabelNoExplodeObject)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/labelPrimitive/{param}", wrapper.GetLabelPrimitive)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/matrixExplodeArray/{id}", wrapper.GetMatrixExplodeArray)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/matrixExplodeObject/{id}", wrapper.GetMatrixExplodeObject)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/matrixExplodePrimitive/{id}", wrapper.GetMatrixExplodePrimitive)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/matrixNoExplodeArray/{id}", wrapper.GetMatrixNoExplodeArray)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/matrixNoExplodeObject/{id}", wrapper.GetMatrixNoExplodeObject)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/matrixPrimitive/{id}", wrapper.GetMatrixPrimitive)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/passThrough/{param}", wrapper.GetPassThrough)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/queryDeepObject", wrapper.GetDeepObject)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/queryDelimited", wrapper.GetQueryDelimited)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/queryForm", wrapper.GetQueryForm)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/simpleExplodeArray/{param}", wrapper.GetSimpleExplodeArray)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/simpleExplodeObject/{param}", wrapper.GetSimpleExplodeObject)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/simpleExplodePrimitive/{param}", wrapper.GetSimpleExplodePrimitive)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/simpleNoExplodeArray/{param}", wrapper.GetSimpleNoExplodeArray)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/simpleNoExplodeObject/{param}", wrapper.GetSimpleNoExplodeObject)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/simplePrimitive/{param}", wrapper.GetSimplePrimitive)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/startingWithNumber/{_param}", wrapper.GetStartingWithNumber)
+
+ return m
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "3FpLb+M2F/0rwv2+VaFYdqYrdRVMp22ATiatA0yBIAtGuo44lUQOSacJDP33gpRkPa2HLeXRXWJd3sch",
+ "z6F4qR14LOIsxlhJcHcgUHIWSzT/rGnEQ/wz+0n/4rFYYaz0nwqflMNDQmP9n/QCjIj5/ZkjuCCVoPED",
+ "JElig4/SE5QrymJw4cKSxq+Vx7LY/Tf0FGjT1I+J/pFpq6cv6UN3B1wwjkLRNLlLvxSNxgofUEBiw6W8",
+ "8KM0qezhPWMhklg/LJz9X+AGXPifU9TvZMGdL0U+Ar9vqUAf3Nt8sK1DF3HuKm6rOW6okOqKRNgCjA2C",
+ "hW0PalGNlV1ydWcwpfGG6cEh9TCbnNgEgs+XN9q7okq7hxuUylqjeEQBNjyikOk0rBbLxVIbMo4x4RRc",
+ "+LBYLlZgAycqMPk72Xyn9Tk7TgSJEv3kAU25ulii51XPBvyK6mN5gHElSIQKhQT3trJ+COch9cxg55tk",
+ "tVXUNT3VhZGhAa5JG+wcBhMZylgqscXkzq6u8fPl8lC8vZ1TI0JiYjoeY39T7EbDWDRgqBKCCxpRRR+1",
+ "IT7xkPkI7oaEErPCvNxNXhrYJag2TEREpST4cA52gxOJPSiihudAQDw5YhbFt4gQ5HloWFIJSxVGclD8",
+ "/S9ptJZ8Gml04T1fGntYWE6YQbiwSkLDpKweuhmxC4LjIs5F92olXmpQYNhagcegCYJ+ZklFhKLxg/UP",
+ "VYEVb6N7I5WtXlayAkRduuvq4uOGbEN1rMJgvE2XWqvAfIq30bUWFtmnMNf5w7RE7dZ6JOEWZV7n9y2K",
+ "59IKM65VcJ2JaFGxfgLu7Wq5tM+Xyzt7gBg0JffHFJvKTDArXy1Z8QESH0WXvP6WWpwqr0HuJiv+r7Pr",
+ "0pBZhbYj9NmnTBteRHqbiVxo6/YkXkyID2T1ynLczCrVpnaw5lDnQxm8O5FuFpI5ygs6QrLrPldn68z6",
+ "7CtVwdlVbv1iMh6SewyzxWEWsLNbGMn6ofNd+vf6sKbStS3PIa/B0xDIBqmezSHDVAhTvlyXMcuPH2NB",
+ "O3QKmQK1Iex6KXz2e8Z4iMo73QwoDVhSM0N0xdqI149PdVwHOmVd/g9Rb19/lXwjgOtl3ynIvQn6NXjX",
+ "j84Qvp2Cy6sSLiJK0Kca36jfrUafG4OOkSLqz060tLr5ANsTbRRix+9xPZCNY9jc4JSo9tMofE7a4Hog",
+ "GkG22fBp7G/UHwDOBLvbe2Zcc3Mbh9oJW9v7YF2VbgOgOW1fe9M840TKm0Cw7UMw5AbkujDvvP8YcX/2",
+ "KrcbpiP4MyIvLrcOlVyy6unF+Yi8u7lSa0T6qeujOVPrSxQLxS9ynvq4nyEXakag3wXcH1XLHvAkJx5a",
+ "fm5udbbOajjKqe4wCgRNOkXyLc1Pyo9Nl0+frs6mlO3UTPmFiah3qo1RzywPatfW2/XTw6WHwsh2bS2r",
+ "F0tqWNu2jtn8l2i1iFME3Jfad7NQr3aeO+MuCk8W0Mr2wgNxum/kXrnBXUv2uEvImpORd5AnKFv6oU71",
+ "gDGgwbhuDHu7neu0RJgNtcqnMyNgezu967kRKp01+t+u160jX715PRtG9eP9UITeTft6fuSGf7y2bhv4",
+ "JhrYs6F0BPk6WPceaZbtu1+pCtKbYWe3GgBFY9iMh/3VzKd9jbD5QDTNeytCcCFQiruOk30dqlCqhT4z",
+ "R4QvCIXkLvk3AAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/parameters/stdhttp/gen/types.gen.go b/internal/test/parameters/stdhttp/gen/types.gen.go
new file mode 100644
index 0000000000..132c9c3499
--- /dev/null
+++ b/internal/test/parameters/stdhttp/gen/types.gen.go
@@ -0,0 +1,143 @@
+// Package stdhttpparamsgen provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package stdhttpparamsgen
+
+// Defines values for EnumParamsParamsEnumPathParam.
+const (
+ N100 EnumParamsParamsEnumPathParam = 100
+ N200 EnumParamsParamsEnumPathParam = 200
+)
+
+// Valid indicates whether the value is a known member of the EnumParamsParamsEnumPathParam enum.
+func (e EnumParamsParamsEnumPathParam) Valid() bool {
+ switch e {
+ case N100:
+ return true
+ case N200:
+ return true
+ default:
+ return false
+ }
+}
+
+// ComplexObject defines model for ComplexObject.
+type ComplexObject struct {
+ Id int `json:"Id"`
+ IsAdmin bool `json:"IsAdmin"`
+ Object Object `json:"Object"`
+}
+
+// Object defines model for Object.
+type Object struct {
+ FirstName string `json:"firstName"`
+ Role string `json:"role"`
+}
+
+// GetCookieParams defines parameters for GetCookie.
+type GetCookieParams struct {
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ep primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
+
+// EnumParamsParams defines parameters for EnumParams.
+type EnumParamsParams struct {
+ // EnumPathParam Parameter with enum values
+ EnumPathParam *EnumParamsParamsEnumPathParam `form:"enumPathParam,omitempty" json:"enumPathParam,omitempty"`
+}
+
+// EnumParamsParamsEnumPathParam defines parameters for EnumParams.
+type EnumParamsParamsEnumPathParam int32
+
+// GetHeaderParams defines parameters for GetHeader.
+type GetHeaderParams struct {
+ // XPrimitive primitive
+ XPrimitive *int32 `json:"X-Primitive,omitempty"`
+
+ // XPrimitiveExploded primitive
+ XPrimitiveExploded *int32 `json:"X-Primitive-Exploded,omitempty"`
+
+ // XArrayExploded exploded array
+ XArrayExploded *[]int32 `json:"X-Array-Exploded,omitempty"`
+
+ // XArray array
+ XArray *[]int32 `json:"X-Array,omitempty"`
+
+ // XObjectExploded exploded object
+ XObjectExploded *Object `json:"X-Object-Exploded,omitempty"`
+
+ // XObject object
+ XObject *Object `json:"X-Object,omitempty"`
+
+ // XComplexObject complex object
+ XComplexObject *ComplexObject `json:"X-Complex-Object,omitempty"`
+
+ // N1StartingWithNumber name starting with number
+ N1StartingWithNumber *string `json:"1-Starting-With-Number,omitempty"`
+}
+
+// GetDeepObjectParams defines parameters for GetDeepObject.
+type GetDeepObjectParams struct {
+ // DeepObj deep object
+ DeepObj ComplexObject `json:"deepObj"`
+}
+
+// GetQueryDelimitedParams defines parameters for GetQueryDelimited.
+type GetQueryDelimitedParams struct {
+ // Sa space delimited array
+ Sa *[]int32 `json:"sa,omitempty"`
+
+ // Pa pipe delimited array
+ Pa *[]int32 `json:"pa,omitempty"`
+}
+
+// GetQueryFormParams defines parameters for GetQueryForm.
+type GetQueryFormParams struct {
+ // Ea exploded array
+ Ea *[]int32 `form:"ea,omitempty" json:"ea,omitempty"`
+
+ // A array
+ A *[]int32 `form:"a,omitempty" json:"a,omitempty"`
+
+ // Eo exploded object
+ Eo *Object `form:"eo,omitempty" json:"eo,omitempty"`
+
+ // O object
+ O *Object `form:"o,omitempty" json:"o,omitempty"`
+
+ // Ep exploded primitive
+ Ep *int32 `form:"ep,omitempty" json:"ep,omitempty"`
+
+ // P primitive
+ P *int32 `form:"p,omitempty" json:"p,omitempty"`
+
+ // Ps primitive string
+ Ps *string `form:"ps,omitempty" json:"ps,omitempty"`
+
+ // Co complex object
+ Co *ComplexObject `form:"co,omitempty" json:"co,omitempty"`
+
+ // N1s name starting with number
+ N1s *string `form:"1s,omitempty" json:"1s,omitempty"`
+}
diff --git a/internal/test/parameters/stdhttp/server.cfg.yaml b/internal/test/parameters/stdhttp/server.cfg.yaml
new file mode 100644
index 0000000000..cae77efded
--- /dev/null
+++ b/internal/test/parameters/stdhttp/server.cfg.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: stdhttpparamsgen
+generate:
+ std-http-server: true
+ embedded-spec: true
+output: gen/server.gen.go
diff --git a/internal/test/parameters/stdhttp/server.go b/internal/test/parameters/stdhttp/server.go
new file mode 100644
index 0000000000..2b1d3b7261
--- /dev/null
+++ b/internal/test/parameters/stdhttp/server.go
@@ -0,0 +1,48 @@
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../parameters.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../parameters.yaml
+
+package stdhttpparams
+
+import (
+ "encoding/json"
+ "net/http"
+
+ gen "github.com/oapi-codegen/oapi-codegen/v2/internal/test/parameters/stdhttp/gen"
+)
+
+type Server struct{}
+
+var _ gen.ServerInterface = (*Server)(nil)
+
+func writeJSON(w http.ResponseWriter, v interface{}) {
+ w.Header().Set("Content-Type", "application/json")
+ _ = json.NewEncoder(w).Encode(v)
+}
+
+func (s *Server) GetContentObject(w http.ResponseWriter, r *http.Request, param gen.ComplexObject) { writeJSON(w, param) }
+func (s *Server) GetCookie(w http.ResponseWriter, r *http.Request, params gen.GetCookieParams) { writeJSON(w, params) }
+func (s *Server) EnumParams(w http.ResponseWriter, r *http.Request, params gen.EnumParamsParams) { w.WriteHeader(http.StatusNoContent) }
+func (s *Server) GetHeader(w http.ResponseWriter, r *http.Request, params gen.GetHeaderParams) { writeJSON(w, params) }
+func (s *Server) GetLabelExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) { writeJSON(w, param) }
+func (s *Server) GetLabelExplodeObject(w http.ResponseWriter, r *http.Request, param gen.Object) { writeJSON(w, param) }
+func (s *Server) GetLabelExplodePrimitive(w http.ResponseWriter, r *http.Request, param int32) { writeJSON(w, param) }
+func (s *Server) GetLabelNoExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) { writeJSON(w, param) }
+func (s *Server) GetLabelNoExplodeObject(w http.ResponseWriter, r *http.Request, param gen.Object) { writeJSON(w, param) }
+func (s *Server) GetLabelPrimitive(w http.ResponseWriter, r *http.Request, param int32) { writeJSON(w, param) }
+func (s *Server) GetMatrixExplodeArray(w http.ResponseWriter, r *http.Request, id []int32) { writeJSON(w, id) }
+func (s *Server) GetMatrixExplodeObject(w http.ResponseWriter, r *http.Request, id gen.Object) { writeJSON(w, id) }
+func (s *Server) GetMatrixExplodePrimitive(w http.ResponseWriter, r *http.Request, id int32) { writeJSON(w, id) }
+func (s *Server) GetMatrixNoExplodeArray(w http.ResponseWriter, r *http.Request, id []int32) { writeJSON(w, id) }
+func (s *Server) GetMatrixNoExplodeObject(w http.ResponseWriter, r *http.Request, id gen.Object) { writeJSON(w, id) }
+func (s *Server) GetMatrixPrimitive(w http.ResponseWriter, r *http.Request, id int32) { writeJSON(w, id) }
+func (s *Server) GetPassThrough(w http.ResponseWriter, r *http.Request, param string) { writeJSON(w, param) }
+func (s *Server) GetDeepObject(w http.ResponseWriter, r *http.Request, params gen.GetDeepObjectParams) { writeJSON(w, params) }
+func (s *Server) GetQueryDelimited(w http.ResponseWriter, r *http.Request, params gen.GetQueryDelimitedParams) { writeJSON(w, params) }
+func (s *Server) GetQueryForm(w http.ResponseWriter, r *http.Request, params gen.GetQueryFormParams) { writeJSON(w, params) }
+func (s *Server) GetSimpleExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) { writeJSON(w, param) }
+func (s *Server) GetSimpleExplodeObject(w http.ResponseWriter, r *http.Request, param gen.Object) { writeJSON(w, param) }
+func (s *Server) GetSimpleExplodePrimitive(w http.ResponseWriter, r *http.Request, param int32) { writeJSON(w, param) }
+func (s *Server) GetSimpleNoExplodeArray(w http.ResponseWriter, r *http.Request, param []int32) { writeJSON(w, param) }
+func (s *Server) GetSimpleNoExplodeObject(w http.ResponseWriter, r *http.Request, param gen.Object) { writeJSON(w, param) }
+func (s *Server) GetSimplePrimitive(w http.ResponseWriter, r *http.Request, param int32) { writeJSON(w, param) }
+func (s *Server) GetStartingWithNumber(w http.ResponseWriter, r *http.Request, n1param string) { writeJSON(w, n1param) }
diff --git a/internal/test/parameters/stdhttp/types.cfg.yaml b/internal/test/parameters/stdhttp/types.cfg.yaml
new file mode 100644
index 0000000000..28ce3eff98
--- /dev/null
+++ b/internal/test/parameters/stdhttp/types.cfg.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: stdhttpparamsgen
+generate:
+ models: true
+output: gen/types.gen.go
diff --git a/internal/test/pathalias/client-config.yaml b/internal/test/pathalias/client-config.yaml
new file mode 100644
index 0000000000..d191dfa49d
--- /dev/null
+++ b/internal/test/pathalias/client-config.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: pathalias
+generate:
+ client: true
+output: client.gen.go
diff --git a/internal/test/pathalias/client.gen.go b/internal/test/pathalias/client.gen.go
new file mode 100644
index 0000000000..bf291c3cee
--- /dev/null
+++ b/internal/test/pathalias/client.gen.go
@@ -0,0 +1,372 @@
+// Package pathalias provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package pathalias
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "net/url"
+ "strings"
+)
+
+// RequestEditorFn is the function signature for the RequestEditor callback function
+type RequestEditorFn func(ctx context.Context, req *http.Request) error
+
+// Doer performs HTTP requests.
+//
+// The standard http.Client implements this interface.
+type HttpRequestDoer interface {
+ Do(req *http.Request) (*http.Response, error)
+}
+
+// Client which conforms to the OpenAPI3 specification for this service.
+type Client struct {
+ // The endpoint of the server conforming to this interface, with scheme,
+ // https://api.deepmap.com for example. This can contain a path relative
+ // to the server, such as https://api.deepmap.com/dev-test, and all the
+ // paths in the swagger spec will be appended to the server.
+ Server string
+
+ // Doer for performing requests, typically a *http.Client with any
+ // customized settings, such as certificate chains.
+ Client HttpRequestDoer
+
+ // A list of callbacks for modifying requests which are generated before sending over
+ // the network.
+ RequestEditors []RequestEditorFn
+}
+
+// ClientOption allows setting custom parameters during construction
+type ClientOption func(*Client) error
+
+// Creates a new Client, with reasonable defaults
+func NewClient(server string, opts ...ClientOption) (*Client, error) {
+ // create a client with sane default values
+ client := Client{
+ Server: server,
+ }
+ // mutate client and add all optional params
+ for _, o := range opts {
+ if err := o(&client); err != nil {
+ return nil, err
+ }
+ }
+ // ensure the server URL always has a trailing slash
+ if !strings.HasSuffix(client.Server, "/") {
+ client.Server += "/"
+ }
+ // create httpClient, if not already present
+ if client.Client == nil {
+ client.Client = &http.Client{}
+ }
+ return &client, nil
+}
+
+// WithHTTPClient allows overriding the default Doer, which is
+// automatically created using http.Client. This is useful for tests.
+func WithHTTPClient(doer HttpRequestDoer) ClientOption {
+ return func(c *Client) error {
+ c.Client = doer
+ return nil
+ }
+}
+
+// WithRequestEditorFn allows setting up a callback function, which will be
+// called right before sending the request. This can be used to mutate the request.
+func WithRequestEditorFn(fn RequestEditorFn) ClientOption {
+ return func(c *Client) error {
+ c.RequestEditors = append(c.RequestEditors, fn)
+ return nil
+ }
+}
+
+// The interface specification for the client above.
+type ClientInterface interface {
+ // GetTest request
+ GetTest(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // GetTestAlias0 request
+ GetTestAlias0(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+}
+
+func (c *Client) GetTest(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetTestRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) GetTestAlias0(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewGetTestAlias0Request(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+// NewGetTestRequest generates requests for GetTest
+func NewGetTestRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/test")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewGetTestAlias0Request generates requests for GetTestAlias0
+func NewGetTestAlias0Request(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/test2")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+func (c *Client) applyEditors(ctx context.Context, req *http.Request, additionalEditors []RequestEditorFn) error {
+ for _, r := range c.RequestEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ for _, r := range additionalEditors {
+ if err := r(ctx, req); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// ClientWithResponses builds on ClientInterface to offer response payloads
+type ClientWithResponses struct {
+ ClientInterface
+}
+
+// NewClientWithResponses creates a new ClientWithResponses, which wraps
+// Client with return type handling
+func NewClientWithResponses(server string, opts ...ClientOption) (*ClientWithResponses, error) {
+ client, err := NewClient(server, opts...)
+ if err != nil {
+ return nil, err
+ }
+ return &ClientWithResponses{client}, nil
+}
+
+// WithBaseURL overrides the baseURL.
+func WithBaseURL(baseURL string) ClientOption {
+ return func(c *Client) error {
+ newBaseURL, err := url.Parse(baseURL)
+ if err != nil {
+ return err
+ }
+ c.Server = newBaseURL.String()
+ return nil
+ }
+}
+
+// ClientWithResponsesInterface is the interface specification for the client with responses above.
+type ClientWithResponsesInterface interface {
+ // GetTestWithResponse request
+ GetTestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetTestResponse, error)
+
+ // GetTestAlias0WithResponse request
+ GetTestAlias0WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetTestAlias0Response, error)
+}
+
+type GetTestResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *B
+}
+
+// GetJSON200 returns JSON200
+func (r GetTestResponse) GetJSON200() *B {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetTestResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetTestResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetTestResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetTestResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type GetTestAlias0Response struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *B
+}
+
+// GetJSON200 returns JSON200
+func (r GetTestAlias0Response) GetJSON200() *B {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetTestAlias0Response) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r GetTestAlias0Response) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r GetTestAlias0Response) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetTestAlias0Response) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+// GetTestWithResponse request returning *GetTestResponse
+func (c *ClientWithResponses) GetTestWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetTestResponse, error) {
+ rsp, err := c.GetTest(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetTestResponse(rsp)
+}
+
+// GetTestAlias0WithResponse request returning *GetTestAlias0Response
+func (c *ClientWithResponses) GetTestAlias0WithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetTestAlias0Response, error) {
+ rsp, err := c.GetTestAlias0(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseGetTestAlias0Response(rsp)
+}
+
+// ParseGetTestResponse parses an HTTP response from a GetTestWithResponse call
+func ParseGetTestResponse(rsp *http.Response) (*GetTestResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetTestResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest B
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseGetTestAlias0Response parses an HTTP response from a GetTestAlias0WithResponse call
+func ParseGetTestAlias0Response(rsp *http.Response) (*GetTestAlias0Response, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &GetTestAlias0Response{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest B
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
diff --git a/internal/test/pathalias/doc.go b/internal/test/pathalias/doc.go
new file mode 100644
index 0000000000..a88f063e40
--- /dev/null
+++ b/internal/test/pathalias/doc.go
@@ -0,0 +1,4 @@
+package pathalias
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server-config.yaml spec.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=client-config.yaml spec.yaml
diff --git a/internal/test/pathalias/server-config.yaml b/internal/test/pathalias/server-config.yaml
new file mode 100644
index 0000000000..d4a4de5248
--- /dev/null
+++ b/internal/test/pathalias/server-config.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: pathalias
+generate:
+ chi-server: true
+ models: true
+output: server.gen.go
diff --git a/internal/test/pathalias/server.gen.go b/internal/test/pathalias/server.gen.go
new file mode 100644
index 0000000000..2883b80b82
--- /dev/null
+++ b/internal/test/pathalias/server.gen.go
@@ -0,0 +1,179 @@
+// Package pathalias provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package pathalias
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/go-chi/chi/v5"
+)
+
+// B defines model for B.
+type B struct {
+ A *string `json:"A,omitempty"`
+}
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+ // test
+ // (GET /test)
+ GetTest(w http.ResponseWriter, r *http.Request)
+}
+
+// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
+
+type Unimplemented struct{}
+
+// test
+// (GET /test)
+func (_ Unimplemented) GetTest(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetTest operation middleware
+func (siw *ServerInterfaceWrapper) GetTest(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetTest(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{})
+}
+
+type ChiServerOptions struct {
+ BaseURL string
+ BaseRouter chi.Router
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, r chi.Router) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseRouter: r,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, r chi.Router, baseURL string) http.Handler {
+ return HandlerWithOptions(si, ChiServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: r,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handler {
+ r := options.BaseRouter
+
+ if r == nil {
+ r = chi.NewRouter()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/test", wrapper.GetTest)
+ })
+ r.Group(func(r chi.Router) {
+ r.Get(options.BaseURL+"/test2", wrapper.GetTest)
+ })
+
+ return r
+}
diff --git a/internal/test/pathalias/spec.yaml b/internal/test/pathalias/spec.yaml
new file mode 100644
index 0000000000..f7b0a3b9f5
--- /dev/null
+++ b/internal/test/pathalias/spec.yaml
@@ -0,0 +1,28 @@
+openapi: "3.0.1"
+info:
+ title: test
+ description: API description.
+ version: 0.1.0
+servers: []
+paths:
+ /test:
+ get:
+ summary: test
+ operationId: getTest
+ responses:
+ "200":
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/B"
+ /test2:
+ $ref: "#/paths/~1test"
+
+components:
+ schemas:
+ B:
+ type: object
+ properties:
+ A:
+ type: string
diff --git a/internal/test/schemas/config.yaml b/internal/test/schemas/config.yaml
index 9086953659..a054e8daf8 100644
--- a/internal/test/schemas/config.yaml
+++ b/internal/test/schemas/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
package: schemas
generate:
echo-server: true
diff --git a/internal/test/schemas/doc.go b/internal/test/schemas/doc.go
index b3a7d25c05..a4147ee5af 100644
--- a/internal/test/schemas/doc.go
+++ b/internal/test/schemas/doc.go
@@ -1,3 +1,3 @@
package schemas
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml schemas.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml schemas.yaml
diff --git a/internal/test/schemas/schemas.gen.go b/internal/test/schemas/schemas.gen.go
index 883074d420..05562de26b 100644
--- a/internal/test/schemas/schemas.gen.go
+++ b/internal/test/schemas/schemas.gen.go
@@ -1,11 +1,11 @@
// Package schemas provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package schemas
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -17,7 +17,7 @@ import (
"path"
"strings"
- "gopkg.in/yaml.v2"
+ "go.yaml.in/yaml/v3"
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
@@ -25,7 +25,7 @@ import (
)
const (
- Access_tokenScopes = "access_token.Scopes"
+ Access_tokenScopes accessTokenContextKey = "access_token.Scopes"
)
// Defines values for EnumInObjInArrayVal.
@@ -34,6 +34,18 @@ const (
Second EnumInObjInArrayVal = "second"
)
+// Valid indicates whether the value is a known member of the EnumInObjInArrayVal enum.
+func (e EnumInObjInArrayVal) Valid() bool {
+ switch e {
+ case First:
+ return true
+ case Second:
+ return true
+ default:
+ return false
+ }
+}
+
// N5StartsWithNumber This schema name starts with a number
type N5StartsWithNumber = map[string]interface{}
@@ -52,11 +64,11 @@ type CustomStringType = string
type DeprecatedProperty struct {
// NewProp Use this now!
NewProp string `json:"newProp"`
- // Deprecated:
+ // Deprecated: this property has been marked as deprecated upstream, but no `x-deprecated-reason` was set
OldProp1 *string `json:"oldProp1,omitempty"`
// OldProp2 It used to do this and that
- // Deprecated:
+ // Deprecated: this property has been marked as deprecated upstream, but no `x-deprecated-reason` was set
OldProp2 *string `json:"oldProp2,omitempty"`
// Deprecated: Use NewProp instead!
OldProp3 *string `json:"oldProp3,omitempty"`
@@ -80,7 +92,7 @@ type GenericObject = map[string]interface{}
// NullableProperties defines model for NullableProperties.
type NullableProperties struct {
Optional *string `json:"optional,omitempty"`
- OptionalAndNullable *string `json:"optionalAndNullable"`
+ OptionalAndNullable *string `json:"optionalAndNullable,omitempty"`
Required string `json:"required"`
RequiredAndNullable *string `json:"requiredAndNullable"`
}
@@ -99,6 +111,9 @@ type InnerRenamedAnonymousObject struct {
// StringInPath defines model for StringInPath.
type StringInPath = string
+// accessTokenContextKey is the context key for access-token security scheme
+type accessTokenContextKey string
+
// Issue9JSONBody defines parameters for Issue9.
type Issue9JSONBody = interface{}
@@ -384,7 +399,7 @@ func NewEnsureEverythingIsReferencedRequest(server string) (*http.Request, error
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -411,7 +426,7 @@ func NewIssue1051Request(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -438,7 +453,7 @@ func NewIssue127Request(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -476,7 +491,7 @@ func NewIssue185RequestWithBody(server string, contentType string, body io.Reade
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -492,7 +507,7 @@ func NewIssue209Request(server string, str StringInPath) (*http.Request, error)
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("simple", false, "str", runtime.ParamLocationPath, str)
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "str", str, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
if err != nil {
return nil, err
}
@@ -512,7 +527,7 @@ func NewIssue209Request(server string, str StringInPath) (*http.Request, error)
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -526,7 +541,7 @@ func NewIssue30Request(server string, pFallthrough string) (*http.Request, error
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("simple", false, "fallthrough", runtime.ParamLocationPath, pFallthrough)
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "fallthrough", pFallthrough, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
if err != nil {
return nil, err
}
@@ -546,7 +561,7 @@ func NewIssue30Request(server string, pFallthrough string) (*http.Request, error
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -573,7 +588,7 @@ func NewGetIssues375Request(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -587,7 +602,7 @@ func NewIssue41Request(server string, n1param N5StartsWithNumber) (*http.Request
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("simple", false, "1param", runtime.ParamLocationPath, n1param)
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "1param", n1param, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "object", Format: ""})
if err != nil {
return nil, err
}
@@ -607,7 +622,7 @@ func NewIssue41Request(server string, n1param N5StartsWithNumber) (*http.Request
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -646,24 +661,29 @@ func NewIssue9RequestWithBody(server string, params *Issue9Params, contentType s
}
if params != nil {
+ // queryValues collects non-styled parameters (passthrough, JSON)
+ // that are safe to round-trip through url.Values.Encode().
queryValues := queryURL.Query()
+ // rawQueryFragments collects pre-encoded query fragments from
+ // styled parameters, preserving literal commas as delimiters
+ // per the OpenAPI spec (e.g. "color=blue,black,brown").
+ var rawQueryFragments []string
- if queryFrag, err := runtime.StyleParamWithLocation("form", true, "foo", runtime.ParamLocationQuery, params.Foo); err != nil {
- return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("form", true, "foo", params.Foo, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "string", Format: ""}); err != nil {
return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
}
}
- queryURL.RawQuery = queryValues.Encode()
+ if encoded := queryValues.Encode(); encoded != "" {
+ rawQueryFragments = append(rawQueryFragments, encoded)
+ }
+ queryURL.RawQuery = strings.Join(rawQueryFragments, "&")
}
- req, err := http.NewRequest("GET", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -692,7 +712,7 @@ func NewIssue975Request(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -792,6 +812,24 @@ type EnsureEverythingIsReferencedResponse struct {
}
}
+// GetJSON200 returns JSON200
+func (r EnsureEverythingIsReferencedResponse) GetJSON200() *struct {
+ AnyType1 *AnyType1 `json:"anyType1,omitempty"`
+
+ // AnyType2 AnyType2 represents any type.
+ //
+ // This should be an interface{}
+ AnyType2 *AnyType2 `json:"anyType2,omitempty"`
+ CustomStringType *CustomStringType `foo:"bar" json:"customStringType,omitempty"`
+} {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r EnsureEverythingIsReferencedResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r EnsureEverythingIsReferencedResponse) Status() string {
if r.HTTPResponse != nil {
@@ -808,6 +846,14 @@ func (r EnsureEverythingIsReferencedResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r EnsureEverythingIsReferencedResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type Issue1051Response struct {
Body []byte
HTTPResponse *http.Response
@@ -815,6 +861,21 @@ type Issue1051Response struct {
ApplicationvndSomethingV1JSON200 *map[string]interface{}
}
+// GetJSON200 returns JSON200
+func (r Issue1051Response) GetJSON200() *map[string]interface{} {
+ return r.JSON200
+}
+
+// GetApplicationvndSomethingV1JSON200 returns ApplicationvndSomethingV1JSON200
+func (r Issue1051Response) GetApplicationvndSomethingV1JSON200() *map[string]interface{} {
+ return r.ApplicationvndSomethingV1JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r Issue1051Response) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r Issue1051Response) Status() string {
if r.HTTPResponse != nil {
@@ -831,6 +892,14 @@ func (r Issue1051Response) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r Issue1051Response) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type Issue127Response struct {
Body []byte
HTTPResponse *http.Response
@@ -840,6 +909,31 @@ type Issue127Response struct {
JSONDefault *GenericObject
}
+// GetJSON200 returns JSON200
+func (r Issue127Response) GetJSON200() *GenericObject {
+ return r.JSON200
+}
+
+// GetXML200 returns XML200
+func (r Issue127Response) GetXML200() *GenericObject {
+ return r.XML200
+}
+
+// GetYAML200 returns YAML200
+func (r Issue127Response) GetYAML200() *GenericObject {
+ return r.YAML200
+}
+
+// GetJSONDefault returns JSONDefault
+func (r Issue127Response) GetJSONDefault() *GenericObject {
+ return r.JSONDefault
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r Issue127Response) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r Issue127Response) Status() string {
if r.HTTPResponse != nil {
@@ -856,11 +950,24 @@ func (r Issue127Response) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r Issue127Response) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type Issue185Response struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r Issue185Response) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r Issue185Response) Status() string {
if r.HTTPResponse != nil {
@@ -877,11 +984,24 @@ func (r Issue185Response) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r Issue185Response) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type Issue209Response struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r Issue209Response) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r Issue209Response) Status() string {
if r.HTTPResponse != nil {
@@ -898,11 +1018,24 @@ func (r Issue209Response) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r Issue209Response) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type Issue30Response struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r Issue30Response) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r Issue30Response) Status() string {
if r.HTTPResponse != nil {
@@ -919,12 +1052,30 @@ func (r Issue30Response) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r Issue30Response) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type GetIssues375Response struct {
Body []byte
HTTPResponse *http.Response
JSON200 *EnumInObjInArray
}
+// GetJSON200 returns JSON200
+func (r GetIssues375Response) GetJSON200() *EnumInObjInArray {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r GetIssues375Response) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r GetIssues375Response) Status() string {
if r.HTTPResponse != nil {
@@ -941,11 +1092,24 @@ func (r GetIssues375Response) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r GetIssues375Response) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type Issue41Response struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r Issue41Response) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r Issue41Response) Status() string {
if r.HTTPResponse != nil {
@@ -962,11 +1126,24 @@ func (r Issue41Response) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r Issue41Response) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type Issue9Response struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r Issue9Response) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r Issue9Response) Status() string {
if r.HTTPResponse != nil {
@@ -983,12 +1160,30 @@ func (r Issue9Response) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r Issue9Response) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type Issue975Response struct {
Body []byte
HTTPResponse *http.Response
JSON200 *DeprecatedProperty
}
+// GetJSON200 returns JSON200
+func (r Issue975Response) GetJSON200() *DeprecatedProperty {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r Issue975Response) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r Issue975Response) Status() string {
if r.HTTPResponse != nil {
@@ -1005,6 +1200,14 @@ func (r Issue975Response) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r Issue975Response) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// EnsureEverythingIsReferencedWithResponse request returning *EnsureEverythingIsReferencedResponse
func (c *ClientWithResponses) EnsureEverythingIsReferencedWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*EnsureEverythingIsReferencedResponse, error) {
rsp, err := c.EnsureEverythingIsReferenced(ctx, reqEditors...)
@@ -1406,7 +1609,7 @@ type ServerInterfaceWrapper struct {
func (w *ServerInterfaceWrapper) EnsureEverythingIsReferenced(ctx echo.Context) error {
var err error
- ctx.Set(Access_tokenScopes, []string{})
+ ctx.Set(string(Access_tokenScopes), []string{})
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.EnsureEverythingIsReferenced(ctx)
@@ -1417,7 +1620,7 @@ func (w *ServerInterfaceWrapper) EnsureEverythingIsReferenced(ctx echo.Context)
func (w *ServerInterfaceWrapper) Issue1051(ctx echo.Context) error {
var err error
- ctx.Set(Access_tokenScopes, []string{})
+ ctx.Set(string(Access_tokenScopes), []string{})
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.Issue1051(ctx)
@@ -1428,7 +1631,7 @@ func (w *ServerInterfaceWrapper) Issue1051(ctx echo.Context) error {
func (w *ServerInterfaceWrapper) Issue127(ctx echo.Context) error {
var err error
- ctx.Set(Access_tokenScopes, []string{})
+ ctx.Set(string(Access_tokenScopes), []string{})
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.Issue127(ctx)
@@ -1439,7 +1642,7 @@ func (w *ServerInterfaceWrapper) Issue127(ctx echo.Context) error {
func (w *ServerInterfaceWrapper) Issue185(ctx echo.Context) error {
var err error
- ctx.Set(Access_tokenScopes, []string{})
+ ctx.Set(string(Access_tokenScopes), []string{})
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.Issue185(ctx)
@@ -1452,12 +1655,12 @@ func (w *ServerInterfaceWrapper) Issue209(ctx echo.Context) error {
// ------------- Path parameter "str" -------------
var str StringInPath
- err = runtime.BindStyledParameterWithLocation("simple", false, "str", runtime.ParamLocationPath, ctx.Param("str"), &str)
+ err = runtime.BindStyledParameterWithOptions("simple", "str", ctx.Param("str"), &str, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter str: %s", err))
}
- ctx.Set(Access_tokenScopes, []string{})
+ ctx.Set(string(Access_tokenScopes), []string{})
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.Issue209(ctx, str)
@@ -1470,12 +1673,12 @@ func (w *ServerInterfaceWrapper) Issue30(ctx echo.Context) error {
// ------------- Path parameter "fallthrough" -------------
var pFallthrough string
- err = runtime.BindStyledParameterWithLocation("simple", false, "fallthrough", runtime.ParamLocationPath, ctx.Param("fallthrough"), &pFallthrough)
+ err = runtime.BindStyledParameterWithOptions("simple", "fallthrough", ctx.Param("fallthrough"), &pFallthrough, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter fallthrough: %s", err))
}
- ctx.Set(Access_tokenScopes, []string{})
+ ctx.Set(string(Access_tokenScopes), []string{})
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.Issue30(ctx, pFallthrough)
@@ -1486,7 +1689,7 @@ func (w *ServerInterfaceWrapper) Issue30(ctx echo.Context) error {
func (w *ServerInterfaceWrapper) GetIssues375(ctx echo.Context) error {
var err error
- ctx.Set(Access_tokenScopes, []string{})
+ ctx.Set(string(Access_tokenScopes), []string{})
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.GetIssues375(ctx)
@@ -1499,12 +1702,12 @@ func (w *ServerInterfaceWrapper) Issue41(ctx echo.Context) error {
// ------------- Path parameter "1param" -------------
var n1param N5StartsWithNumber
- err = runtime.BindStyledParameterWithLocation("simple", false, "1param", runtime.ParamLocationPath, ctx.Param("1param"), &n1param)
+ err = runtime.BindStyledParameterWithOptions("simple", "1param", ctx.Param("1param"), &n1param, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "object", Format: ""})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter 1param: %s", err))
}
- ctx.Set(Access_tokenScopes, []string{})
+ ctx.Set(string(Access_tokenScopes), []string{})
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.Issue41(ctx, n1param)
@@ -1515,13 +1718,13 @@ func (w *ServerInterfaceWrapper) Issue41(ctx echo.Context) error {
func (w *ServerInterfaceWrapper) Issue9(ctx echo.Context) error {
var err error
- ctx.Set(Access_tokenScopes, []string{})
+ ctx.Set(string(Access_tokenScopes), []string{})
// Parameter object where we will unmarshal all parameters from the context
var params Issue9Params
// ------------- Required query parameter "foo" -------------
- err = runtime.BindQueryParameter("form", true, true, "foo", ctx.QueryParams(), ¶ms.Foo)
+ err = runtime.BindQueryParameterWithOptions("form", true, true, "foo", ctx.QueryParams(), ¶ms.Foo, runtime.BindQueryParameterOptions{Type: "string", Format: ""})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter foo: %s", err))
}
@@ -1535,7 +1738,7 @@ func (w *ServerInterfaceWrapper) Issue9(ctx echo.Context) error {
func (w *ServerInterfaceWrapper) Issue975(ctx echo.Context) error {
var err error
- ctx.Set(Access_tokenScopes, []string{})
+ ctx.Set(string(Access_tokenScopes), []string{})
// Invoke the callback with all the unmarshaled arguments
err = w.Handler.Issue975(ctx)
@@ -1557,78 +1760,99 @@ type EchoRouter interface {
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
}
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
- router.GET(baseURL+"/ensure-everything-is-referenced", wrapper.EnsureEverythingIsReferenced)
- router.GET(baseURL+"/issues/1051", wrapper.Issue1051)
- router.GET(baseURL+"/issues/127", wrapper.Issue127)
- router.GET(baseURL+"/issues/185", wrapper.Issue185)
- router.GET(baseURL+"/issues/209/$:str", wrapper.Issue209)
- router.GET(baseURL+"/issues/30/:fallthrough", wrapper.Issue30)
- router.GET(baseURL+"/issues/375", wrapper.GetIssues375)
- router.GET(baseURL+"/issues/41/:1param", wrapper.Issue41)
- router.GET(baseURL+"/issues/9", wrapper.Issue9)
- router.GET(baseURL+"/issues/975", wrapper.Issue975)
+ router.GET(options.BaseURL+"/ensure-everything-is-referenced", wrapper.EnsureEverythingIsReferenced, options.OperationMiddlewares["ensureEverythingIsReferenced"]...)
+ router.GET(options.BaseURL+"/issues/1051", wrapper.Issue1051, options.OperationMiddlewares["Issue1051"]...)
+ router.GET(options.BaseURL+"/issues/127", wrapper.Issue127, options.OperationMiddlewares["Issue127"]...)
+ router.GET(options.BaseURL+"/issues/185", wrapper.Issue185, options.OperationMiddlewares["Issue185"]...)
+ router.GET(options.BaseURL+"/issues/209/$:str", wrapper.Issue209, options.OperationMiddlewares["Issue209"]...)
+ router.GET(options.BaseURL+"/issues/30/:fallthrough", wrapper.Issue30, options.OperationMiddlewares["Issue30"]...)
+ router.GET(options.BaseURL+"/issues/375", wrapper.GetIssues375, options.OperationMiddlewares["GetIssues375"]...)
+ router.GET(options.BaseURL+"/issues/41/:1param", wrapper.Issue41, options.OperationMiddlewares["Issue41"]...)
+ router.GET(options.BaseURL+"/issues/9", wrapper.Issue9, options.OperationMiddlewares["Issue9"]...)
+ router.GET(options.BaseURL+"/issues/975", wrapper.Issue975, options.OperationMiddlewares["Issue975"]...)
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/7RYXW/buBL9Kyxvgftw/Z0GbfyW2+0WLrBJ0GTRhzoPtDi22EhDlaTsCIb++2JI2bIj",
- "yW02bV5iiZzhmTPDM6S2PNJpphHQWT7d8kwYkYID459unVG4muGNcDE9S7CRUZlTGvmUXzLrx1kmXMz2",
- "lrzHFQ3TW97jKFLgU24dDRj4nisDkk+dyaHHbRRDKsi1K7JqmsIVL8tyN+iBnN86YZz9olx8lacLME00",
- "d7GyLJgwWpNZb8I2ysVMMAxmvd1CevENIsfLHr/E4q7IYMyn2/pp0hJuNcIMZAYsMcYEFowcDuY4x4Ag",
- "1nki2QKYQKbQgVmKCLblHGmt97l1Og203nkgW77UJhWOT3nkB2uIFRc9/tjXIlP9SEtYAfbh0RnRd2Jl",
- "g7nmU74QhhNnfxC2SDiQN0ZnYFzhsxp+K/AWCBsabEb4twXmKAjUm1cNHGWP68S7HQfT3Uq7ZHZNn7RP",
- "P1575lhuQTKnmdQBhUDJXCzcCSRnP4OECKzn9A0Iuw/3KnDBFFoHQr468P3mV8N+Ho7ycLd83SdtD4/f",
- "t9TyB8zTGV4vvs3w0hjhk68cpLZZBWuR0D/APCX/S2UsQbYQaZQHzvc7smW56oXwS5U9/hEQjIquw4R6",
- "V9cWV3mSiEUCN0dYjpFpT26A10x8NXiJcufL1/T+d0ct1lxuuwef5/RJhva/2/21pes6d2BIB0jYLlFj",
- "kerczhCDwB3TojpeH4ZEgrMC08CmZHN9KseV7tPLfiXSfuXPQE9yD+d6DzfM2v6ABz+rV8FtRl36GsuN",
- "csUtqXWIQkQRWNt3+gGQnhcgDJg/d9L46ctdP+gkCzOZnzmYI6/6BC0RjOp9FzuXhVaicKlbWgZYxyJh",
- "wbKlNmwtjNK5Zcra3L/KUTK9BsOcSmHAbhIQFpiQkgnmdrZkOkdqBIt8xZbqEWSA5ZSj0gmr3IJZe2hr",
- "MDasPh6MBqNQ0oAiU3zKzwajwZj3fOv0tAwBbW6gD2swhYsVrvrK9g0swQBGoZpX4Dq6IaDMtELH4FFZ",
- "Z5nVXphY3fJZJJB6VWSANIkp9Bo2R5tB5JUMtaMJmckRpI+Lik/QMjPJp/yDB/hhj29mP9foqDBsptGG",
- "JE9GI/oXaXSAHrTIskRF3tvwm1fD7cGZ4LjQRd2n+WsDSz7l/xnWoQyr48Jw38/L3s5m8pM2E7KJWnr0",
- "KdtGT2+RyvDX48NQW8Px6Hzcmbu/8sSpLAGWglTCny8sI9KEQvbp9vqqJQ0z8uu9vpDz5m49nL9GObA6",
- "BZ/qwXr8vx87eBr55G134OIBGJUTy9HmWaYN1aSH/ugqHqTG/zqWGYA0c6ye5UcHncxM3r6UmFMlcNz3",
- "npL2mCYvcUXBD1NhHqTe4IsdFeIlaMiNhKXIE/cbyftFET+tvHfn3XJZZMBWZO8jYJsYkO2OGsNdd2O1",
- "IDFhgO3OB91l9+68Og2Adf/XsvhlpLWco0K0BzVO8A4JmIwuhq+31pmyk4f3MUQPlqllfZ0LoUqIElFT",
- "kBTtAU9GF7yJoXd0rfzaHlk9ZXh07SzvD0I4Gw23S5EkLjY6X8VlM4LPYKnVSvYAxUYbeXgjywz4/kxt",
- "jpo9EejvipVwVJS0xHU2+pmwWq69B2Cfdf09Cvptd+HSgb9KTlW5wu4KmVRxoyKgdLoYGB31/bhCupwG",
- "hZ7jJlZRXL23SgLTSxr2h/q2yv4IznNiCddvFNXGXaaxo9+Mh9uxz0F3Rd/sUnTwUUDhKnwW2H8UaEn5",
- "m3AQ+1GCw/onc3sqyOaHjbK8P7mLL7o3b6IAXdi51jdEpjDSxkDkkoJ+J7kE6c+6lSYFGhZaFnTYm2Md",
- "b6emXXTQ8j0HUxwUvtbPK/h/rZNVUzpk4rpSbh8ZP62KFyd2V/01hS0VJLWYrMAxUWkhHadTQNdJ2O/d",
- "Ji1ffFoY8d/q8qhKuGzE5V+vhSlobySwhoRkQOoop9A8Ll7tvt3tzaf++N729Z7y6AW4Ko3cJNVFbDoc",
- "VhcdujoNJECWimwgFCn8PwEAAP//WUiKvIcUAAA=",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "tFhdb9u4Ev0rLG+B+3D9nQZt/Jbb7RYusEnQZNGHOg+0OLbYSEOVpOwIhv77YkjZsiPJbTZtXmKJnOGZ",
+ "M8MzpLY80mmmEdBZPt3yTBiRggPjn26dUbia4Y1wMT1LsJFRmVMa+ZRfMuvHWSZczPaWvMcVDdNb3uMo",
+ "UuBTbh0NGPieKwOST53JocdtFEMqyLUrsmqawhUvy3I36IGc3zphnP2iXHyVpwswTTR3sbIsmDBak1lv",
+ "wjbKxUwwDGa93UJ68Q0ix8sev8TirshgzKfb+mnSEm41wgxkBiwxxgQWjBwO5jjHgCDWeSLZAphAptCB",
+ "WYoItuUcaa33uXU6DbTeeSBbvtQmFY5PeeQHa4gVFz3+2NciU/1IS1gB9uHRGdF3YmWDueZTvhCGE2d/",
+ "ELZIOJA3RmdgXOGzGn4r8BYIGxpsRvi3BeYoCNSbVw0cZY/rxLsdB9PdSrtkdk2ftE8/XnvmWG5BMqeZ",
+ "1AGFQMlcLNwJJGc/g4QIrOf0DQi7D/cqcMEUWgdCvjrw/eZXw34ejvJwt3zdJ20Pj9+31PIHzNMZXi++",
+ "zfDSGOGTrxyktlkFa5HQP8A8Jf9LZSxBthBplAfO9zuyZbnqhfBLlT3+ERCMiq7DhHpX1xZXeZKIRQI3",
+ "R1iOkWlPboDXTHw1eIly58vX9P53Ry3WXG67B5/n9EmG9r/b/bWl6zp3YEgHSNguUWOR6tzOEIPAHdOi",
+ "Ol4fhkSCswLTwKZkc30qx5Xu08t+JdJ+5c9AT3IP53oPN8za/oAHP6tXwW1GXfoay41yxS2pdYhCRBFY",
+ "23f6AZCeFyAMmD930vjpy10/6CQLM5mfOZgjr/oELRGM6n0XO5eFVqJwqVtaBljHImHBsqU2bC2M0rll",
+ "ytrcv8pRMr0Gw5xKYcBuEhAWmJCSCeZ2tmQ6R2oEi3zFluoRZIDllKPSCavcgll7aGswNqw+HowGo1DS",
+ "gCJTfMrPBqPBmPd86/S0DAFtbqAPazCFixWu+sr2DSzBAEahmlfgOrohoMy0QsfgUVlnmdVemFjd8lkk",
+ "kHpVZIA0iSn0GjZHm0HklQy1owmZyRGkj4uKT9AyM8mn/IMH+GGPb2Y/1+ioMGym0YYkT0Yj+hdpdIAe",
+ "tMiyREXe2/CbV8PtwZnguNBF3af5awNLPuX/GdahDKvjwnDfz8vezmbykzYTsolaevQp20ZPb5HK8Nfj",
+ "w1Bbw/HofNyZu7/yxKksAZaCVMKfLywj0oRC9un2+qolDTPy672+kPPmbj2cv0Y5sDoFn+rBevy/Hzt4",
+ "GvnkbXfg4gEYlRPL0eZZpg3VpIf+6CoepMb/OpYZgDRzrJ7lRwedzEzevpSYUyVw3PeekvaYJi9xRcEP",
+ "U2EepN7gix0V4iVoyI2EpcgT9xvJ+0URP628d+fdcllkwFZk7yNgmxiQ7Y4aw113Y7UgMWGA7c4H3WX3",
+ "7rw6DYB1/9ey+GWktZyjQrQHNU7wDgmYjC6Gr7fWmbKTh/cxRA+WqWV9nQuhSogSUVOQFO0BT0YXvImh",
+ "d3St/NoeWT1leHTtLO8PQjgbDbdLkSQuNjpfxWUzgs9gqdVK9gDFRht5eCPLDPj+TG2Omj0R6O+KlXBU",
+ "lLTEdTb6mbBarr0HYJ91/T0K+m134dKBv0pOVbnC7gqZVHGjIqB0uhgYHfX9uEK6nAaFnuMmVlFcvbdK",
+ "AtNLGvaH+rbK/gjOc2IJ128U1cZdprGj34yH27HPQXdF3+xSdPBRQOEqfBbYfxRoSfmbcBD7UYLD+idz",
+ "eyrI5oeNsrw/uYsvujdvogBd2LnWN0SmMNLGQOSSgn4nuQTpz7qVJgUaFloWdNibYx1vp6ZddNDyPQdT",
+ "HBS+1s8r+H+tk1VTOmTiulJuHxk/rYoXJ3ZX/TWFLRUktZiswDFRaSEdp1NA10nY790mLV98Whjx3+ry",
+ "qEq4bMTlX6+FKWhvJLCGhGRA6iin0DwuXu2+3e3Np/743vb1nvLoBbgqjdwk1UVsOhxWFx26Og0kQJaK",
+ "bCAUKfw/AQAA//8=",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -1636,7 +1860,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -1654,12 +1878,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -1685,3 +1909,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/server-specific/spec.yaml b/internal/test/server-specific/spec.yaml
new file mode 100644
index 0000000000..ee8daefcdb
--- /dev/null
+++ b/internal/test/server-specific/spec.yaml
@@ -0,0 +1,24 @@
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Server-specific tests
+paths:
+ # The dashed path parameter name "addressing-identifier" is not a valid Go
+ # identifier. This exercises GitHub issue #2278: stdhttp's ServeMux requires
+ # wildcard names to be valid Go identifiers.
+ /resources/{addressing-identifier}:
+ get:
+ operationId: getResource
+ parameters:
+ - name: addressing-identifier
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ "200":
+ description: OK
+ content:
+ text/plain:
+ schema:
+ type: string
diff --git a/internal/test/server-specific/stdhttp/config.yaml b/internal/test/server-specific/stdhttp/config.yaml
new file mode 100644
index 0000000000..bcac4ff9be
--- /dev/null
+++ b/internal/test/server-specific/stdhttp/config.yaml
@@ -0,0 +1,6 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: stdhttp
+generate:
+ std-http-server: true
+ models: true
+output: server.gen.go
diff --git a/internal/test/server-specific/stdhttp/doc.go b/internal/test/server-specific/stdhttp/doc.go
new file mode 100644
index 0000000000..17ae8b870d
--- /dev/null
+++ b/internal/test/server-specific/stdhttp/doc.go
@@ -0,0 +1,3 @@
+package stdhttp
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../spec.yaml
diff --git a/internal/test/server-specific/stdhttp/server.gen.go b/internal/test/server-specific/stdhttp/server.gen.go
new file mode 100644
index 0000000000..16962d5dcc
--- /dev/null
+++ b/internal/test/server-specific/stdhttp/server.gen.go
@@ -0,0 +1,180 @@
+//go:build go1.22
+
+// Package stdhttp provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package stdhttp
+
+import (
+ "fmt"
+ "net/http"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (GET /resources/{addressing-identifier})
+ GetResource(w http.ResponseWriter, r *http.Request, addressingIdentifier string)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// GetResource operation middleware
+func (siw *ServerInterfaceWrapper) GetResource(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "addressing-identifier" -------------
+ var addressingIdentifier string
+
+ err = runtime.BindStyledParameterWithOptions("simple", "addressing-identifier", r.PathValue("addressing_identifier"), &addressingIdentifier, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "addressing-identifier", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.GetResource(w, r, addressingIdentifier)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{})
+}
+
+// ServeMux is an abstraction of [http.ServeMux].
+type ServeMux interface {
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+ http.Handler
+}
+
+type StdHTTPServerOptions struct {
+ BaseURL string
+ BaseRouter ServeMux
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/resources/{addressing_identifier}", wrapper.GetResource)
+
+ return m
+}
diff --git a/internal/test/server-specific/stdhttp/server_test.go b/internal/test/server-specific/stdhttp/server_test.go
new file mode 100644
index 0000000000..8b06430952
--- /dev/null
+++ b/internal/test/server-specific/stdhttp/server_test.go
@@ -0,0 +1,33 @@
+//go:build go1.22
+
+package stdhttp
+
+import (
+ "fmt"
+ "net/http"
+ "net/http/httptest"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+type testServer struct {
+ receivedParam string
+}
+
+func (s *testServer) GetResource(w http.ResponseWriter, r *http.Request, addressingIdentifier string) {
+ s.receivedParam = addressingIdentifier
+ _, _ = fmt.Fprint(w, addressingIdentifier)
+}
+
+func TestDashedPathParam(t *testing.T) {
+ server := &testServer{}
+ handler := Handler(server)
+
+ req := httptest.NewRequest(http.MethodGet, "/resources/my-value", nil)
+ rec := httptest.NewRecorder()
+ handler.ServeHTTP(rec, req)
+
+ assert.Equal(t, http.StatusOK, rec.Code, "expected 200 OK, got %d; body: %s", rec.Code, rec.Body.String())
+ assert.Equal(t, "my-value", server.receivedParam, "path parameter was not correctly extracted")
+}
diff --git a/internal/test/server/config.yaml b/internal/test/server/config.yaml
index 729401be70..4e8702b1f3 100644
--- a/internal/test/server/config.yaml
+++ b/internal/test/server/config.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../configuration-schema.json
package: server
generate:
chi-server: true
diff --git a/internal/test/server/doc.go b/internal/test/server/doc.go
index ca7633a98f..f46abed62f 100644
--- a/internal/test/server/doc.go
+++ b/internal/test/server/doc.go
@@ -1,3 +1,3 @@
package server
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=config.yaml ../test-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../test-schema.yaml
diff --git a/internal/test/server/server.gen.go b/internal/test/server/server.gen.go
index 3b44fe7a49..df00ee714b 100644
--- a/internal/test/server/server.gen.go
+++ b/internal/test/server/server.gen.go
@@ -1,9 +1,10 @@
// Package server provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package server
import (
+ "errors"
"fmt"
"net/http"
"time"
@@ -19,6 +20,18 @@ const (
Text GetWithContentTypeParamsContentType = "text"
)
+// Valid indicates whether the value is a known member of the GetWithContentTypeParamsContentType enum.
+func (e GetWithContentTypeParamsContentType) Valid() bool {
+ switch e {
+ case Json:
+ return true
+ case Text:
+ return true
+ default:
+ return false
+ }
+}
+
// EveryTypeOptional defines model for EveryTypeOptional.
type EveryTypeOptional struct {
ArrayInlineField *[]int `json:"array_inline_field,omitempty"`
@@ -238,7 +251,6 @@ type MiddlewareFunc func(http.Handler) http.Handler
// GetEveryTypeOptional operation middleware
func (siw *ServerInterfaceWrapper) GetEveryTypeOptional(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.GetEveryTypeOptional(w, r)
@@ -248,12 +260,11 @@ func (siw *ServerInterfaceWrapper) GetEveryTypeOptional(w http.ResponseWriter, r
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// GetSimple operation middleware
func (siw *ServerInterfaceWrapper) GetSimple(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.GetSimple(w, r)
@@ -263,38 +274,41 @@ func (siw *ServerInterfaceWrapper) GetSimple(w http.ResponseWriter, r *http.Requ
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// GetWithArgs operation middleware
func (siw *ServerInterfaceWrapper) GetWithArgs(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// Parameter object where we will unmarshal all parameters from the context
var params GetWithArgsParams
// ------------- Optional query parameter "optional_argument" -------------
- err = runtime.BindQueryParameter("form", true, false, "optional_argument", r.URL.Query(), ¶ms.OptionalArgument)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "optional_argument", r.URL.Query(), ¶ms.OptionalArgument, runtime.BindQueryParameterOptions{Type: "integer", Format: "int64"})
if err != nil {
- siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "optional_argument", Err: err})
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "optional_argument"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "optional_argument", Err: err})
+ }
return
}
// ------------- Required query parameter "required_argument" -------------
- if paramValue := r.URL.Query().Get("required_argument"); paramValue != "" {
-
- } else {
- siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "required_argument"})
- return
- }
-
- err = runtime.BindQueryParameter("form", true, true, "required_argument", r.URL.Query(), ¶ms.RequiredArgument)
+ err = runtime.BindQueryParameterWithOptions("form", true, true, "required_argument", r.URL.Query(), ¶ms.RequiredArgument, runtime.BindQueryParameterOptions{Type: "integer", Format: "int64"})
if err != nil {
- siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "required_argument", Err: err})
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "required_argument"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "required_argument", Err: err})
+ }
return
}
@@ -309,7 +323,7 @@ func (siw *ServerInterfaceWrapper) GetWithArgs(w http.ResponseWriter, r *http.Re
return
}
- err = runtime.BindStyledParameterWithLocation("simple", false, "header_argument", runtime.ParamLocationHeader, valueList[0], &HeaderArgument)
+ err = runtime.BindStyledParameterWithOptions("simple", "header_argument", valueList[0], &HeaderArgument, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: "int32"})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "header_argument", Err: err})
return
@@ -327,19 +341,19 @@ func (siw *ServerInterfaceWrapper) GetWithArgs(w http.ResponseWriter, r *http.Re
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// GetWithReferences operation middleware
func (siw *ServerInterfaceWrapper) GetWithReferences(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// ------------- Path parameter "global_argument" -------------
var globalArgument int64
- err = runtime.BindStyledParameterWithLocation("simple", false, "global_argument", runtime.ParamLocationPath, chi.URLParam(r, "global_argument"), &globalArgument)
+ err = runtime.BindStyledParameterWithOptions("simple", "global_argument", chi.URLParam(r, "global_argument"), &globalArgument, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: "int64"})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "global_argument", Err: err})
return
@@ -348,7 +362,7 @@ func (siw *ServerInterfaceWrapper) GetWithReferences(w http.ResponseWriter, r *h
// ------------- Path parameter "argument" -------------
var argument Argument
- err = runtime.BindStyledParameterWithLocation("simple", false, "argument", runtime.ParamLocationPath, chi.URLParam(r, "argument"), &argument)
+ err = runtime.BindStyledParameterWithOptions("simple", "argument", chi.URLParam(r, "argument"), &argument, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "argument", Err: err})
return
@@ -362,19 +376,19 @@ func (siw *ServerInterfaceWrapper) GetWithReferences(w http.ResponseWriter, r *h
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// GetWithContentType operation middleware
func (siw *ServerInterfaceWrapper) GetWithContentType(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// ------------- Path parameter "content_type" -------------
var contentType GetWithContentTypeParamsContentType
- err = runtime.BindStyledParameterWithLocation("simple", false, "content_type", runtime.ParamLocationPath, chi.URLParam(r, "content_type"), &contentType)
+ err = runtime.BindStyledParameterWithOptions("simple", "content_type", chi.URLParam(r, "content_type"), &contentType, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "content_type", Err: err})
return
@@ -388,12 +402,11 @@ func (siw *ServerInterfaceWrapper) GetWithContentType(w http.ResponseWriter, r *
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// GetReservedKeyword operation middleware
func (siw *ServerInterfaceWrapper) GetReservedKeyword(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.GetReservedKeyword(w, r)
@@ -403,19 +416,19 @@ func (siw *ServerInterfaceWrapper) GetReservedKeyword(w http.ResponseWriter, r *
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// CreateResource operation middleware
func (siw *ServerInterfaceWrapper) CreateResource(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// ------------- Path parameter "argument" -------------
var argument Argument
- err = runtime.BindStyledParameterWithLocation("simple", false, "argument", runtime.ParamLocationPath, chi.URLParam(r, "argument"), &argument)
+ err = runtime.BindStyledParameterWithOptions("simple", "argument", chi.URLParam(r, "argument"), &argument, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "argument", Err: err})
return
@@ -429,19 +442,19 @@ func (siw *ServerInterfaceWrapper) CreateResource(w http.ResponseWriter, r *http
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// CreateResource2 operation middleware
func (siw *ServerInterfaceWrapper) CreateResource2(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// ------------- Path parameter "inline_argument" -------------
var inlineArgument int
- err = runtime.BindStyledParameterWithLocation("simple", false, "inline_argument", runtime.ParamLocationPath, chi.URLParam(r, "inline_argument"), &inlineArgument)
+ err = runtime.BindStyledParameterWithOptions("simple", "inline_argument", chi.URLParam(r, "inline_argument"), &inlineArgument, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: ""})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "inline_argument", Err: err})
return
@@ -452,9 +465,14 @@ func (siw *ServerInterfaceWrapper) CreateResource2(w http.ResponseWriter, r *htt
// ------------- Optional query parameter "inline_query_argument" -------------
- err = runtime.BindQueryParameter("form", true, false, "inline_query_argument", r.URL.Query(), ¶ms.InlineQueryArgument)
+ err = runtime.BindQueryParameterWithOptions("form", true, false, "inline_query_argument", r.URL.Query(), ¶ms.InlineQueryArgument, runtime.BindQueryParameterOptions{Type: "integer", Format: ""})
if err != nil {
- siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "inline_query_argument", Err: err})
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "inline_query_argument"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "inline_query_argument", Err: err})
+ }
return
}
@@ -466,19 +484,19 @@ func (siw *ServerInterfaceWrapper) CreateResource2(w http.ResponseWriter, r *htt
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// UpdateResource3 operation middleware
func (siw *ServerInterfaceWrapper) UpdateResource3(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// ------------- Path parameter "fallthrough" -------------
var pFallthrough int
- err = runtime.BindStyledParameterWithLocation("simple", false, "fallthrough", runtime.ParamLocationPath, chi.URLParam(r, "fallthrough"), &pFallthrough)
+ err = runtime.BindStyledParameterWithOptions("simple", "fallthrough", chi.URLParam(r, "fallthrough"), &pFallthrough, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "integer", Format: ""})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "fallthrough", Err: err})
return
@@ -492,12 +510,11 @@ func (siw *ServerInterfaceWrapper) UpdateResource3(w http.ResponseWriter, r *htt
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// GetResponseWithReference operation middleware
func (siw *ServerInterfaceWrapper) GetResponseWithReference(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.GetResponseWithReference(w, r)
@@ -507,7 +524,7 @@ func (siw *ServerInterfaceWrapper) GetResponseWithReference(w http.ResponseWrite
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
type UnescapedCookieParamError struct {
diff --git a/internal/test/strict-server/chi/server.cfg.yaml b/internal/test/strict-server/chi/server.cfg.yaml
index ca1c62c3c5..35425d6ec7 100644
--- a/internal/test/strict-server/chi/server.cfg.yaml
+++ b/internal/test/strict-server/chi/server.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
chi-server: true
diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go
index 90fa582437..f54a6191ed 100644
--- a/internal/test/strict-server/chi/server.gen.go
+++ b/internal/test/strict-server/chi/server.gen.go
@@ -1,16 +1,18 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
+ "errors"
"fmt"
"io"
+ "mime"
"mime/multipart"
"net/http"
"net/url"
@@ -20,7 +22,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/go-chi/chi/v5"
"github.com/oapi-codegen/runtime"
- strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"
)
// ServerInterface represents all server handlers.
@@ -32,9 +33,21 @@ type ServerInterface interface {
// (POST /multipart)
MultipartExample(w http.ResponseWriter, r *http.Request)
+ // (POST /multipart-related)
+ MultipartRelatedExample(w http.ResponseWriter, r *http.Request)
+
// (POST /multiple)
MultipleRequestAndResponseTypes(w http.ResponseWriter, r *http.Request)
+ // (POST /no-content-headers)
+ NoContentHeaders(w http.ResponseWriter, r *http.Request)
+
+ // (POST /required-json-body)
+ RequiredJSONBody(w http.ResponseWriter, r *http.Request)
+
+ // (POST /required-text-body)
+ RequiredTextBody(w http.ResponseWriter, r *http.Request)
+
// (GET /reserved-go-keyword-parameters/{type})
ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request, pType string)
@@ -74,11 +87,31 @@ func (_ Unimplemented) MultipartExample(w http.ResponseWriter, r *http.Request)
w.WriteHeader(http.StatusNotImplemented)
}
+// (POST /multipart-related)
+func (_ Unimplemented) MultipartRelatedExample(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
// (POST /multiple)
func (_ Unimplemented) MultipleRequestAndResponseTypes(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNotImplemented)
}
+// (POST /no-content-headers)
+func (_ Unimplemented) NoContentHeaders(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (POST /required-json-body)
+func (_ Unimplemented) RequiredJSONBody(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
+// (POST /required-text-body)
+func (_ Unimplemented) RequiredTextBody(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusNotImplemented)
+}
+
// (GET /reserved-go-keyword-parameters/{type})
func (_ Unimplemented) ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request, pType string) {
w.WriteHeader(http.StatusNotImplemented)
@@ -130,7 +163,6 @@ type MiddlewareFunc func(http.Handler) http.Handler
// JSONExample operation middleware
func (siw *ServerInterfaceWrapper) JSONExample(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.JSONExample(w, r)
@@ -140,12 +172,11 @@ func (siw *ServerInterfaceWrapper) JSONExample(w http.ResponseWriter, r *http.Re
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// MultipartExample operation middleware
func (siw *ServerInterfaceWrapper) MultipartExample(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.MultipartExample(w, r)
@@ -155,12 +186,25 @@ func (siw *ServerInterfaceWrapper) MultipartExample(w http.ResponseWriter, r *ht
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
+}
+
+// MultipartRelatedExample operation middleware
+func (siw *ServerInterfaceWrapper) MultipartRelatedExample(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.MultipartRelatedExample(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
}
// MultipleRequestAndResponseTypes operation middleware
func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.MultipleRequestAndResponseTypes(w, r)
@@ -170,19 +214,61 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(w http.Respon
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
+}
+
+// NoContentHeaders operation middleware
+func (siw *ServerInterfaceWrapper) NoContentHeaders(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.NoContentHeaders(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// RequiredJSONBody operation middleware
+func (siw *ServerInterfaceWrapper) RequiredJSONBody(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.RequiredJSONBody(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// RequiredTextBody operation middleware
+func (siw *ServerInterfaceWrapper) RequiredTextBody(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.RequiredTextBody(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
}
// ReservedGoKeywordParameters operation middleware
func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// ------------- Path parameter "type" -------------
var pType string
- err = runtime.BindStyledParameterWithLocation("simple", false, "type", runtime.ParamLocationPath, chi.URLParam(r, "type"), &pType)
+ err = runtime.BindStyledParameterWithOptions("simple", "type", chi.URLParam(r, "type"), &pType, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "type", Err: err})
return
@@ -196,12 +282,11 @@ func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(w http.ResponseWr
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// ReusableResponses operation middleware
func (siw *ServerInterfaceWrapper) ReusableResponses(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.ReusableResponses(w, r)
@@ -211,12 +296,11 @@ func (siw *ServerInterfaceWrapper) ReusableResponses(w http.ResponseWriter, r *h
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// TextExample operation middleware
func (siw *ServerInterfaceWrapper) TextExample(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.TextExample(w, r)
@@ -226,12 +310,11 @@ func (siw *ServerInterfaceWrapper) TextExample(w http.ResponseWriter, r *http.Re
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// UnknownExample operation middleware
func (siw *ServerInterfaceWrapper) UnknownExample(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.UnknownExample(w, r)
@@ -241,12 +324,11 @@ func (siw *ServerInterfaceWrapper) UnknownExample(w http.ResponseWriter, r *http
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// UnspecifiedContentType operation middleware
func (siw *ServerInterfaceWrapper) UnspecifiedContentType(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.UnspecifiedContentType(w, r)
@@ -256,12 +338,11 @@ func (siw *ServerInterfaceWrapper) UnspecifiedContentType(w http.ResponseWriter,
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// URLEncodedExample operation middleware
func (siw *ServerInterfaceWrapper) URLEncodedExample(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.URLEncodedExample(w, r)
@@ -271,14 +352,14 @@ func (siw *ServerInterfaceWrapper) URLEncodedExample(w http.ResponseWriter, r *h
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// HeadersExample operation middleware
func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// Parameter object where we will unmarshal all parameters from the context
var params HeadersExampleParams
@@ -294,7 +375,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http
return
}
- err = runtime.BindStyledParameterWithLocation("simple", false, "header1", runtime.ParamLocationHeader, valueList[0], &Header1)
+ err = runtime.BindStyledParameterWithOptions("simple", "header1", valueList[0], &Header1, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "header1", Err: err})
return
@@ -317,7 +398,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http
return
}
- err = runtime.BindStyledParameterWithLocation("simple", false, "header2", runtime.ParamLocationHeader, valueList[0], &Header2)
+ err = runtime.BindStyledParameterWithOptions("simple", "header2", valueList[0], &Header2, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: ""})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "header2", Err: err})
return
@@ -335,12 +416,11 @@ func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// UnionExample operation middleware
func (siw *ServerInterfaceWrapper) UnionExample(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.UnionExample(w, r)
@@ -350,7 +430,7 @@ func (siw *ServerInterfaceWrapper) UnionExample(w http.ResponseWriter, r *http.R
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
type UnescapedCookieParamError struct {
@@ -472,9 +552,21 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl
r.Group(func(r chi.Router) {
r.Post(options.BaseURL+"/multipart", wrapper.MultipartExample)
})
+ r.Group(func(r chi.Router) {
+ r.Post(options.BaseURL+"/multipart-related", wrapper.MultipartRelatedExample)
+ })
r.Group(func(r chi.Router) {
r.Post(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes)
})
+ r.Group(func(r chi.Router) {
+ r.Post(options.BaseURL+"/no-content-headers", wrapper.NoContentHeaders)
+ })
+ r.Group(func(r chi.Router) {
+ r.Post(options.BaseURL+"/required-json-body", wrapper.RequiredJSONBody)
+ })
+ r.Group(func(r chi.Router) {
+ r.Post(options.BaseURL+"/required-text-body", wrapper.RequiredTextBody)
+ })
r.Group(func(r chi.Router) {
r.Get(options.BaseURL+"/reserved-go-keyword-parameters/{type}", wrapper.ReservedGoKeywordParameters)
})
@@ -527,10 +619,15 @@ type JSONExampleResponseObject interface {
type JSONExample200JSONResponse Example
func (response JSONExample200JSONResponse) VisitJSONExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type JSONExample400Response = BadrequestResponse
@@ -561,6 +658,7 @@ type MultipartExample200MultipartResponse func(writer *multipart.Writer) error
func (response MultipartExample200MultipartResponse) VisitMultipartExampleResponse(w http.ResponseWriter) error {
writer := multipart.NewWriter(w)
+
w.Header().Set("Content-Type", writer.FormDataContentType())
w.WriteHeader(200)
@@ -584,6 +682,42 @@ func (response MultipartExampledefaultResponse) VisitMultipartExampleResponse(w
return nil
}
+type MultipartRelatedExampleRequestObject struct {
+ Body *multipart.Reader
+}
+
+type MultipartRelatedExampleResponseObject interface {
+ VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error
+}
+
+type MultipartRelatedExample200MultipartResponse func(writer *multipart.Writer) error
+
+func (response MultipartRelatedExample200MultipartResponse) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ writer := multipart.NewWriter(w)
+
+ w.Header().Set("Content-Type", mime.FormatMediaType("multipart/related", map[string]string{"boundary": writer.Boundary()}))
+ w.WriteHeader(200)
+
+ defer writer.Close()
+ return response(writer)
+}
+
+type MultipartRelatedExample400Response = BadrequestResponse
+
+func (response MultipartRelatedExample400Response) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type MultipartRelatedExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response MultipartRelatedExampledefaultResponse) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
type MultipleRequestAndResponseTypesRequestObject struct {
JSONBody *MultipleRequestAndResponseTypesJSONRequestBody
FormdataBody *MultipleRequestAndResponseTypesFormdataRequestBody
@@ -599,24 +733,29 @@ type MultipleRequestAndResponseTypesResponseObject interface {
type MultipleRequestAndResponseTypes200JSONResponse Example
func (response MultipleRequestAndResponseTypes200JSONResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type MultipleRequestAndResponseTypes200FormdataResponse Example
func (response MultipleRequestAndResponseTypes200FormdataResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
- w.WriteHeader(200)
- if form, err := runtime.MarshalForm(response, nil); err != nil {
- return err
- } else {
- _, err := w.Write([]byte(form.Encode()))
+ form, err := runtime.MarshalForm(response, nil)
+ if err != nil {
return err
}
+ w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
+ w.WriteHeader(200)
+ _, err = w.Write([]byte(form.Encode()))
+ return err
}
type MultipleRequestAndResponseTypes200ImagepngResponse struct {
@@ -625,6 +764,7 @@ type MultipleRequestAndResponseTypes200ImagepngResponse struct {
}
func (response MultipleRequestAndResponseTypes200ImagepngResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "image/png")
if response.ContentLength != 0 {
w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
@@ -642,6 +782,7 @@ type MultipleRequestAndResponseTypes200MultipartResponse func(writer *multipart.
func (response MultipleRequestAndResponseTypes200MultipartResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
writer := multipart.NewWriter(w)
+
w.Header().Set("Content-Type", writer.FormDataContentType())
w.WriteHeader(200)
@@ -652,6 +793,7 @@ func (response MultipleRequestAndResponseTypes200MultipartResponse) VisitMultipl
type MultipleRequestAndResponseTypes200TextResponse string
func (response MultipleRequestAndResponseTypes200TextResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(200)
@@ -666,6 +808,106 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA
return nil
}
+type NoContentHeadersRequestObject struct {
+}
+
+type NoContentHeadersResponseObject interface {
+ VisitNoContentHeadersResponse(w http.ResponseWriter) error
+}
+
+type NoContentHeaders204ResponseHeaders struct {
+ NullableHeader *string
+ OptionalHeader *string
+}
+
+type NoContentHeaders204Response struct {
+ Headers NoContentHeaders204ResponseHeaders
+}
+
+func (response NoContentHeaders204Response) VisitNoContentHeadersResponse(w http.ResponseWriter) error {
+ if response.Headers.NullableHeader != nil {
+ w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader))
+ }
+ if response.Headers.OptionalHeader != nil {
+ w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader))
+ }
+ w.WriteHeader(204)
+ return nil
+}
+
+type RequiredJSONBodyRequestObject struct {
+ Body *RequiredJSONBodyJSONRequestBody
+}
+
+type RequiredJSONBodyResponseObject interface {
+ VisitRequiredJSONBodyResponse(w http.ResponseWriter) error
+}
+
+type RequiredJSONBody200JSONResponse Example
+
+func (response RequiredJSONBody200JSONResponse) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type RequiredJSONBody400Response = BadrequestResponse
+
+func (response RequiredJSONBody400Response) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type RequiredJSONBodydefaultResponse struct {
+ StatusCode int
+}
+
+func (response RequiredJSONBodydefaultResponse) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type RequiredTextBodyRequestObject struct {
+ Body *RequiredTextBodyTextRequestBody
+}
+
+type RequiredTextBodyResponseObject interface {
+ VisitRequiredTextBodyResponse(w http.ResponseWriter) error
+}
+
+type RequiredTextBody200TextResponse string
+
+func (response RequiredTextBody200TextResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "text/plain")
+ w.WriteHeader(200)
+
+ _, err := w.Write([]byte(response))
+ return err
+}
+
+type RequiredTextBody400Response = BadrequestResponse
+
+func (response RequiredTextBody400Response) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type RequiredTextBodydefaultResponse struct {
+ StatusCode int
+}
+
+func (response RequiredTextBodydefaultResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
type ReservedGoKeywordParametersRequestObject struct {
Type string `json:"type"`
}
@@ -677,6 +919,7 @@ type ReservedGoKeywordParametersResponseObject interface {
type ReservedGoKeywordParameters200TextResponse string
func (response ReservedGoKeywordParameters200TextResponse) VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(200)
@@ -695,12 +938,17 @@ type ReusableResponsesResponseObject interface {
type ReusableResponses200JSONResponse struct{ ReusableresponseJSONResponse }
func (response ReusableResponses200JSONResponse) VisitReusableResponsesResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type ReusableResponses400Response = BadrequestResponse
@@ -730,6 +978,7 @@ type TextExampleResponseObject interface {
type TextExample200TextResponse string
func (response TextExample200TextResponse) VisitTextExampleResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(200)
@@ -767,6 +1016,7 @@ type UnknownExample200Videomp4Response struct {
}
func (response UnknownExample200Videomp4Response) VisitUnknownExampleResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "video/mp4")
if response.ContentLength != 0 {
w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
@@ -812,6 +1062,7 @@ type UnspecifiedContentType200VideoResponse struct {
}
func (response UnspecifiedContentType200VideoResponse) VisitUnspecifiedContentTypeResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", response.ContentType)
if response.ContentLength != 0 {
w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
@@ -868,15 +1119,15 @@ type URLEncodedExampleResponseObject interface {
type URLEncodedExample200FormdataResponse Example
func (response URLEncodedExample200FormdataResponse) VisitURLEncodedExampleResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
- w.WriteHeader(200)
- if form, err := runtime.MarshalForm(response, nil); err != nil {
- return err
- } else {
- _, err := w.Write([]byte(form.Encode()))
+ form, err := runtime.MarshalForm(response, nil)
+ if err != nil {
return err
}
+ w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
+ w.WriteHeader(200)
+ _, err = w.Write([]byte(form.Encode()))
+ return err
}
type URLEncodedExample400Response = BadrequestResponse
@@ -905,8 +1156,10 @@ type HeadersExampleResponseObject interface {
}
type HeadersExample200ResponseHeaders struct {
- Header1 string
- Header2 int
+ Header1 string
+ Header2 int
+ NullableHeader *string
+ OptionalHeader *string
}
type HeadersExample200JSONResponse struct {
@@ -915,12 +1168,23 @@ type HeadersExample200JSONResponse struct {
}
func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
+ if response.Headers.NullableHeader != nil {
+ w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader))
+ }
+ if response.Headers.OptionalHeader != nil {
+ w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader))
+ }
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type HeadersExample400Response = BadrequestResponse
@@ -958,28 +1222,36 @@ type UnionExample200ApplicationAlternativePlusJSONResponse struct {
}
func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/alternative+json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type UnionExample200JSONResponse struct {
- Body struct {
- union json.RawMessage
- }
+ Body UnionExample200JSONResponseBody
Headers UnionExample200ResponseHeaders
}
func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body.union); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body.union)
+ _, err := buf.WriteTo(w)
+ return err
}
type UnionExample400Response = BadrequestResponse
@@ -1007,9 +1279,21 @@ type StrictServerInterface interface {
// (POST /multipart)
MultipartExample(ctx context.Context, request MultipartExampleRequestObject) (MultipartExampleResponseObject, error)
+ // (POST /multipart-related)
+ MultipartRelatedExample(ctx context.Context, request MultipartRelatedExampleRequestObject) (MultipartRelatedExampleResponseObject, error)
+
// (POST /multiple)
MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error)
+ // (POST /no-content-headers)
+ NoContentHeaders(ctx context.Context, request NoContentHeadersRequestObject) (NoContentHeadersResponseObject, error)
+
+ // (POST /required-json-body)
+ RequiredJSONBody(ctx context.Context, request RequiredJSONBodyRequestObject) (RequiredJSONBodyResponseObject, error)
+
+ // (POST /required-text-body)
+ RequiredTextBody(ctx context.Context, request RequiredTextBodyRequestObject) (RequiredTextBodyResponseObject, error)
+
// (GET /reserved-go-keyword-parameters/{type})
ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error)
@@ -1035,8 +1319,8 @@ type StrictServerInterface interface {
UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error)
}
-type StrictHandlerFunc = strictnethttp.StrictHttpHandlerFunc
-type StrictMiddlewareFunc = strictnethttp.StrictHttpMiddlewareFunc
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
type StrictHTTPServerOptions struct {
RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
@@ -1070,10 +1354,13 @@ func (sh *strictHandler) JSONExample(w http.ResponseWriter, r *http.Request) {
var body JSONExampleJSONRequestBody
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
- sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
- return
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
return sh.ssi.JSONExample(ctx, request.(JSONExampleRequestObject))
@@ -1126,6 +1413,40 @@ func (sh *strictHandler) MultipartExample(w http.ResponseWriter, r *http.Request
}
}
+// MultipartRelatedExample operation middleware
+func (sh *strictHandler) MultipartRelatedExample(w http.ResponseWriter, r *http.Request) {
+ var request MultipartRelatedExampleRequestObject
+
+ if _, params, err := mime.ParseMediaType(r.Header.Get("Content-Type")); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, err)
+ return
+ } else if boundary := params["boundary"]; boundary == "" {
+ sh.options.RequestErrorHandlerFunc(w, r, http.ErrMissingBoundary)
+ return
+ } else {
+ request.Body = multipart.NewReader(r.Body, boundary)
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.MultipartRelatedExample(ctx, request.(MultipartRelatedExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "MultipartRelatedExample")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(MultipartRelatedExampleResponseObject); ok {
+ if err := validResponse.VisitMultipartRelatedExampleResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
// MultipleRequestAndResponseTypes operation middleware
func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter, r *http.Request) {
var request MultipleRequestAndResponseTypesRequestObject
@@ -1134,10 +1455,13 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter,
var body MultipleRequestAndResponseTypesJSONRequestBody
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
- sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
- return
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.JSONBody = &body
}
- request.JSONBody = &body
}
if strings.HasPrefix(r.Header.Get("Content-Type"), "application/x-www-form-urlencoded") {
if err := r.ParseForm(); err != nil {
@@ -1168,8 +1492,10 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter,
sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't read body: %w", err))
return
}
- body := MultipleRequestAndResponseTypesTextRequestBody(data)
- request.TextBody = &body
+ if len(data) > 0 {
+ body := MultipleRequestAndResponseTypesTextRequestBody(data)
+ request.TextBody = &body
+ }
}
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
@@ -1192,6 +1518,93 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter,
}
}
+// NoContentHeaders operation middleware
+func (sh *strictHandler) NoContentHeaders(w http.ResponseWriter, r *http.Request) {
+ var request NoContentHeadersRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.NoContentHeaders(ctx, request.(NoContentHeadersRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "NoContentHeaders")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(NoContentHeadersResponseObject); ok {
+ if err := validResponse.VisitNoContentHeadersResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// RequiredJSONBody operation middleware
+func (sh *strictHandler) RequiredJSONBody(w http.ResponseWriter, r *http.Request) {
+ var request RequiredJSONBodyRequestObject
+
+ var body RequiredJSONBodyJSONRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ request.Body = &body
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.RequiredJSONBody(ctx, request.(RequiredJSONBodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "RequiredJSONBody")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(RequiredJSONBodyResponseObject); ok {
+ if err := validResponse.VisitRequiredJSONBodyResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// RequiredTextBody operation middleware
+func (sh *strictHandler) RequiredTextBody(w http.ResponseWriter, r *http.Request) {
+ var request RequiredTextBodyRequestObject
+
+ data, err := io.ReadAll(r.Body)
+ if err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't read body: %w", err))
+ return
+ }
+ body := RequiredTextBodyTextRequestBody(data)
+ request.Body = &body
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.RequiredTextBody(ctx, request.(RequiredTextBodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "RequiredTextBody")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(RequiredTextBodyResponseObject); ok {
+ if err := validResponse.VisitRequiredTextBodyResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
// ReservedGoKeywordParameters operation middleware
func (sh *strictHandler) ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request, pType string) {
var request ReservedGoKeywordParametersRequestObject
@@ -1224,10 +1637,13 @@ func (sh *strictHandler) ReusableResponses(w http.ResponseWriter, r *http.Reques
var body ReusableResponsesJSONRequestBody
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
- sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
- return
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
return sh.ssi.ReusableResponses(ctx, request.(ReusableResponsesRequestObject))
@@ -1258,8 +1674,10 @@ func (sh *strictHandler) TextExample(w http.ResponseWriter, r *http.Request) {
sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't read body: %w", err))
return
}
- body := TextExampleTextRequestBody(data)
- request.Body = &body
+ if len(data) > 0 {
+ body := TextExampleTextRequestBody(data)
+ request.Body = &body
+ }
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
return sh.ssi.TextExample(ctx, request.(TextExampleRequestObject))
@@ -1378,10 +1796,13 @@ func (sh *strictHandler) HeadersExample(w http.ResponseWriter, r *http.Request,
var body HeadersExampleJSONRequestBody
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
- sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
- return
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
return sh.ssi.HeadersExample(ctx, request.(HeadersExampleRequestObject))
@@ -1409,10 +1830,13 @@ func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) {
var body UnionExampleJSONRequestBody
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
- sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
- return
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
return sh.ssi.UnionExample(ctx, request.(UnionExampleRequestObject))
@@ -1434,43 +1858,49 @@ func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) {
}
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/+xYS2/jNhD+KwTb01aynGxOunWDxbbdtimc5FTkQIsjm7sSyQ5HVgzD/72gKL9ixbW3",
- "fhRBb3oMvxl+8+BwZjwzpTUaNDmezjiCs0Y7aF6GQiL8VYEj/ybBZagsKaN5yj8IOWj/zSOOUDkxLGCx",
- "3MtnRhPoZqmwtlCZ8EuTL86vn3GXjaEU/ul7hJyn/LtkZUoS/roEnkVpC+Dz+Tx6YcHdZx7xMQgJ2Fgb",
- "Hq82sWlqgafcESo94h4kiF13iilNMAL02rxoa4QXWNiRzrhFYwFJBY4moqigW1P7xQy/QEZhB0rnZpvL",
- "W6NJKO2YVHkOCJpYSx7zGI65ylqDBJINp8xryIg5wAkgjzgp8obx+/XvrDXY8YhPAF1QdNXr9/reX8aC",
- "FlbxlL9vPkXcCho3G1o6yJouv/9yf/c7U46JikwpSGWiKKasFOjGogDJlCbjTawycj3eaMLG8T/LdvXH",
- "lkofNU0AfTByeoqAaeJyLZyv+/0zxeU84jdBWRfG0qhkLcEamFxURQfnj/qrNrVmgGiw3VlSVgUpK5DW",
- "fbXJ9m8LkX0oX+IlucEyloLEiVg/lqaLEt/Wgs4cuR+b2rGxqRkZJkEUrFY0ZouFL5JbaSaYU3pUAFsY",
- "FXV6soC25P6o5aDdy4PHOHkuRRsoz3Fd13HjvAoL0JmRIL8NVpViBInVo83lHlsQT/lwSj5st4vrkYIo",
- "4gTPlNhCKL375DhTOfmf6aMldkhXhOZElPHIxF9hWhuUsRUoSiBAl8y89rkHHkFHKv+xlGSZ0GwITIsS",
- "JBM5AbJPhrWQbitlB63eT+ZzEFlBNcft8iX9c8Y9Jc0RzCPuFfA0sBLyWqF3OmEF0Q7anv4xPv+VAxZs",
- "hkYv3lDVXQYXJWpJHULufEns8lwHf0HTYE3iMg3D7ojban3PcQZ5T75+7j/A815H/hFL37lz+1DCqvDx",
- "dc7aVfvQ9o2VdA8WJ0qCSUp7cyDyxUh1FjKVK5Bxu4s42PZaSbg1OkOgzRbIXye0IbYE87ccGgMLDETM",
- "GVYDKytHzArnmKKmihQq3JQkbBWPx5Vlt0HTw6qc7vLquxP59N2lPHrTvzp8yfsTx81GK/NKPg5+/Rhk",
- "Dr0vHq1nOrDjO57eC6Wzv6TEawOV7hT+KQiszvQM1MR3RFoyBKpQg2QTJRZDgK3cbAFWbu3qhYIZq25o",
- "Mdw5pCGKdmJd82jXAOjpDY8nTjk2O1ecVlrtGlM9+t+s7aFfng3K6P/oEEoUBKgFqQn8cJwb5DaK0XCX",
- "N5n2wsvRnhqe3l5UzSMe5qahBFVY+DpBZNMkCfPWnqvFaATYUyYRVnkW/g4AAP//Pk3lbjwXAAA=",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "7Fnbcts2E36VHfz/RZuSpuL4SndNJpO2aZOObF91fAERKwkJCSDAUrJGo5k+RJ+wT9IBAepI21KqgyfT",
+ "O4ncE/fbXX5LzFiuS6MVKnKsO2MWndHKYf2nz4XFLxU68v8EutxKQ1Ir1mWvuejFe/OEWawc7xfYqHv5",
+ "XCtCVatyYwqZc6+afXJef8ZcPsKS+1//tzhgXfa/bBlKFu66DO95aQpk8/k82Yjg43uWsBFygbaONvx8",
+ "GZ7iSyUtCtYlW2Gy4oumBlmXObJSDZk3GtQud1KTinCI1kfjVWOQXqCJsztjxmqDlmTI4ZgXFbZ7jld0",
+ "/xPmFJ5QqoHezvUbrYhL5UDIwQAtKoKYXPA2HLjKGG0JBfSn4D3kBA7tGC1LGEnygbHr1esQA3YsYWO0",
+ "Ljh6edG56Hg8tUHFjWRd9qq+lDDDaVQ/0AJAo9vq4pfrjx9AOuAV6ZKTzHlRTKHk1o14gQKkIu1DrHJy",
+ "F6z2ZOvC+FlE7bcxlQmLxfdai+kxCqqu25Vyv+x0TlS384RdBWdtNhZBZSsNWJsZ8Kpoyfmt+qz0RAFa",
+ "q218sqysCpKGW1rFaj3bvzUiu6R8YS8baFumghM/UtYP5enciU8tFpz8OHkSgF6Q3A+HFfNHReHf+Dkr",
+ "BnEet86p65GeOBjpCZAGgbyAiaQRNIobA1Yq4OCkGhYITVBJK5gFxtfij0r04rPceBtHn2fJmpX7dDKZ",
+ "pHUDVbZAlWvxdRAmTJZ8iJlRw3V1b5sT67L+lHzJbr/gDtTICSO8p8wUXG4kZtPliUb6f5k+WGOHdlU6",
+ "jRClK4SuvXE/LGThu8vO1ffQGA4NrGs5XgBXAlRVFJ6WLmWiefj7z78A79Hm0qEDGnGCSjmkhQC3CLqU",
+ "5EnVwOoSaLQ0s9X7H/SbENNPMfytOrxqexKIWutEtok65mIdiOZmw1G3a6HJQKv6dscEBBrqm/qeSPtx",
+ "QrUjEAcceClP9RrdBJyGUjo/J8NNN9JVIYAXEz51YUJvc75eVPfcrx6NRyd+yQbT/7aJ4AJa39vngfYG",
+ "7+lJaPcYPfvCd+qptj9E9VYm0qFOP+N0oq1IDbe8RELrspmPc+5tDbHF5O8LSci5gj6C4iUK4ANCC+80",
+ "RJOuBZ/g951+H0SWpuqVb/Gn+8eM+eTVayBLmHfAuiF/yR7r9t1xoWqyGT5GpGuuHir4KNKkzuLAeUrY",
+ "hnFL/oKn3orEeZbWx2tz6/PMKYraI/nw6uNHwi7rzgGp33OfAlW4+HDOotYuaftKJrlDFsdSoM5Kc7Wn",
+ "5bMl1RnM5UCiWHDMENtDI+GNVrlFWl8B/ctQaYKFMehPa0oYMlC/HycIZeUIDHcOJNVTpJDha53Y5oy3",
+ "y8giDbxZjtPHUH1xJExfnAvRq87L/VVeHblu1la5B/qx9+vbILPvN8uD7Yx7bryH83umdvY73tM7YtzC",
+ "lu/0HOXYMyIlwCJVVqGAseTNh+it3owGlrC2caG4Xy3YUHMAsQ8hSh61dckePYS4+4Y/kZ/vaCc58QJ+",
+ "qq6plHzs4ObW34bI6DffVFKrZ3oswwtCqzjJMf5wmO9521a0wo+Duu830Et29HD3/I4vj11184SFk8Yw",
+ "MCtb+KlGZLpZFk4oL9yED4doL6TOuJE+S/8EAAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -1478,7 +1908,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -1496,12 +1926,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -1527,3 +1957,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/strict-server/chi/server.go b/internal/test/strict-server/chi/server.go
index 669d4da4f4..1f4c633fae 100644
--- a/internal/test/strict-server/chi/server.go
+++ b/internal/test/strict-server/chi/server.go
@@ -1,5 +1,5 @@
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
package api
@@ -41,6 +41,30 @@ func (s StrictServer) MultipartExample(ctx context.Context, request MultipartExa
}), nil
}
+func (s StrictServer) MultipartRelatedExample(ctx context.Context, request MultipartRelatedExampleRequestObject) (MultipartRelatedExampleResponseObject, error) {
+ return MultipartRelatedExample200MultipartResponse(func(writer *multipart.Writer) error {
+ for {
+ part, err := request.Body.NextPart()
+ if err == io.EOF {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ w, err := writer.CreatePart(part.Header)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(w, part)
+ if err != nil {
+ return err
+ }
+ if err = part.Close(); err != nil {
+ return err
+ }
+ }
+ }), nil
+}
+
func (s StrictServer) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error) {
switch {
case request.Body != nil:
@@ -98,10 +122,22 @@ func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExample
return HeadersExample200JSONResponse{Body: *request.Body, Headers: HeadersExample200ResponseHeaders{Header1: request.Params.Header1, Header2: *request.Params.Header2}}, nil
}
+func (s StrictServer) NoContentHeaders(ctx context.Context, request NoContentHeadersRequestObject) (NoContentHeadersResponseObject, error) {
+ return NoContentHeaders204Response{}, nil
+}
+
func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) {
return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil
}
+func (s StrictServer) RequiredJSONBody(ctx context.Context, request RequiredJSONBodyRequestObject) (RequiredJSONBodyResponseObject, error) {
+ return RequiredJSONBody200JSONResponse(*request.Body), nil
+}
+
+func (s StrictServer) RequiredTextBody(ctx context.Context, request RequiredTextBodyRequestObject) (RequiredTextBodyResponseObject, error) {
+ return RequiredTextBody200TextResponse(*request.Body), nil
+}
+
func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) {
return ReservedGoKeywordParameters200TextResponse(""), nil
}
diff --git a/internal/test/strict-server/chi/types.cfg.yaml b/internal/test/strict-server/chi/types.cfg.yaml
index 4ea1d8aa5b..2ed9740ea7 100644
--- a/internal/test/strict-server/chi/types.cfg.yaml
+++ b/internal/test/strict-server/chi/types.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
models: true
diff --git a/internal/test/strict-server/chi/types.gen.go b/internal/test/strict-server/chi/types.gen.go
index 6a0de0c970..08ae8548e1 100644
--- a/internal/test/strict-server/chi/types.gen.go
+++ b/internal/test/strict-server/chi/types.gen.go
@@ -1,8 +1,14 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
+import (
+ "encoding/json"
+
+ "github.com/oapi-codegen/runtime"
+)
+
// Example defines model for example.
type Example struct {
Value *string `json:"value,omitempty"`
@@ -14,6 +20,9 @@ type Reusableresponse = Example
// MultipleRequestAndResponseTypesTextBody defines parameters for MultipleRequestAndResponseTypes.
type MultipleRequestAndResponseTypesTextBody = string
+// RequiredTextBodyTextBody defines parameters for RequiredTextBody.
+type RequiredTextBodyTextBody = string
+
// TextExampleTextBody defines parameters for TextExample.
type TextExampleTextBody = string
@@ -23,12 +32,23 @@ type HeadersExampleParams struct {
Header2 *int `json:"header2,omitempty"`
}
+// UnionExample200JSONResponseBody0 defines parameters for UnionExample.
+type UnionExample200JSONResponseBody0 = string
+
+// UnionExample200JSONResponseBody defines parameters for UnionExample.
+type UnionExample200JSONResponseBody struct {
+ union json.RawMessage
+}
+
// JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType.
type JSONExampleJSONRequestBody = Example
// MultipartExampleMultipartRequestBody defines body for MultipartExample for multipart/form-data ContentType.
type MultipartExampleMultipartRequestBody = Example
+// MultipartRelatedExampleMultipartRequestBody defines body for MultipartRelatedExample for multipart/related ContentType.
+type MultipartRelatedExampleMultipartRequestBody = Example
+
// MultipleRequestAndResponseTypesJSONRequestBody defines body for MultipleRequestAndResponseTypes for application/json ContentType.
type MultipleRequestAndResponseTypesJSONRequestBody = Example
@@ -41,6 +61,12 @@ type MultipleRequestAndResponseTypesMultipartRequestBody = Example
// MultipleRequestAndResponseTypesTextRequestBody defines body for MultipleRequestAndResponseTypes for text/plain ContentType.
type MultipleRequestAndResponseTypesTextRequestBody = MultipleRequestAndResponseTypesTextBody
+// RequiredJSONBodyJSONRequestBody defines body for RequiredJSONBody for application/json ContentType.
+type RequiredJSONBodyJSONRequestBody = Example
+
+// RequiredTextBodyTextRequestBody defines body for RequiredTextBody for text/plain ContentType.
+type RequiredTextBodyTextRequestBody = RequiredTextBodyTextBody
+
// ReusableResponsesJSONRequestBody defines body for ReusableResponses for application/json ContentType.
type ReusableResponsesJSONRequestBody = Example
@@ -55,3 +81,65 @@ type HeadersExampleJSONRequestBody = Example
// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType.
type UnionExampleJSONRequestBody = Example
+
+// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0
+func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) {
+ var body UnionExample200JSONResponseBody0
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example
+func (t UnionExample200JSONResponseBody) AsExample() (Example, error) {
+ var body Example
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example
+func (t *UnionExample200JSONResponseBody) FromExample(v Example) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example
+func (t *UnionExample200JSONResponseBody) MergeExample(v Example) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
diff --git a/internal/test/strict-server/client/client.cfg.yaml b/internal/test/strict-server/client/client.cfg.yaml
index 637450eaa2..8437bde142 100644
--- a/internal/test/strict-server/client/client.cfg.yaml
+++ b/internal/test/strict-server/client/client.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
models: true
diff --git a/internal/test/strict-server/client/client.gen.go b/internal/test/strict-server/client/client.gen.go
index 63010154d2..a076eddef0 100644
--- a/internal/test/strict-server/client/client.gen.go
+++ b/internal/test/strict-server/client/client.gen.go
@@ -1,6 +1,6 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
@@ -27,6 +27,9 @@ type Reusableresponse = Example
// MultipleRequestAndResponseTypesTextBody defines parameters for MultipleRequestAndResponseTypes.
type MultipleRequestAndResponseTypesTextBody = string
+// RequiredTextBodyTextBody defines parameters for RequiredTextBody.
+type RequiredTextBodyTextBody = string
+
// TextExampleTextBody defines parameters for TextExample.
type TextExampleTextBody = string
@@ -36,12 +39,23 @@ type HeadersExampleParams struct {
Header2 *int `json:"header2,omitempty"`
}
+// UnionExample200JSONResponseBody0 defines parameters for UnionExample.
+type UnionExample200JSONResponseBody0 = string
+
+// UnionExample200JSONResponseBody defines parameters for UnionExample.
+type UnionExample200JSONResponseBody struct {
+ union json.RawMessage
+}
+
// JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType.
type JSONExampleJSONRequestBody = Example
// MultipartExampleMultipartRequestBody defines body for MultipartExample for multipart/form-data ContentType.
type MultipartExampleMultipartRequestBody = Example
+// MultipartRelatedExampleMultipartRequestBody defines body for MultipartRelatedExample for multipart/related ContentType.
+type MultipartRelatedExampleMultipartRequestBody = Example
+
// MultipleRequestAndResponseTypesJSONRequestBody defines body for MultipleRequestAndResponseTypes for application/json ContentType.
type MultipleRequestAndResponseTypesJSONRequestBody = Example
@@ -54,6 +68,12 @@ type MultipleRequestAndResponseTypesMultipartRequestBody = Example
// MultipleRequestAndResponseTypesTextRequestBody defines body for MultipleRequestAndResponseTypes for text/plain ContentType.
type MultipleRequestAndResponseTypesTextRequestBody = MultipleRequestAndResponseTypesTextBody
+// RequiredJSONBodyJSONRequestBody defines body for RequiredJSONBody for application/json ContentType.
+type RequiredJSONBodyJSONRequestBody = Example
+
+// RequiredTextBodyTextRequestBody defines body for RequiredTextBody for text/plain ContentType.
+type RequiredTextBodyTextRequestBody = RequiredTextBodyTextBody
+
// ReusableResponsesJSONRequestBody defines body for ReusableResponses for application/json ContentType.
type ReusableResponsesJSONRequestBody = Example
@@ -69,6 +89,68 @@ type HeadersExampleJSONRequestBody = Example
// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType.
type UnionExampleJSONRequestBody = Example
+// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0
+func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) {
+ var body UnionExample200JSONResponseBody0
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example
+func (t UnionExample200JSONResponseBody) AsExample() (Example, error) {
+ var body Example
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example
+func (t *UnionExample200JSONResponseBody) FromExample(v Example) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example
+func (t *UnionExample200JSONResponseBody) MergeExample(v Example) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
+
// RequestEditorFn is the function signature for the RequestEditor callback function
type RequestEditorFn func(ctx context.Context, req *http.Request) error
@@ -150,6 +232,9 @@ type ClientInterface interface {
// MultipartExampleWithBody request with any body
MultipartExampleWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // MultipartRelatedExampleWithBody request with any body
+ MultipartRelatedExampleWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
// MultipleRequestAndResponseTypesWithBody request with any body
MultipleRequestAndResponseTypesWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
@@ -159,6 +244,19 @@ type ClientInterface interface {
MultipleRequestAndResponseTypesWithTextBody(ctx context.Context, body MultipleRequestAndResponseTypesTextRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+ // NoContentHeaders request
+ NoContentHeaders(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // RequiredJSONBodyWithBody request with any body
+ RequiredJSONBodyWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ RequiredJSONBody(ctx context.Context, body RequiredJSONBodyJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ // RequiredTextBodyWithBody request with any body
+ RequiredTextBodyWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+ RequiredTextBodyWithTextBody(ctx context.Context, body RequiredTextBodyTextRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
// ReservedGoKeywordParameters request
ReservedGoKeywordParameters(ctx context.Context, pType string, reqEditors ...RequestEditorFn) (*http.Response, error)
@@ -230,6 +328,18 @@ func (c *Client) MultipartExampleWithBody(ctx context.Context, contentType strin
return c.Client.Do(req)
}
+func (c *Client) MultipartRelatedExampleWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewMultipartRelatedExampleRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
func (c *Client) MultipleRequestAndResponseTypesWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewMultipleRequestAndResponseTypesRequestWithBody(c.Server, contentType, body)
if err != nil {
@@ -278,6 +388,66 @@ func (c *Client) MultipleRequestAndResponseTypesWithTextBody(ctx context.Context
return c.Client.Do(req)
}
+func (c *Client) NoContentHeaders(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewNoContentHeadersRequest(c.Server)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) RequiredJSONBodyWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewRequiredJSONBodyRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) RequiredJSONBody(ctx context.Context, body RequiredJSONBodyJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewRequiredJSONBodyRequest(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) RequiredTextBodyWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewRequiredTextBodyRequestWithBody(c.Server, contentType, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
+func (c *Client) RequiredTextBodyWithTextBody(ctx context.Context, body RequiredTextBodyTextRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+ req, err := NewRequiredTextBodyRequestWithTextBody(c.Server, body)
+ if err != nil {
+ return nil, err
+ }
+ req = req.WithContext(ctx)
+ if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+ return nil, err
+ }
+ return c.Client.Do(req)
+}
+
func (c *Client) ReservedGoKeywordParameters(ctx context.Context, pType string, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewReservedGoKeywordParametersRequest(c.Server, pType)
if err != nil {
@@ -464,7 +634,7 @@ func NewJSONExampleRequestWithBody(server string, contentType string, body io.Re
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -493,7 +663,36 @@ func NewMultipartExampleRequestWithBody(server string, contentType string, body
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewMultipartRelatedExampleRequestWithBody generates requests for MultipartRelatedExample with any type of body
+func NewMultipartRelatedExampleRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/multipart-related")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -528,7 +727,11 @@ func NewMultipleRequestAndResponseTypesRequestWithFormdataBody(server string, bo
// NewMultipleRequestAndResponseTypesRequestWithTextBody calls the generic MultipleRequestAndResponseTypes builder with text/plain body
func NewMultipleRequestAndResponseTypesRequestWithTextBody(server string, body MultipleRequestAndResponseTypesTextRequestBody) (*http.Request, error) {
var bodyReader io.Reader
- bodyReader = strings.NewReader(string(body))
+ if stringer, ok := interface{}(body).(fmt.Stringer); ok {
+ bodyReader = strings.NewReader(stringer.String())
+ } else {
+ bodyReader = strings.NewReader(fmt.Sprint(body))
+ }
return NewMultipleRequestAndResponseTypesRequestWithBody(server, "text/plain", bodyReader)
}
@@ -551,7 +754,114 @@ func NewMultipleRequestAndResponseTypesRequestWithBody(server string, contentTyp
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewNoContentHeadersRequest generates requests for NoContentHeaders
+func NewNoContentHeadersRequest(server string) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/no-content-headers")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), nil)
+ if err != nil {
+ return nil, err
+ }
+
+ return req, nil
+}
+
+// NewRequiredJSONBodyRequest calls the generic RequiredJSONBody builder with application/json body
+func NewRequiredJSONBodyRequest(server string, body RequiredJSONBodyJSONRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ buf, err := json.Marshal(body)
+ if err != nil {
+ return nil, err
+ }
+ bodyReader = bytes.NewReader(buf)
+ return NewRequiredJSONBodyRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewRequiredJSONBodyRequestWithBody generates requests for RequiredJSONBody with any type of body
+func NewRequiredJSONBodyRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/required-json-body")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
+ if err != nil {
+ return nil, err
+ }
+
+ req.Header.Add("Content-Type", contentType)
+
+ return req, nil
+}
+
+// NewRequiredTextBodyRequestWithTextBody calls the generic RequiredTextBody builder with text/plain body
+func NewRequiredTextBodyRequestWithTextBody(server string, body RequiredTextBodyTextRequestBody) (*http.Request, error) {
+ var bodyReader io.Reader
+ if stringer, ok := interface{}(body).(fmt.Stringer); ok {
+ bodyReader = strings.NewReader(stringer.String())
+ } else {
+ bodyReader = strings.NewReader(fmt.Sprint(body))
+ }
+ return NewRequiredTextBodyRequestWithBody(server, "text/plain", bodyReader)
+}
+
+// NewRequiredTextBodyRequestWithBody generates requests for RequiredTextBody with any type of body
+func NewRequiredTextBodyRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+ var err error
+
+ serverURL, err := url.Parse(server)
+ if err != nil {
+ return nil, err
+ }
+
+ operationPath := fmt.Sprintf("/required-text-body")
+ if operationPath[0] == '/' {
+ operationPath = "." + operationPath
+ }
+
+ queryURL, err := serverURL.Parse(operationPath)
+ if err != nil {
+ return nil, err
+ }
+
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -567,7 +877,7 @@ func NewReservedGoKeywordParametersRequest(server string, pType string) (*http.R
var pathParam0 string
- pathParam0, err = runtime.StyleParamWithLocation("simple", false, "type", runtime.ParamLocationPath, pType)
+ pathParam0, err = runtime.StyleParamWithOptions("simple", false, "type", pType, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "string", Format: ""})
if err != nil {
return nil, err
}
@@ -587,7 +897,7 @@ func NewReservedGoKeywordParametersRequest(server string, pType string) (*http.R
return nil, err
}
- req, err := http.NewRequest("GET", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodGet, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -625,7 +935,7 @@ func NewReusableResponsesRequestWithBody(server string, contentType string, body
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -638,7 +948,11 @@ func NewReusableResponsesRequestWithBody(server string, contentType string, body
// NewTextExampleRequestWithTextBody calls the generic TextExample builder with text/plain body
func NewTextExampleRequestWithTextBody(server string, body TextExampleTextRequestBody) (*http.Request, error) {
var bodyReader io.Reader
- bodyReader = strings.NewReader(string(body))
+ if stringer, ok := interface{}(body).(fmt.Stringer); ok {
+ bodyReader = strings.NewReader(stringer.String())
+ } else {
+ bodyReader = strings.NewReader(fmt.Sprint(body))
+ }
return NewTextExampleRequestWithBody(server, "text/plain", bodyReader)
}
@@ -661,7 +975,7 @@ func NewTextExampleRequestWithBody(server string, contentType string, body io.Re
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -690,7 +1004,7 @@ func NewUnknownExampleRequestWithBody(server string, contentType string, body io
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -719,7 +1033,7 @@ func NewUnspecifiedContentTypeRequestWithBody(server string, contentType string,
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -759,7 +1073,7 @@ func NewURLEncodedExampleRequestWithBody(server string, contentType string, body
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -799,7 +1113,7 @@ func NewHeadersExampleRequestWithBody(server string, params *HeadersExampleParam
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -810,7 +1124,7 @@ func NewHeadersExampleRequestWithBody(server string, params *HeadersExampleParam
var headerParam0 string
- headerParam0, err = runtime.StyleParamWithLocation("simple", false, "header1", runtime.ParamLocationHeader, params.Header1)
+ headerParam0, err = runtime.StyleParamWithOptions("simple", false, "header1", params.Header1, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "string", Format: ""})
if err != nil {
return nil, err
}
@@ -820,7 +1134,7 @@ func NewHeadersExampleRequestWithBody(server string, params *HeadersExampleParam
if params.Header2 != nil {
var headerParam1 string
- headerParam1, err = runtime.StyleParamWithLocation("simple", false, "header2", runtime.ParamLocationHeader, *params.Header2)
+ headerParam1, err = runtime.StyleParamWithOptions("simple", false, "header2", *params.Header2, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "integer", Format: ""})
if err != nil {
return nil, err
}
@@ -863,7 +1177,7 @@ func NewUnionExampleRequestWithBody(server string, contentType string, body io.R
return nil, err
}
- req, err := http.NewRequest("POST", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPost, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -924,6 +1238,9 @@ type ClientWithResponsesInterface interface {
// MultipartExampleWithBodyWithResponse request with any body
MultipartExampleWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*MultipartExampleResponse, error)
+ // MultipartRelatedExampleWithBodyWithResponse request with any body
+ MultipartRelatedExampleWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*MultipartRelatedExampleResponse, error)
+
// MultipleRequestAndResponseTypesWithBodyWithResponse request with any body
MultipleRequestAndResponseTypesWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*MultipleRequestAndResponseTypesResponse, error)
@@ -933,6 +1250,19 @@ type ClientWithResponsesInterface interface {
MultipleRequestAndResponseTypesWithTextBodyWithResponse(ctx context.Context, body MultipleRequestAndResponseTypesTextRequestBody, reqEditors ...RequestEditorFn) (*MultipleRequestAndResponseTypesResponse, error)
+ // NoContentHeadersWithResponse request
+ NoContentHeadersWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*NoContentHeadersResponse, error)
+
+ // RequiredJSONBodyWithBodyWithResponse request with any body
+ RequiredJSONBodyWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RequiredJSONBodyResponse, error)
+
+ RequiredJSONBodyWithResponse(ctx context.Context, body RequiredJSONBodyJSONRequestBody, reqEditors ...RequestEditorFn) (*RequiredJSONBodyResponse, error)
+
+ // RequiredTextBodyWithBodyWithResponse request with any body
+ RequiredTextBodyWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RequiredTextBodyResponse, error)
+
+ RequiredTextBodyWithTextBodyWithResponse(ctx context.Context, body RequiredTextBodyTextRequestBody, reqEditors ...RequestEditorFn) (*RequiredTextBodyResponse, error)
+
// ReservedGoKeywordParametersWithResponse request
ReservedGoKeywordParametersWithResponse(ctx context.Context, pType string, reqEditors ...RequestEditorFn) (*ReservedGoKeywordParametersResponse, error)
@@ -974,6 +1304,16 @@ type JSONExampleResponse struct {
JSON200 *Example
}
+// GetJSON200 returns JSON200
+func (r JSONExampleResponse) GetJSON200() *Example {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r JSONExampleResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r JSONExampleResponse) Status() string {
if r.HTTPResponse != nil {
@@ -990,11 +1330,24 @@ func (r JSONExampleResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r JSONExampleResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type MultipartExampleResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r MultipartExampleResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r MultipartExampleResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1011,12 +1364,64 @@ func (r MultipartExampleResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r MultipartExampleResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type MultipartRelatedExampleResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r MultipartRelatedExampleResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r MultipartRelatedExampleResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r MultipartRelatedExampleResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r MultipartRelatedExampleResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type MultipleRequestAndResponseTypesResponse struct {
Body []byte
HTTPResponse *http.Response
JSON200 *Example
}
+// GetJSON200 returns JSON200
+func (r MultipleRequestAndResponseTypesResponse) GetJSON200() *Example {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r MultipleRequestAndResponseTypesResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r MultipleRequestAndResponseTypesResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1033,11 +1438,132 @@ func (r MultipleRequestAndResponseTypesResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r MultipleRequestAndResponseTypesResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type NoContentHeadersResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r NoContentHeadersResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r NoContentHeadersResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r NoContentHeadersResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r NoContentHeadersResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type RequiredJSONBodyResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+ JSON200 *Example
+}
+
+// GetJSON200 returns JSON200
+func (r RequiredJSONBodyResponse) GetJSON200() *Example {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r RequiredJSONBodyResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r RequiredJSONBodyResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r RequiredJSONBodyResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r RequiredJSONBodyResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
+type RequiredTextBodyResponse struct {
+ Body []byte
+ HTTPResponse *http.Response
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r RequiredTextBodyResponse) GetBody() []byte {
+ return r.Body
+}
+
+// Status returns HTTPResponse.Status
+func (r RequiredTextBodyResponse) Status() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Status
+ }
+ return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r RequiredTextBodyResponse) StatusCode() int {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.StatusCode
+ }
+ return 0
+}
+
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r RequiredTextBodyResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type ReservedGoKeywordParametersResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r ReservedGoKeywordParametersResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r ReservedGoKeywordParametersResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1054,12 +1580,30 @@ func (r ReservedGoKeywordParametersResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r ReservedGoKeywordParametersResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type ReusableResponsesResponse struct {
Body []byte
HTTPResponse *http.Response
JSON200 *Reusableresponse
}
+// GetJSON200 returns JSON200
+func (r ReusableResponsesResponse) GetJSON200() *Reusableresponse {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r ReusableResponsesResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r ReusableResponsesResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1076,11 +1620,24 @@ func (r ReusableResponsesResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r ReusableResponsesResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type TextExampleResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r TextExampleResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r TextExampleResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1097,11 +1654,24 @@ func (r TextExampleResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r TextExampleResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type UnknownExampleResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r UnknownExampleResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r UnknownExampleResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1118,11 +1688,24 @@ func (r UnknownExampleResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r UnknownExampleResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type UnspecifiedContentTypeResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r UnspecifiedContentTypeResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r UnspecifiedContentTypeResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1139,11 +1722,24 @@ func (r UnspecifiedContentTypeResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r UnspecifiedContentTypeResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type URLEncodedExampleResponse struct {
Body []byte
HTTPResponse *http.Response
}
+// GetBody returns the raw response body bytes (Body)
+func (r URLEncodedExampleResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r URLEncodedExampleResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1160,12 +1756,30 @@ func (r URLEncodedExampleResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r URLEncodedExampleResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type HeadersExampleResponse struct {
Body []byte
HTTPResponse *http.Response
JSON200 *Example
}
+// GetJSON200 returns JSON200
+func (r HeadersExampleResponse) GetJSON200() *Example {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r HeadersExampleResponse) GetBody() []byte {
+ return r.Body
+}
+
// Status returns HTTPResponse.Status
func (r HeadersExampleResponse) Status() string {
if r.HTTPResponse != nil {
@@ -1182,13 +1796,34 @@ func (r HeadersExampleResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r HeadersExampleResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
type UnionExampleResponse struct {
Body []byte
HTTPResponse *http.Response
ApplicationalternativeJSON200 *Example
- JSON200 *struct {
- union json.RawMessage
- }
+ JSON200 *UnionExample200JSONResponseBody
+}
+
+// GetApplicationalternativeJSON200 returns ApplicationalternativeJSON200
+func (r UnionExampleResponse) GetApplicationalternativeJSON200() *Example {
+ return r.ApplicationalternativeJSON200
+}
+
+// GetJSON200 returns JSON200
+func (r UnionExampleResponse) GetJSON200() *UnionExample200JSONResponseBody {
+ return r.JSON200
+}
+
+// GetBody returns the raw response body bytes (Body)
+func (r UnionExampleResponse) GetBody() []byte {
+ return r.Body
}
// Status returns HTTPResponse.Status
@@ -1207,6 +1842,14 @@ func (r UnionExampleResponse) StatusCode() int {
return 0
}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r UnionExampleResponse) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+
// JSONExampleWithBodyWithResponse request with arbitrary body returning *JSONExampleResponse
func (c *ClientWithResponses) JSONExampleWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*JSONExampleResponse, error) {
rsp, err := c.JSONExampleWithBody(ctx, contentType, body, reqEditors...)
@@ -1233,6 +1876,15 @@ func (c *ClientWithResponses) MultipartExampleWithBodyWithResponse(ctx context.C
return ParseMultipartExampleResponse(rsp)
}
+// MultipartRelatedExampleWithBodyWithResponse request with arbitrary body returning *MultipartRelatedExampleResponse
+func (c *ClientWithResponses) MultipartRelatedExampleWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*MultipartRelatedExampleResponse, error) {
+ rsp, err := c.MultipartRelatedExampleWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseMultipartRelatedExampleResponse(rsp)
+}
+
// MultipleRequestAndResponseTypesWithBodyWithResponse request with arbitrary body returning *MultipleRequestAndResponseTypesResponse
func (c *ClientWithResponses) MultipleRequestAndResponseTypesWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*MultipleRequestAndResponseTypesResponse, error) {
rsp, err := c.MultipleRequestAndResponseTypesWithBody(ctx, contentType, body, reqEditors...)
@@ -1266,6 +1918,49 @@ func (c *ClientWithResponses) MultipleRequestAndResponseTypesWithTextBodyWithRes
return ParseMultipleRequestAndResponseTypesResponse(rsp)
}
+// NoContentHeadersWithResponse request returning *NoContentHeadersResponse
+func (c *ClientWithResponses) NoContentHeadersWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*NoContentHeadersResponse, error) {
+ rsp, err := c.NoContentHeaders(ctx, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseNoContentHeadersResponse(rsp)
+}
+
+// RequiredJSONBodyWithBodyWithResponse request with arbitrary body returning *RequiredJSONBodyResponse
+func (c *ClientWithResponses) RequiredJSONBodyWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RequiredJSONBodyResponse, error) {
+ rsp, err := c.RequiredJSONBodyWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseRequiredJSONBodyResponse(rsp)
+}
+
+func (c *ClientWithResponses) RequiredJSONBodyWithResponse(ctx context.Context, body RequiredJSONBodyJSONRequestBody, reqEditors ...RequestEditorFn) (*RequiredJSONBodyResponse, error) {
+ rsp, err := c.RequiredJSONBody(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseRequiredJSONBodyResponse(rsp)
+}
+
+// RequiredTextBodyWithBodyWithResponse request with arbitrary body returning *RequiredTextBodyResponse
+func (c *ClientWithResponses) RequiredTextBodyWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*RequiredTextBodyResponse, error) {
+ rsp, err := c.RequiredTextBodyWithBody(ctx, contentType, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseRequiredTextBodyResponse(rsp)
+}
+
+func (c *ClientWithResponses) RequiredTextBodyWithTextBodyWithResponse(ctx context.Context, body RequiredTextBodyTextRequestBody, reqEditors ...RequestEditorFn) (*RequiredTextBodyResponse, error) {
+ rsp, err := c.RequiredTextBodyWithTextBody(ctx, body, reqEditors...)
+ if err != nil {
+ return nil, err
+ }
+ return ParseRequiredTextBodyResponse(rsp)
+}
+
// ReservedGoKeywordParametersWithResponse request returning *ReservedGoKeywordParametersResponse
func (c *ClientWithResponses) ReservedGoKeywordParametersWithResponse(ctx context.Context, pType string, reqEditors ...RequestEditorFn) (*ReservedGoKeywordParametersResponse, error) {
rsp, err := c.ReservedGoKeywordParameters(ctx, pType, reqEditors...)
@@ -1420,6 +2115,22 @@ func ParseMultipartExampleResponse(rsp *http.Response) (*MultipartExampleRespons
return response, nil
}
+// ParseMultipartRelatedExampleResponse parses an HTTP response from a MultipartRelatedExampleWithResponse call
+func ParseMultipartRelatedExampleResponse(rsp *http.Response) (*MultipartRelatedExampleResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &MultipartRelatedExampleResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
// ParseMultipleRequestAndResponseTypesResponse parses an HTTP response from a MultipleRequestAndResponseTypesWithResponse call
func ParseMultipleRequestAndResponseTypesResponse(rsp *http.Response) (*MultipleRequestAndResponseTypesResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
@@ -1449,6 +2160,64 @@ func ParseMultipleRequestAndResponseTypesResponse(rsp *http.Response) (*Multiple
return response, nil
}
+// ParseNoContentHeadersResponse parses an HTTP response from a NoContentHeadersWithResponse call
+func ParseNoContentHeadersResponse(rsp *http.Response) (*NoContentHeadersResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &NoContentHeadersResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
+// ParseRequiredJSONBodyResponse parses an HTTP response from a RequiredJSONBodyWithResponse call
+func ParseRequiredJSONBodyResponse(rsp *http.Response) (*RequiredJSONBodyResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &RequiredJSONBodyResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ switch {
+ case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+ var dest Example
+ if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+ return nil, err
+ }
+ response.JSON200 = &dest
+
+ }
+
+ return response, nil
+}
+
+// ParseRequiredTextBodyResponse parses an HTTP response from a RequiredTextBodyWithResponse call
+func ParseRequiredTextBodyResponse(rsp *http.Response) (*RequiredTextBodyResponse, error) {
+ bodyBytes, err := io.ReadAll(rsp.Body)
+ defer func() { _ = rsp.Body.Close() }()
+ if err != nil {
+ return nil, err
+ }
+
+ response := &RequiredTextBodyResponse{
+ Body: bodyBytes,
+ HTTPResponse: rsp,
+ }
+
+ return response, nil
+}
+
// ParseReservedGoKeywordParametersResponse parses an HTTP response from a ReservedGoKeywordParametersWithResponse call
func ParseReservedGoKeywordParametersResponse(rsp *http.Response) (*ReservedGoKeywordParametersResponse, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
@@ -1603,9 +2372,7 @@ func ParseUnionExampleResponse(rsp *http.Response) (*UnionExampleResponse, error
response.ApplicationalternativeJSON200 = &dest
case rsp.Header.Get("Content-Type") == "application/json" && rsp.StatusCode == 200:
- var dest struct {
- union json.RawMessage
- }
+ var dest UnionExample200JSONResponseBody
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
diff --git a/internal/test/strict-server/client/client.go b/internal/test/strict-server/client/client.go
index 3b37a171f0..5b350a4884 100644
--- a/internal/test/strict-server/client/client.go
+++ b/internal/test/strict-server/client/client.go
@@ -1,3 +1,3 @@
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=client.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=client.cfg.yaml ../strict-schema.yaml
package api
diff --git a/internal/test/strict-server/echo/server.cfg.yaml b/internal/test/strict-server/echo/server.cfg.yaml
index 3c3c5c9c5d..143f57f078 100644
--- a/internal/test/strict-server/echo/server.cfg.yaml
+++ b/internal/test/strict-server/echo/server.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
echo-server: true
diff --git a/internal/test/strict-server/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go
index 3a03e11813..f3d5f6eaf9 100644
--- a/internal/test/strict-server/echo/server.gen.go
+++ b/internal/test/strict-server/echo/server.gen.go
@@ -1,16 +1,18 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
+ "errors"
"fmt"
"io"
+ "mime"
"mime/multipart"
"net/http"
"net/url"
@@ -20,7 +22,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
"github.com/oapi-codegen/runtime"
- strictecho "github.com/oapi-codegen/runtime/strictmiddleware/echo"
)
// ServerInterface represents all server handlers.
@@ -32,9 +33,21 @@ type ServerInterface interface {
// (POST /multipart)
MultipartExample(ctx echo.Context) error
+ // (POST /multipart-related)
+ MultipartRelatedExample(ctx echo.Context) error
+
// (POST /multiple)
MultipleRequestAndResponseTypes(ctx echo.Context) error
+ // (POST /no-content-headers)
+ NoContentHeaders(ctx echo.Context) error
+
+ // (POST /required-json-body)
+ RequiredJSONBody(ctx echo.Context) error
+
+ // (POST /required-text-body)
+ RequiredTextBody(ctx echo.Context) error
+
// (GET /reserved-go-keyword-parameters/{type})
ReservedGoKeywordParameters(ctx echo.Context, pType string) error
@@ -83,6 +96,15 @@ func (w *ServerInterfaceWrapper) MultipartExample(ctx echo.Context) error {
return err
}
+// MultipartRelatedExample converts echo context to params.
+func (w *ServerInterfaceWrapper) MultipartRelatedExample(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.MultipartRelatedExample(ctx)
+ return err
+}
+
// MultipleRequestAndResponseTypes converts echo context to params.
func (w *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(ctx echo.Context) error {
var err error
@@ -92,13 +114,40 @@ func (w *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(ctx echo.Contex
return err
}
+// NoContentHeaders converts echo context to params.
+func (w *ServerInterfaceWrapper) NoContentHeaders(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.NoContentHeaders(ctx)
+ return err
+}
+
+// RequiredJSONBody converts echo context to params.
+func (w *ServerInterfaceWrapper) RequiredJSONBody(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.RequiredJSONBody(ctx)
+ return err
+}
+
+// RequiredTextBody converts echo context to params.
+func (w *ServerInterfaceWrapper) RequiredTextBody(ctx echo.Context) error {
+ var err error
+
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.RequiredTextBody(ctx)
+ return err
+}
+
// ReservedGoKeywordParameters converts echo context to params.
func (w *ServerInterfaceWrapper) ReservedGoKeywordParameters(ctx echo.Context) error {
var err error
// ------------- Path parameter "type" -------------
var pType string
- err = runtime.BindStyledParameterWithLocation("simple", false, "type", runtime.ParamLocationPath, ctx.Param("type"), &pType)
+ err = runtime.BindStyledParameterWithOptions("simple", "type", ctx.Param("type"), &pType, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter type: %s", err))
}
@@ -169,7 +218,7 @@ func (w *ServerInterfaceWrapper) HeadersExample(ctx echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for header1, got %d", n))
}
- err = runtime.BindStyledParameterWithLocation("simple", false, "header1", runtime.ParamLocationHeader, valueList[0], &Header1)
+ err = runtime.BindStyledParameterWithOptions("simple", "header1", valueList[0], &Header1, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter header1: %s", err))
}
@@ -186,7 +235,7 @@ func (w *ServerInterfaceWrapper) HeadersExample(ctx echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for header2, got %d", n))
}
- err = runtime.BindStyledParameterWithLocation("simple", false, "header2", runtime.ParamLocationHeader, valueList[0], &Header2)
+ err = runtime.BindStyledParameterWithOptions("simple", "header2", valueList[0], &Header2, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: ""})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter header2: %s", err))
}
@@ -223,30 +272,53 @@ type EchoRouter interface {
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
}
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
wrapper := ServerInterfaceWrapper{
Handler: si,
}
- router.POST(baseURL+"/json", wrapper.JSONExample)
- router.POST(baseURL+"/multipart", wrapper.MultipartExample)
- router.POST(baseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes)
- router.GET(baseURL+"/reserved-go-keyword-parameters/:type", wrapper.ReservedGoKeywordParameters)
- router.POST(baseURL+"/reusable-responses", wrapper.ReusableResponses)
- router.POST(baseURL+"/text", wrapper.TextExample)
- router.POST(baseURL+"/unknown", wrapper.UnknownExample)
- router.POST(baseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType)
- router.POST(baseURL+"/urlencoded", wrapper.URLEncodedExample)
- router.POST(baseURL+"/with-headers", wrapper.HeadersExample)
- router.POST(baseURL+"/with-union", wrapper.UnionExample)
+ router.POST(options.BaseURL+"/json", wrapper.JSONExample, options.OperationMiddlewares["JSONExample"]...)
+ router.POST(options.BaseURL+"/multipart", wrapper.MultipartExample, options.OperationMiddlewares["MultipartExample"]...)
+ router.POST(options.BaseURL+"/multipart-related", wrapper.MultipartRelatedExample, options.OperationMiddlewares["MultipartRelatedExample"]...)
+ router.POST(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes, options.OperationMiddlewares["MultipleRequestAndResponseTypes"]...)
+ router.POST(options.BaseURL+"/no-content-headers", wrapper.NoContentHeaders, options.OperationMiddlewares["NoContentHeaders"]...)
+ router.POST(options.BaseURL+"/required-json-body", wrapper.RequiredJSONBody, options.OperationMiddlewares["RequiredJSONBody"]...)
+ router.POST(options.BaseURL+"/required-text-body", wrapper.RequiredTextBody, options.OperationMiddlewares["RequiredTextBody"]...)
+ router.GET(options.BaseURL+"/reserved-go-keyword-parameters/:type", wrapper.ReservedGoKeywordParameters, options.OperationMiddlewares["ReservedGoKeywordParameters"]...)
+ router.POST(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses, options.OperationMiddlewares["ReusableResponses"]...)
+ router.POST(options.BaseURL+"/text", wrapper.TextExample, options.OperationMiddlewares["TextExample"]...)
+ router.POST(options.BaseURL+"/unknown", wrapper.UnknownExample, options.OperationMiddlewares["UnknownExample"]...)
+ router.POST(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType, options.OperationMiddlewares["UnspecifiedContentType"]...)
+ router.POST(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample, options.OperationMiddlewares["URLEncodedExample"]...)
+ router.POST(options.BaseURL+"/with-headers", wrapper.HeadersExample, options.OperationMiddlewares["HeadersExample"]...)
+ router.POST(options.BaseURL+"/with-union", wrapper.UnionExample, options.OperationMiddlewares["UnionExample"]...)
}
@@ -274,10 +346,15 @@ type JSONExampleResponseObject interface {
type JSONExample200JSONResponse Example
func (response JSONExample200JSONResponse) VisitJSONExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type JSONExample400Response = BadrequestResponse
@@ -308,6 +385,7 @@ type MultipartExample200MultipartResponse func(writer *multipart.Writer) error
func (response MultipartExample200MultipartResponse) VisitMultipartExampleResponse(w http.ResponseWriter) error {
writer := multipart.NewWriter(w)
+
w.Header().Set("Content-Type", writer.FormDataContentType())
w.WriteHeader(200)
@@ -331,6 +409,42 @@ func (response MultipartExampledefaultResponse) VisitMultipartExampleResponse(w
return nil
}
+type MultipartRelatedExampleRequestObject struct {
+ Body *multipart.Reader
+}
+
+type MultipartRelatedExampleResponseObject interface {
+ VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error
+}
+
+type MultipartRelatedExample200MultipartResponse func(writer *multipart.Writer) error
+
+func (response MultipartRelatedExample200MultipartResponse) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ writer := multipart.NewWriter(w)
+
+ w.Header().Set("Content-Type", mime.FormatMediaType("multipart/related", map[string]string{"boundary": writer.Boundary()}))
+ w.WriteHeader(200)
+
+ defer writer.Close()
+ return response(writer)
+}
+
+type MultipartRelatedExample400Response = BadrequestResponse
+
+func (response MultipartRelatedExample400Response) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type MultipartRelatedExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response MultipartRelatedExampledefaultResponse) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
type MultipleRequestAndResponseTypesRequestObject struct {
JSONBody *MultipleRequestAndResponseTypesJSONRequestBody
FormdataBody *MultipleRequestAndResponseTypesFormdataRequestBody
@@ -346,24 +460,29 @@ type MultipleRequestAndResponseTypesResponseObject interface {
type MultipleRequestAndResponseTypes200JSONResponse Example
func (response MultipleRequestAndResponseTypes200JSONResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type MultipleRequestAndResponseTypes200FormdataResponse Example
func (response MultipleRequestAndResponseTypes200FormdataResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
- w.WriteHeader(200)
- if form, err := runtime.MarshalForm(response, nil); err != nil {
- return err
- } else {
- _, err := w.Write([]byte(form.Encode()))
+ form, err := runtime.MarshalForm(response, nil)
+ if err != nil {
return err
}
+ w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
+ w.WriteHeader(200)
+ _, err = w.Write([]byte(form.Encode()))
+ return err
}
type MultipleRequestAndResponseTypes200ImagepngResponse struct {
@@ -372,6 +491,7 @@ type MultipleRequestAndResponseTypes200ImagepngResponse struct {
}
func (response MultipleRequestAndResponseTypes200ImagepngResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "image/png")
if response.ContentLength != 0 {
w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
@@ -389,6 +509,7 @@ type MultipleRequestAndResponseTypes200MultipartResponse func(writer *multipart.
func (response MultipleRequestAndResponseTypes200MultipartResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
writer := multipart.NewWriter(w)
+
w.Header().Set("Content-Type", writer.FormDataContentType())
w.WriteHeader(200)
@@ -399,6 +520,7 @@ func (response MultipleRequestAndResponseTypes200MultipartResponse) VisitMultipl
type MultipleRequestAndResponseTypes200TextResponse string
func (response MultipleRequestAndResponseTypes200TextResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(200)
@@ -413,6 +535,106 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA
return nil
}
+type NoContentHeadersRequestObject struct {
+}
+
+type NoContentHeadersResponseObject interface {
+ VisitNoContentHeadersResponse(w http.ResponseWriter) error
+}
+
+type NoContentHeaders204ResponseHeaders struct {
+ NullableHeader *string
+ OptionalHeader *string
+}
+
+type NoContentHeaders204Response struct {
+ Headers NoContentHeaders204ResponseHeaders
+}
+
+func (response NoContentHeaders204Response) VisitNoContentHeadersResponse(w http.ResponseWriter) error {
+ if response.Headers.NullableHeader != nil {
+ w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader))
+ }
+ if response.Headers.OptionalHeader != nil {
+ w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader))
+ }
+ w.WriteHeader(204)
+ return nil
+}
+
+type RequiredJSONBodyRequestObject struct {
+ Body *RequiredJSONBodyJSONRequestBody
+}
+
+type RequiredJSONBodyResponseObject interface {
+ VisitRequiredJSONBodyResponse(w http.ResponseWriter) error
+}
+
+type RequiredJSONBody200JSONResponse Example
+
+func (response RequiredJSONBody200JSONResponse) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type RequiredJSONBody400Response = BadrequestResponse
+
+func (response RequiredJSONBody400Response) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type RequiredJSONBodydefaultResponse struct {
+ StatusCode int
+}
+
+func (response RequiredJSONBodydefaultResponse) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type RequiredTextBodyRequestObject struct {
+ Body *RequiredTextBodyTextRequestBody
+}
+
+type RequiredTextBodyResponseObject interface {
+ VisitRequiredTextBodyResponse(w http.ResponseWriter) error
+}
+
+type RequiredTextBody200TextResponse string
+
+func (response RequiredTextBody200TextResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "text/plain")
+ w.WriteHeader(200)
+
+ _, err := w.Write([]byte(response))
+ return err
+}
+
+type RequiredTextBody400Response = BadrequestResponse
+
+func (response RequiredTextBody400Response) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type RequiredTextBodydefaultResponse struct {
+ StatusCode int
+}
+
+func (response RequiredTextBodydefaultResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
type ReservedGoKeywordParametersRequestObject struct {
Type string `json:"type"`
}
@@ -424,6 +646,7 @@ type ReservedGoKeywordParametersResponseObject interface {
type ReservedGoKeywordParameters200TextResponse string
func (response ReservedGoKeywordParameters200TextResponse) VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(200)
@@ -442,12 +665,17 @@ type ReusableResponsesResponseObject interface {
type ReusableResponses200JSONResponse struct{ ReusableresponseJSONResponse }
func (response ReusableResponses200JSONResponse) VisitReusableResponsesResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type ReusableResponses400Response = BadrequestResponse
@@ -477,6 +705,7 @@ type TextExampleResponseObject interface {
type TextExample200TextResponse string
func (response TextExample200TextResponse) VisitTextExampleResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(200)
@@ -514,6 +743,7 @@ type UnknownExample200Videomp4Response struct {
}
func (response UnknownExample200Videomp4Response) VisitUnknownExampleResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "video/mp4")
if response.ContentLength != 0 {
w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
@@ -559,6 +789,7 @@ type UnspecifiedContentType200VideoResponse struct {
}
func (response UnspecifiedContentType200VideoResponse) VisitUnspecifiedContentTypeResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", response.ContentType)
if response.ContentLength != 0 {
w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
@@ -615,15 +846,15 @@ type URLEncodedExampleResponseObject interface {
type URLEncodedExample200FormdataResponse Example
func (response URLEncodedExample200FormdataResponse) VisitURLEncodedExampleResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
- w.WriteHeader(200)
- if form, err := runtime.MarshalForm(response, nil); err != nil {
- return err
- } else {
- _, err := w.Write([]byte(form.Encode()))
+ form, err := runtime.MarshalForm(response, nil)
+ if err != nil {
return err
}
+ w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
+ w.WriteHeader(200)
+ _, err = w.Write([]byte(form.Encode()))
+ return err
}
type URLEncodedExample400Response = BadrequestResponse
@@ -652,8 +883,10 @@ type HeadersExampleResponseObject interface {
}
type HeadersExample200ResponseHeaders struct {
- Header1 string
- Header2 int
+ Header1 string
+ Header2 int
+ NullableHeader *string
+ OptionalHeader *string
}
type HeadersExample200JSONResponse struct {
@@ -662,12 +895,23 @@ type HeadersExample200JSONResponse struct {
}
func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
+ if response.Headers.NullableHeader != nil {
+ w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader))
+ }
+ if response.Headers.OptionalHeader != nil {
+ w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader))
+ }
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type HeadersExample400Response = BadrequestResponse
@@ -705,28 +949,36 @@ type UnionExample200ApplicationAlternativePlusJSONResponse struct {
}
func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/alternative+json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type UnionExample200JSONResponse struct {
- Body struct {
- union json.RawMessage
- }
+ Body UnionExample200JSONResponseBody
Headers UnionExample200ResponseHeaders
}
func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body.union); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body.union)
+ _, err := buf.WriteTo(w)
+ return err
}
type UnionExample400Response = BadrequestResponse
@@ -754,9 +1006,21 @@ type StrictServerInterface interface {
// (POST /multipart)
MultipartExample(ctx context.Context, request MultipartExampleRequestObject) (MultipartExampleResponseObject, error)
+ // (POST /multipart-related)
+ MultipartRelatedExample(ctx context.Context, request MultipartRelatedExampleRequestObject) (MultipartRelatedExampleResponseObject, error)
+
// (POST /multiple)
MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error)
+ // (POST /no-content-headers)
+ NoContentHeaders(ctx context.Context, request NoContentHeadersRequestObject) (NoContentHeadersResponseObject, error)
+
+ // (POST /required-json-body)
+ RequiredJSONBody(ctx context.Context, request RequiredJSONBodyRequestObject) (RequiredJSONBodyResponseObject, error)
+
+ // (POST /required-text-body)
+ RequiredTextBody(ctx context.Context, request RequiredTextBodyRequestObject) (RequiredTextBodyResponseObject, error)
+
// (GET /reserved-go-keyword-parameters/{type})
ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error)
@@ -782,8 +1046,8 @@ type StrictServerInterface interface {
UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error)
}
-type StrictHandlerFunc = strictecho.StrictEchoHandlerFunc
-type StrictMiddlewareFunc = strictecho.StrictEchoMiddlewareFunc
+type StrictHandlerFunc func(ctx echo.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
return &strictHandler{ssi: ssi, middlewares: middlewares}
@@ -800,9 +1064,12 @@ func (sh *strictHandler) JSONExample(ctx echo.Context) error {
var body JSONExampleJSONRequestBody
if err := ctx.Bind(&body); err != nil {
- return err
+ if !errors.Is(err, io.EOF) {
+ return err
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
return sh.ssi.JSONExample(ctx.Request().Context(), request.(JSONExampleRequestObject))
@@ -852,6 +1119,37 @@ func (sh *strictHandler) MultipartExample(ctx echo.Context) error {
return nil
}
+// MultipartRelatedExample operation middleware
+func (sh *strictHandler) MultipartRelatedExample(ctx echo.Context) error {
+ var request MultipartRelatedExampleRequestObject
+
+ if _, params, err := mime.ParseMediaType(ctx.Request().Header.Get("Content-Type")); err != nil {
+ return err
+ } else if boundary := params["boundary"]; boundary == "" {
+ return http.ErrMissingBoundary
+ } else {
+ request.Body = multipart.NewReader(ctx.Request().Body, boundary)
+ }
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.MultipartRelatedExample(ctx.Request().Context(), request.(MultipartRelatedExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "MultipartRelatedExample")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(MultipartRelatedExampleResponseObject); ok {
+ return validResponse.VisitMultipartRelatedExampleResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
// MultipleRequestAndResponseTypes operation middleware
func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx echo.Context) error {
var request MultipleRequestAndResponseTypesRequestObject
@@ -859,9 +1157,12 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx echo.Context) error
if strings.HasPrefix(ctx.Request().Header.Get("Content-Type"), "application/json") {
var body MultipleRequestAndResponseTypesJSONRequestBody
if err := ctx.Bind(&body); err != nil {
- return err
+ if !errors.Is(err, io.EOF) {
+ return err
+ }
+ } else {
+ request.JSONBody = &body
}
- request.JSONBody = &body
}
if strings.HasPrefix(ctx.Request().Header.Get("Content-Type"), "application/x-www-form-urlencoded") {
if form, err := ctx.FormParams(); err == nil {
@@ -889,8 +1190,10 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx echo.Context) error
if err != nil {
return err
}
- body := MultipleRequestAndResponseTypesTextRequestBody(data)
- request.TextBody = &body
+ if len(data) > 0 {
+ body := MultipleRequestAndResponseTypesTextRequestBody(data)
+ request.TextBody = &body
+ }
}
handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
@@ -912,6 +1215,88 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx echo.Context) error
return nil
}
+// NoContentHeaders operation middleware
+func (sh *strictHandler) NoContentHeaders(ctx echo.Context) error {
+ var request NoContentHeadersRequestObject
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.NoContentHeaders(ctx.Request().Context(), request.(NoContentHeadersRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "NoContentHeaders")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(NoContentHeadersResponseObject); ok {
+ return validResponse.VisitNoContentHeadersResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// RequiredJSONBody operation middleware
+func (sh *strictHandler) RequiredJSONBody(ctx echo.Context) error {
+ var request RequiredJSONBodyRequestObject
+
+ var body RequiredJSONBodyJSONRequestBody
+ if err := ctx.Bind(&body); err != nil {
+ return err
+ }
+ request.Body = &body
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.RequiredJSONBody(ctx.Request().Context(), request.(RequiredJSONBodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "RequiredJSONBody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(RequiredJSONBodyResponseObject); ok {
+ return validResponse.VisitRequiredJSONBodyResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// RequiredTextBody operation middleware
+func (sh *strictHandler) RequiredTextBody(ctx echo.Context) error {
+ var request RequiredTextBodyRequestObject
+
+ data, err := io.ReadAll(ctx.Request().Body)
+ if err != nil {
+ return err
+ }
+ body := RequiredTextBodyTextRequestBody(data)
+ request.Body = &body
+
+ handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.RequiredTextBody(ctx.Request().Context(), request.(RequiredTextBodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "RequiredTextBody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.(RequiredTextBodyResponseObject); ok {
+ return validResponse.VisitRequiredTextBodyResponse(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
// ReservedGoKeywordParameters operation middleware
func (sh *strictHandler) ReservedGoKeywordParameters(ctx echo.Context, pType string) error {
var request ReservedGoKeywordParametersRequestObject
@@ -943,9 +1328,12 @@ func (sh *strictHandler) ReusableResponses(ctx echo.Context) error {
var body ReusableResponsesJSONRequestBody
if err := ctx.Bind(&body); err != nil {
- return err
+ if !errors.Is(err, io.EOF) {
+ return err
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
return sh.ssi.ReusableResponses(ctx.Request().Context(), request.(ReusableResponsesRequestObject))
@@ -974,8 +1362,10 @@ func (sh *strictHandler) TextExample(ctx echo.Context) error {
if err != nil {
return err
}
- body := TextExampleTextRequestBody(data)
- request.Body = &body
+ if len(data) > 0 {
+ body := TextExampleTextRequestBody(data)
+ request.Body = &body
+ }
handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
return sh.ssi.TextExample(ctx.Request().Context(), request.(TextExampleRequestObject))
@@ -1089,9 +1479,12 @@ func (sh *strictHandler) HeadersExample(ctx echo.Context, params HeadersExampleP
var body HeadersExampleJSONRequestBody
if err := ctx.Bind(&body); err != nil {
- return err
+ if !errors.Is(err, io.EOF) {
+ return err
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
return sh.ssi.HeadersExample(ctx.Request().Context(), request.(HeadersExampleRequestObject))
@@ -1118,9 +1511,12 @@ func (sh *strictHandler) UnionExample(ctx echo.Context) error {
var body UnionExampleJSONRequestBody
if err := ctx.Bind(&body); err != nil {
- return err
+ if !errors.Is(err, io.EOF) {
+ return err
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx echo.Context, request interface{}) (interface{}, error) {
return sh.ssi.UnionExample(ctx.Request().Context(), request.(UnionExampleRequestObject))
@@ -1141,43 +1537,49 @@ func (sh *strictHandler) UnionExample(ctx echo.Context) error {
return nil
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/+xYS2/jNhD+KwTb01aynGxOunWDxbbdtimc5FTkQIsjm7sSyQ5HVgzD/72gKL9ixbW3",
- "fhRBb3oMvxl+8+BwZjwzpTUaNDmezjiCs0Y7aF6GQiL8VYEj/ybBZagsKaN5yj8IOWj/zSOOUDkxLGCx",
- "3MtnRhPoZqmwtlCZ8EuTL86vn3GXjaEU/ul7hJyn/LtkZUoS/roEnkVpC+Dz+Tx6YcHdZx7xMQgJ2Fgb",
- "Hq82sWlqgafcESo94h4kiF13iilNMAL02rxoa4QXWNiRzrhFYwFJBY4moqigW1P7xQy/QEZhB0rnZpvL",
- "W6NJKO2YVHkOCJpYSx7zGI65ylqDBJINp8xryIg5wAkgjzgp8obx+/XvrDXY8YhPAF1QdNXr9/reX8aC",
- "FlbxlL9vPkXcCho3G1o6yJouv/9yf/c7U46JikwpSGWiKKasFOjGogDJlCbjTawycj3eaMLG8T/LdvXH",
- "lkofNU0AfTByeoqAaeJyLZyv+/0zxeU84jdBWRfG0qhkLcEamFxURQfnj/qrNrVmgGiw3VlSVgUpK5DW",
- "fbXJ9m8LkX0oX+IlucEyloLEiVg/lqaLEt/Wgs4cuR+b2rGxqRkZJkEUrFY0ZouFL5JbaSaYU3pUAFsY",
- "FXV6soC25P6o5aDdy4PHOHkuRRsoz3Fd13HjvAoL0JmRIL8NVpViBInVo83lHlsQT/lwSj5st4vrkYIo",
- "4gTPlNhCKL375DhTOfmf6aMldkhXhOZElPHIxF9hWhuUsRUoSiBAl8y89rkHHkFHKv+xlGSZ0GwITIsS",
- "JBM5AbJPhrWQbitlB63eT+ZzEFlBNcft8iX9c8Y9Jc0RzCPuFfA0sBLyWqF3OmEF0Q7anv4xPv+VAxZs",
- "hkYv3lDVXQYXJWpJHULufEns8lwHf0HTYE3iMg3D7ojban3PcQZ5T75+7j/A815H/hFL37lz+1DCqvDx",
- "dc7aVfvQ9o2VdA8WJ0qCSUp7cyDyxUh1FjKVK5Bxu4s42PZaSbg1OkOgzRbIXye0IbYE87ccGgMLDETM",
- "GVYDKytHzArnmKKmihQq3JQkbBWPx5Vlt0HTw6qc7vLquxP59N2lPHrTvzp8yfsTx81GK/NKPg5+/Rhk",
- "Dr0vHq1nOrDjO57eC6Wzv6TEawOV7hT+KQiszvQM1MR3RFoyBKpQg2QTJRZDgK3cbAFWbu3qhYIZq25o",
- "Mdw5pCGKdmJd82jXAOjpDY8nTjk2O1ecVlrtGlM9+t+s7aFfng3K6P/oEEoUBKgFqQn8cJwb5DaK0XCX",
- "N5n2wsvRnhqe3l5UzSMe5qahBFVY+DpBZNMkCfPWnqvFaATYUyYRVnkW/g4AAP//Pk3lbjwXAAA=",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "7Fnbcts2E36VHfz/RZuSpuL4SndNJpO2aZOObF91fAERKwkJCSDAUrJGo5k+RJ+wT9IBAepI21KqgyfT",
+ "O4ncE/fbXX5LzFiuS6MVKnKsO2MWndHKYf2nz4XFLxU68v8EutxKQ1Ir1mWvuejFe/OEWawc7xfYqHv5",
+ "XCtCVatyYwqZc6+afXJef8ZcPsKS+1//tzhgXfa/bBlKFu66DO95aQpk8/k82Yjg43uWsBFygbaONvx8",
+ "GZ7iSyUtCtYlW2Gy4oumBlmXObJSDZk3GtQud1KTinCI1kfjVWOQXqCJsztjxmqDlmTI4ZgXFbZ7jld0",
+ "/xPmFJ5QqoHezvUbrYhL5UDIwQAtKoKYXPA2HLjKGG0JBfSn4D3kBA7tGC1LGEnygbHr1esQA3YsYWO0",
+ "Ljh6edG56Hg8tUHFjWRd9qq+lDDDaVQ/0AJAo9vq4pfrjx9AOuAV6ZKTzHlRTKHk1o14gQKkIu1DrHJy",
+ "F6z2ZOvC+FlE7bcxlQmLxfdai+kxCqqu25Vyv+x0TlS384RdBWdtNhZBZSsNWJsZ8Kpoyfmt+qz0RAFa",
+ "q218sqysCpKGW1rFaj3bvzUiu6R8YS8baFumghM/UtYP5enciU8tFpz8OHkSgF6Q3A+HFfNHReHf+Dkr",
+ "BnEet86p65GeOBjpCZAGgbyAiaQRNIobA1Yq4OCkGhYITVBJK5gFxtfij0r04rPceBtHn2fJmpX7dDKZ",
+ "pHUDVbZAlWvxdRAmTJZ8iJlRw3V1b5sT67L+lHzJbr/gDtTICSO8p8wUXG4kZtPliUb6f5k+WGOHdlU6",
+ "jRClK4SuvXE/LGThu8vO1ffQGA4NrGs5XgBXAlRVFJ6WLmWiefj7z78A79Hm0qEDGnGCSjmkhQC3CLqU",
+ "5EnVwOoSaLQ0s9X7H/SbENNPMfytOrxqexKIWutEtok65mIdiOZmw1G3a6HJQKv6dscEBBrqm/qeSPtx",
+ "QrUjEAcceClP9RrdBJyGUjo/J8NNN9JVIYAXEz51YUJvc75eVPfcrx6NRyd+yQbT/7aJ4AJa39vngfYG",
+ "7+lJaPcYPfvCd+qptj9E9VYm0qFOP+N0oq1IDbe8RELrspmPc+5tDbHF5O8LSci5gj6C4iUK4ANCC+80",
+ "RJOuBZ/g951+H0SWpuqVb/Gn+8eM+eTVayBLmHfAuiF/yR7r9t1xoWqyGT5GpGuuHir4KNKkzuLAeUrY",
+ "hnFL/oKn3orEeZbWx2tz6/PMKYraI/nw6uNHwi7rzgGp33OfAlW4+HDOotYuaftKJrlDFsdSoM5Kc7Wn",
+ "5bMl1RnM5UCiWHDMENtDI+GNVrlFWl8B/ctQaYKFMehPa0oYMlC/HycIZeUIDHcOJNVTpJDha53Y5oy3",
+ "y8giDbxZjtPHUH1xJExfnAvRq87L/VVeHblu1la5B/qx9+vbILPvN8uD7Yx7bryH83umdvY73tM7YtzC",
+ "lu/0HOXYMyIlwCJVVqGAseTNh+it3owGlrC2caG4Xy3YUHMAsQ8hSh61dckePYS4+4Y/kZ/vaCc58QJ+",
+ "qq6plHzs4ObW34bI6DffVFKrZ3oswwtCqzjJMf5wmO9521a0wo+Duu830Et29HD3/I4vj11184SFk8Yw",
+ "MCtb+KlGZLpZFk4oL9yED4doL6TOuJE+S/8EAAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -1185,7 +1587,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -1203,12 +1605,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -1234,3 +1636,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/strict-server/echo/server.go b/internal/test/strict-server/echo/server.go
index 669d4da4f4..1f4c633fae 100644
--- a/internal/test/strict-server/echo/server.go
+++ b/internal/test/strict-server/echo/server.go
@@ -1,5 +1,5 @@
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
package api
@@ -41,6 +41,30 @@ func (s StrictServer) MultipartExample(ctx context.Context, request MultipartExa
}), nil
}
+func (s StrictServer) MultipartRelatedExample(ctx context.Context, request MultipartRelatedExampleRequestObject) (MultipartRelatedExampleResponseObject, error) {
+ return MultipartRelatedExample200MultipartResponse(func(writer *multipart.Writer) error {
+ for {
+ part, err := request.Body.NextPart()
+ if err == io.EOF {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ w, err := writer.CreatePart(part.Header)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(w, part)
+ if err != nil {
+ return err
+ }
+ if err = part.Close(); err != nil {
+ return err
+ }
+ }
+ }), nil
+}
+
func (s StrictServer) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error) {
switch {
case request.Body != nil:
@@ -98,10 +122,22 @@ func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExample
return HeadersExample200JSONResponse{Body: *request.Body, Headers: HeadersExample200ResponseHeaders{Header1: request.Params.Header1, Header2: *request.Params.Header2}}, nil
}
+func (s StrictServer) NoContentHeaders(ctx context.Context, request NoContentHeadersRequestObject) (NoContentHeadersResponseObject, error) {
+ return NoContentHeaders204Response{}, nil
+}
+
func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) {
return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil
}
+func (s StrictServer) RequiredJSONBody(ctx context.Context, request RequiredJSONBodyRequestObject) (RequiredJSONBodyResponseObject, error) {
+ return RequiredJSONBody200JSONResponse(*request.Body), nil
+}
+
+func (s StrictServer) RequiredTextBody(ctx context.Context, request RequiredTextBodyRequestObject) (RequiredTextBodyResponseObject, error) {
+ return RequiredTextBody200TextResponse(*request.Body), nil
+}
+
func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) {
return ReservedGoKeywordParameters200TextResponse(""), nil
}
diff --git a/internal/test/strict-server/echo/types.cfg.yaml b/internal/test/strict-server/echo/types.cfg.yaml
index 4ea1d8aa5b..2ed9740ea7 100644
--- a/internal/test/strict-server/echo/types.cfg.yaml
+++ b/internal/test/strict-server/echo/types.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
models: true
diff --git a/internal/test/strict-server/echo/types.gen.go b/internal/test/strict-server/echo/types.gen.go
index 6a0de0c970..08ae8548e1 100644
--- a/internal/test/strict-server/echo/types.gen.go
+++ b/internal/test/strict-server/echo/types.gen.go
@@ -1,8 +1,14 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
+import (
+ "encoding/json"
+
+ "github.com/oapi-codegen/runtime"
+)
+
// Example defines model for example.
type Example struct {
Value *string `json:"value,omitempty"`
@@ -14,6 +20,9 @@ type Reusableresponse = Example
// MultipleRequestAndResponseTypesTextBody defines parameters for MultipleRequestAndResponseTypes.
type MultipleRequestAndResponseTypesTextBody = string
+// RequiredTextBodyTextBody defines parameters for RequiredTextBody.
+type RequiredTextBodyTextBody = string
+
// TextExampleTextBody defines parameters for TextExample.
type TextExampleTextBody = string
@@ -23,12 +32,23 @@ type HeadersExampleParams struct {
Header2 *int `json:"header2,omitempty"`
}
+// UnionExample200JSONResponseBody0 defines parameters for UnionExample.
+type UnionExample200JSONResponseBody0 = string
+
+// UnionExample200JSONResponseBody defines parameters for UnionExample.
+type UnionExample200JSONResponseBody struct {
+ union json.RawMessage
+}
+
// JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType.
type JSONExampleJSONRequestBody = Example
// MultipartExampleMultipartRequestBody defines body for MultipartExample for multipart/form-data ContentType.
type MultipartExampleMultipartRequestBody = Example
+// MultipartRelatedExampleMultipartRequestBody defines body for MultipartRelatedExample for multipart/related ContentType.
+type MultipartRelatedExampleMultipartRequestBody = Example
+
// MultipleRequestAndResponseTypesJSONRequestBody defines body for MultipleRequestAndResponseTypes for application/json ContentType.
type MultipleRequestAndResponseTypesJSONRequestBody = Example
@@ -41,6 +61,12 @@ type MultipleRequestAndResponseTypesMultipartRequestBody = Example
// MultipleRequestAndResponseTypesTextRequestBody defines body for MultipleRequestAndResponseTypes for text/plain ContentType.
type MultipleRequestAndResponseTypesTextRequestBody = MultipleRequestAndResponseTypesTextBody
+// RequiredJSONBodyJSONRequestBody defines body for RequiredJSONBody for application/json ContentType.
+type RequiredJSONBodyJSONRequestBody = Example
+
+// RequiredTextBodyTextRequestBody defines body for RequiredTextBody for text/plain ContentType.
+type RequiredTextBodyTextRequestBody = RequiredTextBodyTextBody
+
// ReusableResponsesJSONRequestBody defines body for ReusableResponses for application/json ContentType.
type ReusableResponsesJSONRequestBody = Example
@@ -55,3 +81,65 @@ type HeadersExampleJSONRequestBody = Example
// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType.
type UnionExampleJSONRequestBody = Example
+
+// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0
+func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) {
+ var body UnionExample200JSONResponseBody0
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example
+func (t UnionExample200JSONResponseBody) AsExample() (Example, error) {
+ var body Example
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example
+func (t *UnionExample200JSONResponseBody) FromExample(v Example) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example
+func (t *UnionExample200JSONResponseBody) MergeExample(v Example) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
diff --git a/internal/test/strict-server/fiber/fiber_strict_test.go b/internal/test/strict-server/fiber/fiber_strict_test.go
new file mode 100644
index 0000000000..473aa394f8
--- /dev/null
+++ b/internal/test/strict-server/fiber/fiber_strict_test.go
@@ -0,0 +1,235 @@
+package api
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+ "mime"
+ "mime/multipart"
+ "net/http"
+ "net/url"
+ "strings"
+ "testing"
+
+ "github.com/gofiber/fiber/v2"
+ "github.com/gofiber/fiber/v2/middleware/adaptor"
+ "github.com/stretchr/testify/assert"
+
+ clientAPI "github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/client"
+ "github.com/oapi-codegen/runtime"
+ "github.com/oapi-codegen/testutil"
+)
+
+func TestFiberServer(t *testing.T) {
+ server := StrictServer{}
+ strictHandler := NewStrictHandler(server, nil)
+ r := fiber.New()
+ RegisterHandlers(r, strictHandler)
+ testImpl(t, adaptor.FiberApp(r))
+}
+
+func testImpl(t *testing.T, handler http.Handler) {
+ t.Run("JSONExample", func(t *testing.T) {
+ value := "123"
+ requestBody := clientAPI.Example{Value: &value}
+ rr := testutil.NewRequest().Post("/json").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
+ var responseBody clientAPI.Example
+ err := json.NewDecoder(rr.Body).Decode(&responseBody)
+ assert.NoError(t, err)
+ assert.Equal(t, requestBody, responseBody)
+ })
+ t.Run("URLEncodedExample", func(t *testing.T) {
+ value := "456"
+ requestBody := clientAPI.Example{Value: &value}
+ requestBodyEncoded, err := runtime.MarshalForm(&requestBody, nil)
+ assert.NoError(t, err)
+ rr := testutil.NewRequest().Post("/urlencoded").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(requestBodyEncoded.Encode())).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.Equal(t, "application/x-www-form-urlencoded", rr.Header().Get("Content-Type"))
+ values, err := url.ParseQuery(rr.Body.String())
+ assert.NoError(t, err)
+ var responseBody clientAPI.Example
+ err = runtime.BindForm(&responseBody, values, nil, nil)
+ assert.NoError(t, err)
+ assert.Equal(t, requestBody, responseBody)
+ })
+ t.Run("MultipartExample", func(t *testing.T) {
+ value := "789"
+ fieldName := "value"
+ var writer bytes.Buffer
+ mw := multipart.NewWriter(&writer)
+ field, err := mw.CreateFormField(fieldName)
+ assert.NoError(t, err)
+ _, _ = field.Write([]byte(value))
+ assert.NoError(t, mw.Close())
+ rr := testutil.NewRequest().Post("/multipart").WithContentType(mw.FormDataContentType()).WithBody(writer.Bytes()).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ contentType, params, err := mime.ParseMediaType(rr.Header().Get("Content-Type"))
+ assert.NoError(t, err)
+ assert.Equal(t, "multipart/form-data", contentType)
+ reader := multipart.NewReader(rr.Body, params["boundary"])
+ part, err := reader.NextPart()
+ assert.NoError(t, err)
+ assert.Equal(t, part.FormName(), fieldName)
+ readValue, err := io.ReadAll(part)
+ assert.NoError(t, err)
+ assert.Equal(t, value, string(readValue))
+ _, err = reader.NextPart()
+ assert.Equal(t, io.EOF, err)
+ })
+ t.Run("MultipartRelatedExample", func(t *testing.T) {
+ value := "789"
+ fieldName := "value"
+ var writer bytes.Buffer
+ mw := multipart.NewWriter(&writer)
+ field, err := mw.CreateFormField(fieldName)
+ assert.NoError(t, err)
+ _, _ = field.Write([]byte(value))
+ assert.NoError(t, mw.Close())
+ rr := testutil.NewRequest().Post("/multipart-related").WithContentType(mime.FormatMediaType("multipart/related", map[string]string{"boundary": mw.Boundary()})).WithBody(writer.Bytes()).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ contentType, params, err := mime.ParseMediaType(rr.Header().Get("Content-Type"))
+ assert.NoError(t, err)
+ assert.Equal(t, "multipart/related", contentType)
+ reader := multipart.NewReader(rr.Body, params["boundary"])
+ part, err := reader.NextPart()
+ assert.NoError(t, err)
+ assert.Equal(t, part.FormName(), fieldName)
+ readValue, err := io.ReadAll(part)
+ assert.NoError(t, err)
+ assert.Equal(t, value, string(readValue))
+ _, err = reader.NextPart()
+ assert.Equal(t, io.EOF, err)
+ })
+ t.Run("TextExample", func(t *testing.T) {
+ value := "text"
+ rr := testutil.NewRequest().Post("/text").WithContentType("text/plain").WithBody([]byte(value)).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.Equal(t, "text/plain", rr.Header().Get("Content-Type"))
+ assert.Equal(t, value, rr.Body.String())
+ })
+ t.Run("UnknownExample", func(t *testing.T) {
+ data := []byte("unknown data")
+ rr := testutil.NewRequest().Post("/unknown").WithContentType("image/png").WithBody(data).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.Equal(t, "video/mp4", rr.Header().Get("Content-Type"))
+ assert.Equal(t, data, rr.Body.Bytes())
+ })
+ t.Run("MultipleRequestAndResponseTypesJSON", func(t *testing.T) {
+ value := "123"
+ requestBody := clientAPI.Example{Value: &value}
+ rr := testutil.NewRequest().Post("/multiple").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
+ var responseBody clientAPI.Example
+ err := json.NewDecoder(rr.Body).Decode(&responseBody)
+ assert.NoError(t, err)
+ assert.Equal(t, requestBody, responseBody)
+ })
+ t.Run("MultipleRequestAndResponseTypesFormdata", func(t *testing.T) {
+ value := "456"
+ requestBody := clientAPI.Example{Value: &value}
+ requestBodyEncoded, err := runtime.MarshalForm(&requestBody, nil)
+ assert.NoError(t, err)
+ rr := testutil.NewRequest().Post("/multiple").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(requestBodyEncoded.Encode())).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.Equal(t, "application/x-www-form-urlencoded", rr.Header().Get("Content-Type"))
+ values, err := url.ParseQuery(rr.Body.String())
+ assert.NoError(t, err)
+ var responseBody clientAPI.Example
+ err = runtime.BindForm(&responseBody, values, nil, nil)
+ assert.NoError(t, err)
+ assert.Equal(t, requestBody, responseBody)
+ })
+ t.Run("MultipleRequestAndResponseTypesMultipart", func(t *testing.T) {
+ value := "789"
+ fieldName := "value"
+ var writer bytes.Buffer
+ mw := multipart.NewWriter(&writer)
+ field, err := mw.CreateFormField(fieldName)
+ assert.NoError(t, err)
+ _, _ = field.Write([]byte(value))
+ assert.NoError(t, mw.Close())
+ rr := testutil.NewRequest().Post("/multiple").WithContentType(mw.FormDataContentType()).WithBody(writer.Bytes()).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ contentType, params, err := mime.ParseMediaType(rr.Header().Get("Content-Type"))
+ assert.NoError(t, err)
+ assert.Equal(t, "multipart/form-data", contentType)
+ reader := multipart.NewReader(rr.Body, params["boundary"])
+ part, err := reader.NextPart()
+ assert.NoError(t, err)
+ assert.Equal(t, part.FormName(), fieldName)
+ readValue, err := io.ReadAll(part)
+ assert.NoError(t, err)
+ assert.Equal(t, value, string(readValue))
+ _, err = reader.NextPart()
+ assert.Equal(t, io.EOF, err)
+ })
+ t.Run("MultipleRequestAndResponseTypesText", func(t *testing.T) {
+ value := "text"
+ rr := testutil.NewRequest().Post("/multiple").WithContentType("text/plain").WithBody([]byte(value)).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.Equal(t, "text/plain", rr.Header().Get("Content-Type"))
+ assert.Equal(t, value, rr.Body.String())
+ })
+ t.Run("MultipleRequestAndResponseTypesImage", func(t *testing.T) {
+ data := []byte("unknown data")
+ rr := testutil.NewRequest().Post("/multiple").WithContentType("image/png").WithBody(data).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.Equal(t, "image/png", rr.Header().Get("Content-Type"))
+ assert.Equal(t, data, rr.Body.Bytes())
+ })
+ t.Run("HeadersExample", func(t *testing.T) {
+ header1 := "value1"
+ header2 := "890"
+ value := "asdf"
+ requestBody := clientAPI.Example{Value: &value}
+ rr := testutil.NewRequest().Post("/with-headers").WithHeader("header1", header1).WithHeader("header2", header2).WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
+ var responseBody clientAPI.Example
+ err := json.NewDecoder(rr.Body).Decode(&responseBody)
+ assert.NoError(t, err)
+ assert.Equal(t, requestBody, responseBody)
+ assert.Equal(t, header1, rr.Header().Get("header1"))
+ assert.Equal(t, header2, rr.Header().Get("header2"))
+ })
+ t.Run("NoContentHeadersOmitUnset", func(t *testing.T) {
+ rr := testutil.NewRequest().Post("/no-content-headers").GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusNoContent, rr.Code)
+ assert.Empty(t, rr.Header().Values("optional-header"), "optional-header should be omitted when the response field is nil")
+ assert.Empty(t, rr.Header().Values("nullable-header"), "nullable-header should be omitted when the response field is unspecified")
+ })
+ t.Run("UnspecifiedContentType", func(t *testing.T) {
+ data := []byte("image data")
+ contentType := "image/jpeg"
+ rr := testutil.NewRequest().Post("/unspecified-content-type").WithContentType(contentType).WithBody(data).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.Equal(t, contentType, rr.Header().Get("Content-Type"))
+ assert.Equal(t, data, rr.Body.Bytes())
+ })
+ t.Run("ReusableResponses", func(t *testing.T) {
+ value := "jkl;"
+ requestBody := clientAPI.Example{Value: &value}
+ rr := testutil.NewRequest().Post("/reusable-responses").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
+ var responseBody clientAPI.Example
+ err := json.NewDecoder(rr.Body).Decode(&responseBody)
+ assert.NoError(t, err)
+ assert.Equal(t, requestBody, responseBody)
+ })
+ t.Run("UnionResponses", func(t *testing.T) {
+ value := "union"
+ requestBody := clientAPI.Example{Value: &value}
+ rr := testutil.NewRequest().Post("/with-union").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
+ var responseBody clientAPI.Example
+ err := json.NewDecoder(rr.Body).Decode(&responseBody)
+ assert.NoError(t, err)
+ assert.Equal(t, requestBody, responseBody)
+ })
+}
diff --git a/internal/test/strict-server/fiber/server.cfg.yaml b/internal/test/strict-server/fiber/server.cfg.yaml
index 3a6471261f..73540ffc2c 100644
--- a/internal/test/strict-server/fiber/server.cfg.yaml
+++ b/internal/test/strict-server/fiber/server.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
fiber-server: true
diff --git a/internal/test/strict-server/fiber/server.gen.go b/internal/test/strict-server/fiber/server.gen.go
index bf34ef0d30..aa69ce929a 100644
--- a/internal/test/strict-server/fiber/server.gen.go
+++ b/internal/test/strict-server/fiber/server.gen.go
@@ -1,16 +1,17 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
- "encoding/json"
+ "errors"
"fmt"
"io"
+ "mime"
"mime/multipart"
"net/http"
"net/url"
@@ -31,9 +32,21 @@ type ServerInterface interface {
// (POST /multipart)
MultipartExample(c *fiber.Ctx) error
+ // (POST /multipart-related)
+ MultipartRelatedExample(c *fiber.Ctx) error
+
// (POST /multiple)
MultipleRequestAndResponseTypes(c *fiber.Ctx) error
+ // (POST /no-content-headers)
+ NoContentHeaders(c *fiber.Ctx) error
+
+ // (POST /required-json-body)
+ RequiredJSONBody(c *fiber.Ctx) error
+
+ // (POST /required-text-body)
+ RequiredTextBody(c *fiber.Ctx) error
+
// (GET /reserved-go-keyword-parameters/{type})
ReservedGoKeywordParameters(c *fiber.Ctx, pType string) error
@@ -61,79 +74,263 @@ type ServerInterface interface {
// ServerInterfaceWrapper converts contexts to parameters.
type ServerInterfaceWrapper struct {
- Handler ServerInterface
+ Handler ServerInterface
+ HandlerMiddlewares []HandlerMiddlewareFunc
}
type MiddlewareFunc fiber.Handler
+type HandlerMiddlewareFunc func(c *fiber.Ctx, next fiber.Handler) error
// JSONExample operation middleware
func (siw *ServerInterfaceWrapper) JSONExample(c *fiber.Ctx) error {
- return siw.Handler.JSONExample(c)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.JSONExample(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// MultipartExample operation middleware
func (siw *ServerInterfaceWrapper) MultipartExample(c *fiber.Ctx) error {
- return siw.Handler.MultipartExample(c)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.MultipartExample(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// MultipartRelatedExample operation middleware
+func (siw *ServerInterfaceWrapper) MultipartRelatedExample(c *fiber.Ctx) error {
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.MultipartRelatedExample(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// MultipleRequestAndResponseTypes operation middleware
func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(c *fiber.Ctx) error {
- return siw.Handler.MultipleRequestAndResponseTypes(c)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.MultipleRequestAndResponseTypes(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// NoContentHeaders operation middleware
+func (siw *ServerInterfaceWrapper) NoContentHeaders(c *fiber.Ctx) error {
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.NoContentHeaders(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// RequiredJSONBody operation middleware
+func (siw *ServerInterfaceWrapper) RequiredJSONBody(c *fiber.Ctx) error {
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.RequiredJSONBody(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
+}
+
+// RequiredTextBody operation middleware
+func (siw *ServerInterfaceWrapper) RequiredTextBody(c *fiber.Ctx) error {
+
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.RequiredTextBody(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// ReservedGoKeywordParameters operation middleware
func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(c *fiber.Ctx) error {
var err error
+ _ = err
// ------------- Path parameter "type" -------------
var pType string
- err = runtime.BindStyledParameter("simple", false, "type", c.Params("type"), &pType)
+ err = runtime.BindStyledParameterWithOptions("simple", "type", c.Params("type"), &pType, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter type: %w", err).Error())
}
- return siw.Handler.ReservedGoKeywordParameters(c, pType)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.ReservedGoKeywordParameters(c, pType)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// ReusableResponses operation middleware
func (siw *ServerInterfaceWrapper) ReusableResponses(c *fiber.Ctx) error {
- return siw.Handler.ReusableResponses(c)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.ReusableResponses(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// TextExample operation middleware
func (siw *ServerInterfaceWrapper) TextExample(c *fiber.Ctx) error {
- return siw.Handler.TextExample(c)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.TextExample(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// UnknownExample operation middleware
func (siw *ServerInterfaceWrapper) UnknownExample(c *fiber.Ctx) error {
- return siw.Handler.UnknownExample(c)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.UnknownExample(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// UnspecifiedContentType operation middleware
func (siw *ServerInterfaceWrapper) UnspecifiedContentType(c *fiber.Ctx) error {
- return siw.Handler.UnspecifiedContentType(c)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.UnspecifiedContentType(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// URLEncodedExample operation middleware
func (siw *ServerInterfaceWrapper) URLEncodedExample(c *fiber.Ctx) error {
- return siw.Handler.URLEncodedExample(c)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.URLEncodedExample(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// HeadersExample operation middleware
func (siw *ServerInterfaceWrapper) HeadersExample(c *fiber.Ctx) error {
var err error
+ _ = err
// Parameter object where we will unmarshal all parameters from the context
var params HeadersExampleParams
@@ -141,10 +338,14 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *fiber.Ctx) error {
headers := c.GetReqHeaders()
// ------------- Required header parameter "header1" -------------
- if value, found := headers[http.CanonicalHeaderKey("header1")]; found {
+ if valueList, found := headers[http.CanonicalHeaderKey("header1")]; found {
var Header1 string
+ n := len(valueList)
+ if n != 1 {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Too many values for ParamName header1, 1 is required, but %d found", n))
+ }
- err = runtime.BindStyledParameterWithLocation("simple", false, "header1", runtime.ParamLocationHeader, value, &Header1)
+ err = runtime.BindStyledParameterWithOptions("simple", "header1", valueList[0], &Header1, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter header1: %w", err).Error())
}
@@ -157,10 +358,14 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *fiber.Ctx) error {
}
// ------------- Optional header parameter "header2" -------------
- if value, found := headers[http.CanonicalHeaderKey("header2")]; found {
+ if valueList, found := headers[http.CanonicalHeaderKey("header2")]; found {
var Header2 int
+ n := len(valueList)
+ if n != 1 {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Too many values for ParamName header2, 1 is required, but %d found", n))
+ }
- err = runtime.BindStyledParameterWithLocation("simple", false, "header2", runtime.ParamLocationHeader, value, &Header2)
+ err = runtime.BindStyledParameterWithOptions("simple", "header2", valueList[0], &Header2, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: ""})
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter header2: %w", err).Error())
}
@@ -169,19 +374,44 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *fiber.Ctx) error {
}
- return siw.Handler.HeadersExample(c, params)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.HeadersExample(c, params)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// UnionExample operation middleware
func (siw *ServerInterfaceWrapper) UnionExample(c *fiber.Ctx) error {
- return siw.Handler.UnionExample(c)
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.UnionExample(c)
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
// FiberServerOptions provides options for the Fiber server.
type FiberServerOptions struct {
- BaseURL string
- Middlewares []MiddlewareFunc
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ HandlerMiddlewares []HandlerMiddlewareFunc
}
// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
@@ -192,19 +422,28 @@ func RegisterHandlers(router fiber.Router, si ServerInterface) {
// RegisterHandlersWithOptions creates http.Handler with additional options
func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
wrapper := ServerInterfaceWrapper{
- Handler: si,
+ Handler: si,
+ HandlerMiddlewares: options.HandlerMiddlewares,
}
for _, m := range options.Middlewares {
- router.Use(m)
+ router.Use(fiber.Handler(m))
}
router.Post(options.BaseURL+"/json", wrapper.JSONExample)
router.Post(options.BaseURL+"/multipart", wrapper.MultipartExample)
+ router.Post(options.BaseURL+"/multipart-related", wrapper.MultipartRelatedExample)
+
router.Post(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes)
+ router.Post(options.BaseURL+"/no-content-headers", wrapper.NoContentHeaders)
+
+ router.Post(options.BaseURL+"/required-json-body", wrapper.RequiredJSONBody)
+
+ router.Post(options.BaseURL+"/required-text-body", wrapper.RequiredTextBody)
+
router.Get(options.BaseURL+"/reserved-go-keyword-parameters/:type", wrapper.ReservedGoKeywordParameters)
router.Post(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses)
@@ -304,6 +543,41 @@ func (response MultipartExampledefaultResponse) VisitMultipartExampleResponse(ct
return nil
}
+type MultipartRelatedExampleRequestObject struct {
+ Body *multipart.Reader
+}
+
+type MultipartRelatedExampleResponseObject interface {
+ VisitMultipartRelatedExampleResponse(ctx *fiber.Ctx) error
+}
+
+type MultipartRelatedExample200MultipartResponse func(writer *multipart.Writer) error
+
+func (response MultipartRelatedExample200MultipartResponse) VisitMultipartRelatedExampleResponse(ctx *fiber.Ctx) error {
+ writer := multipart.NewWriter(ctx.Response().BodyWriter())
+ ctx.Response().Header.Set("Content-Type", mime.FormatMediaType("multipart/related", map[string]string{"boundary": writer.Boundary()}))
+ ctx.Status(200)
+
+ defer writer.Close()
+ return response(writer)
+}
+
+type MultipartRelatedExample400Response = BadrequestResponse
+
+func (response MultipartRelatedExample400Response) VisitMultipartRelatedExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Status(400)
+ return nil
+}
+
+type MultipartRelatedExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response MultipartRelatedExampledefaultResponse) VisitMultipartRelatedExampleResponse(ctx *fiber.Ctx) error {
+ ctx.Status(response.StatusCode)
+ return nil
+}
+
type MultipleRequestAndResponseTypesRequestObject struct {
JSONBody *MultipleRequestAndResponseTypesJSONRequestBody
FormdataBody *MultipleRequestAndResponseTypesFormdataRequestBody
@@ -386,6 +660,100 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA
return nil
}
+type NoContentHeadersRequestObject struct {
+}
+
+type NoContentHeadersResponseObject interface {
+ VisitNoContentHeadersResponse(ctx *fiber.Ctx) error
+}
+
+type NoContentHeaders204ResponseHeaders struct {
+ NullableHeader *string
+ OptionalHeader *string
+}
+
+type NoContentHeaders204Response struct {
+ Headers NoContentHeaders204ResponseHeaders
+}
+
+func (response NoContentHeaders204Response) VisitNoContentHeadersResponse(ctx *fiber.Ctx) error {
+ if response.Headers.NullableHeader != nil {
+ ctx.Response().Header.Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader))
+ }
+ if response.Headers.OptionalHeader != nil {
+ ctx.Response().Header.Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader))
+ }
+ ctx.Status(204)
+ return nil
+}
+
+type RequiredJSONBodyRequestObject struct {
+ Body *RequiredJSONBodyJSONRequestBody
+}
+
+type RequiredJSONBodyResponseObject interface {
+ VisitRequiredJSONBodyResponse(ctx *fiber.Ctx) error
+}
+
+type RequiredJSONBody200JSONResponse Example
+
+func (response RequiredJSONBody200JSONResponse) VisitRequiredJSONBodyResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "application/json")
+ ctx.Status(200)
+
+ return ctx.JSON(&response)
+}
+
+type RequiredJSONBody400Response = BadrequestResponse
+
+func (response RequiredJSONBody400Response) VisitRequiredJSONBodyResponse(ctx *fiber.Ctx) error {
+ ctx.Status(400)
+ return nil
+}
+
+type RequiredJSONBodydefaultResponse struct {
+ StatusCode int
+}
+
+func (response RequiredJSONBodydefaultResponse) VisitRequiredJSONBodyResponse(ctx *fiber.Ctx) error {
+ ctx.Status(response.StatusCode)
+ return nil
+}
+
+type RequiredTextBodyRequestObject struct {
+ Body *RequiredTextBodyTextRequestBody
+}
+
+type RequiredTextBodyResponseObject interface {
+ VisitRequiredTextBodyResponse(ctx *fiber.Ctx) error
+}
+
+type RequiredTextBody200TextResponse string
+
+func (response RequiredTextBody200TextResponse) VisitRequiredTextBodyResponse(ctx *fiber.Ctx) error {
+ ctx.Response().Header.Set("Content-Type", "text/plain")
+ ctx.Status(200)
+
+ _, err := ctx.WriteString(string(response))
+ return err
+}
+
+type RequiredTextBody400Response = BadrequestResponse
+
+func (response RequiredTextBody400Response) VisitRequiredTextBodyResponse(ctx *fiber.Ctx) error {
+ ctx.Status(400)
+ return nil
+}
+
+type RequiredTextBodydefaultResponse struct {
+ StatusCode int
+}
+
+func (response RequiredTextBodydefaultResponse) VisitRequiredTextBodyResponse(ctx *fiber.Ctx) error {
+ ctx.Status(response.StatusCode)
+ return nil
+}
+
type ReservedGoKeywordParametersRequestObject struct {
Type string `json:"type"`
}
@@ -625,8 +993,10 @@ type HeadersExampleResponseObject interface {
}
type HeadersExample200ResponseHeaders struct {
- Header1 string
- Header2 int
+ Header1 string
+ Header2 int
+ NullableHeader *string
+ OptionalHeader *string
}
type HeadersExample200JSONResponse struct {
@@ -637,6 +1007,12 @@ type HeadersExample200JSONResponse struct {
func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(ctx *fiber.Ctx) error {
ctx.Response().Header.Set("header1", fmt.Sprint(response.Headers.Header1))
ctx.Response().Header.Set("header2", fmt.Sprint(response.Headers.Header2))
+ if response.Headers.NullableHeader != nil {
+ ctx.Response().Header.Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader))
+ }
+ if response.Headers.OptionalHeader != nil {
+ ctx.Response().Header.Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader))
+ }
ctx.Response().Header.Set("Content-Type", "application/json")
ctx.Status(200)
@@ -687,9 +1063,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion
}
type UnionExample200JSONResponse struct {
- Body struct {
- union json.RawMessage
- }
+ Body UnionExample200JSONResponseBody
Headers UnionExample200ResponseHeaders
}
@@ -727,9 +1101,21 @@ type StrictServerInterface interface {
// (POST /multipart)
MultipartExample(ctx context.Context, request MultipartExampleRequestObject) (MultipartExampleResponseObject, error)
+ // (POST /multipart-related)
+ MultipartRelatedExample(ctx context.Context, request MultipartRelatedExampleRequestObject) (MultipartRelatedExampleResponseObject, error)
+
// (POST /multiple)
MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error)
+ // (POST /no-content-headers)
+ NoContentHeaders(ctx context.Context, request NoContentHeadersRequestObject) (NoContentHeadersResponseObject, error)
+
+ // (POST /required-json-body)
+ RequiredJSONBody(ctx context.Context, request RequiredJSONBodyRequestObject) (RequiredJSONBodyResponseObject, error)
+
+ // (POST /required-text-body)
+ RequiredTextBody(ctx context.Context, request RequiredTextBodyRequestObject) (RequiredTextBodyResponseObject, error)
+
// (GET /reserved-go-keyword-parameters/{type})
ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error)
@@ -755,8 +1141,7 @@ type StrictServerInterface interface {
UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error)
}
-type StrictHandlerFunc func(ctx *fiber.Ctx, args interface{}) (interface{}, error)
-
+type StrictHandlerFunc func(ctx *fiber.Ctx, args any) (any, error)
type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
@@ -774,9 +1159,12 @@ func (sh *strictHandler) JSONExample(ctx *fiber.Ctx) error {
var body JSONExampleJSONRequestBody
if err := ctx.BodyParser(&body); err != nil {
- return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ if !errors.Is(err, io.EOF) {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
return sh.ssi.JSONExample(ctx.UserContext(), request.(JSONExampleRequestObject))
@@ -826,6 +1214,39 @@ func (sh *strictHandler) MultipartExample(ctx *fiber.Ctx) error {
return nil
}
+// MultipartRelatedExample operation middleware
+func (sh *strictHandler) MultipartRelatedExample(ctx *fiber.Ctx) error {
+ var request MultipartRelatedExampleRequestObject
+
+ if _, params, err := mime.ParseMediaType(string(ctx.Request().Header.ContentType())); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if boundary := params["boundary"]; boundary == "" {
+ return fiber.NewError(fiber.StatusBadRequest, http.ErrMissingBoundary.Error())
+ } else {
+ request.Body = multipart.NewReader(bytes.NewReader(ctx.Request().Body()), boundary)
+ }
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.MultipartRelatedExample(ctx.UserContext(), request.(MultipartRelatedExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "MultipartRelatedExample")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(MultipartRelatedExampleResponseObject); ok {
+ if err := validResponse.VisitMultipartRelatedExampleResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
// MultipleRequestAndResponseTypes operation middleware
func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *fiber.Ctx) error {
var request MultipleRequestAndResponseTypesRequestObject
@@ -834,9 +1255,12 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *fiber.Ctx) error {
var body MultipleRequestAndResponseTypesJSONRequestBody
if err := ctx.BodyParser(&body); err != nil {
- return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ if !errors.Is(err, io.EOF) {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else {
+ request.JSONBody = &body
}
- request.JSONBody = &body
}
if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "application/x-www-form-urlencoded") {
var body MultipleRequestAndResponseTypesFormdataRequestBody
@@ -853,8 +1277,10 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *fiber.Ctx) error {
}
if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "text/plain") {
data := ctx.Request().Body()
- body := MultipleRequestAndResponseTypesTextRequestBody(data)
- request.TextBody = &body
+ if len(data) > 0 {
+ body := MultipleRequestAndResponseTypesTextRequestBody(data)
+ request.TextBody = &body
+ }
}
handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
@@ -878,6 +1304,91 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *fiber.Ctx) error {
return nil
}
+// NoContentHeaders operation middleware
+func (sh *strictHandler) NoContentHeaders(ctx *fiber.Ctx) error {
+ var request NoContentHeadersRequestObject
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.NoContentHeaders(ctx.UserContext(), request.(NoContentHeadersRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "NoContentHeaders")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(NoContentHeadersResponseObject); ok {
+ if err := validResponse.VisitNoContentHeadersResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// RequiredJSONBody operation middleware
+func (sh *strictHandler) RequiredJSONBody(ctx *fiber.Ctx) error {
+ var request RequiredJSONBodyRequestObject
+
+ var body RequiredJSONBodyJSONRequestBody
+ if err := ctx.BodyParser(&body); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ request.Body = &body
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.RequiredJSONBody(ctx.UserContext(), request.(RequiredJSONBodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "RequiredJSONBody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(RequiredJSONBodyResponseObject); ok {
+ if err := validResponse.VisitRequiredJSONBodyResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
+// RequiredTextBody operation middleware
+func (sh *strictHandler) RequiredTextBody(ctx *fiber.Ctx) error {
+ var request RequiredTextBodyRequestObject
+
+ data := ctx.Request().Body()
+ body := RequiredTextBodyTextRequestBody(data)
+ request.Body = &body
+
+ handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
+ return sh.ssi.RequiredTextBody(ctx.UserContext(), request.(RequiredTextBodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "RequiredTextBody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if validResponse, ok := response.(RequiredTextBodyResponseObject); ok {
+ if err := validResponse.VisitRequiredTextBodyResponse(ctx); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+}
+
// ReservedGoKeywordParameters operation middleware
func (sh *strictHandler) ReservedGoKeywordParameters(ctx *fiber.Ctx, pType string) error {
var request ReservedGoKeywordParametersRequestObject
@@ -911,9 +1422,12 @@ func (sh *strictHandler) ReusableResponses(ctx *fiber.Ctx) error {
var body ReusableResponsesJSONRequestBody
if err := ctx.BodyParser(&body); err != nil {
- return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ if !errors.Is(err, io.EOF) {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
return sh.ssi.ReusableResponses(ctx.UserContext(), request.(ReusableResponsesRequestObject))
@@ -941,8 +1455,10 @@ func (sh *strictHandler) TextExample(ctx *fiber.Ctx) error {
var request TextExampleRequestObject
data := ctx.Request().Body()
- body := TextExampleTextRequestBody(data)
- request.Body = &body
+ if len(data) > 0 {
+ body := TextExampleTextRequestBody(data)
+ request.Body = &body
+ }
handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
return sh.ssi.TextExample(ctx.UserContext(), request.(TextExampleRequestObject))
@@ -1060,9 +1576,12 @@ func (sh *strictHandler) HeadersExample(ctx *fiber.Ctx, params HeadersExamplePar
var body HeadersExampleJSONRequestBody
if err := ctx.BodyParser(&body); err != nil {
- return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ if !errors.Is(err, io.EOF) {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
return sh.ssi.HeadersExample(ctx.UserContext(), request.(HeadersExampleRequestObject))
@@ -1091,9 +1610,12 @@ func (sh *strictHandler) UnionExample(ctx *fiber.Ctx) error {
var body UnionExampleJSONRequestBody
if err := ctx.BodyParser(&body); err != nil {
- return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ if !errors.Is(err, io.EOF) {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx *fiber.Ctx, request interface{}) (interface{}, error) {
return sh.ssi.UnionExample(ctx.UserContext(), request.(UnionExampleRequestObject))
@@ -1116,43 +1638,49 @@ func (sh *strictHandler) UnionExample(ctx *fiber.Ctx) error {
return nil
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/+xYS2/jNhD+KwTb01aynGxOunWDxbbdtimc5FTkQIsjm7sSyQ5HVgzD/72gKL9ixbW3",
- "fhRBb3oMvxl+8+BwZjwzpTUaNDmezjiCs0Y7aF6GQiL8VYEj/ybBZagsKaN5yj8IOWj/zSOOUDkxLGCx",
- "3MtnRhPoZqmwtlCZ8EuTL86vn3GXjaEU/ul7hJyn/LtkZUoS/roEnkVpC+Dz+Tx6YcHdZx7xMQgJ2Fgb",
- "Hq82sWlqgafcESo94h4kiF13iilNMAL02rxoa4QXWNiRzrhFYwFJBY4moqigW1P7xQy/QEZhB0rnZpvL",
- "W6NJKO2YVHkOCJpYSx7zGI65ylqDBJINp8xryIg5wAkgjzgp8obx+/XvrDXY8YhPAF1QdNXr9/reX8aC",
- "FlbxlL9vPkXcCho3G1o6yJouv/9yf/c7U46JikwpSGWiKKasFOjGogDJlCbjTawycj3eaMLG8T/LdvXH",
- "lkofNU0AfTByeoqAaeJyLZyv+/0zxeU84jdBWRfG0qhkLcEamFxURQfnj/qrNrVmgGiw3VlSVgUpK5DW",
- "fbXJ9m8LkX0oX+IlucEyloLEiVg/lqaLEt/Wgs4cuR+b2rGxqRkZJkEUrFY0ZouFL5JbaSaYU3pUAFsY",
- "FXV6soC25P6o5aDdy4PHOHkuRRsoz3Fd13HjvAoL0JmRIL8NVpViBInVo83lHlsQT/lwSj5st4vrkYIo",
- "4gTPlNhCKL375DhTOfmf6aMldkhXhOZElPHIxF9hWhuUsRUoSiBAl8y89rkHHkFHKv+xlGSZ0GwITIsS",
- "JBM5AbJPhrWQbitlB63eT+ZzEFlBNcft8iX9c8Y9Jc0RzCPuFfA0sBLyWqF3OmEF0Q7anv4xPv+VAxZs",
- "hkYv3lDVXQYXJWpJHULufEns8lwHf0HTYE3iMg3D7ojban3PcQZ5T75+7j/A815H/hFL37lz+1DCqvDx",
- "dc7aVfvQ9o2VdA8WJ0qCSUp7cyDyxUh1FjKVK5Bxu4s42PZaSbg1OkOgzRbIXye0IbYE87ccGgMLDETM",
- "GVYDKytHzArnmKKmihQq3JQkbBWPx5Vlt0HTw6qc7vLquxP59N2lPHrTvzp8yfsTx81GK/NKPg5+/Rhk",
- "Dr0vHq1nOrDjO57eC6Wzv6TEawOV7hT+KQiszvQM1MR3RFoyBKpQg2QTJRZDgK3cbAFWbu3qhYIZq25o",
- "Mdw5pCGKdmJd82jXAOjpDY8nTjk2O1ecVlrtGlM9+t+s7aFfng3K6P/oEEoUBKgFqQn8cJwb5DaK0XCX",
- "N5n2wsvRnhqe3l5UzSMe5qahBFVY+DpBZNMkCfPWnqvFaATYUyYRVnkW/g4AAP//Pk3lbjwXAAA=",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "7Fnbcts2E36VHfz/RZuSpuL4SndNJpO2aZOObF91fAERKwkJCSDAUrJGo5k+RJ+wT9IBAepI21KqgyfT",
+ "O4ncE/fbXX5LzFiuS6MVKnKsO2MWndHKYf2nz4XFLxU68v8EutxKQ1Ir1mWvuejFe/OEWawc7xfYqHv5",
+ "XCtCVatyYwqZc6+afXJef8ZcPsKS+1//tzhgXfa/bBlKFu66DO95aQpk8/k82Yjg43uWsBFygbaONvx8",
+ "GZ7iSyUtCtYlW2Gy4oumBlmXObJSDZk3GtQud1KTinCI1kfjVWOQXqCJsztjxmqDlmTI4ZgXFbZ7jld0",
+ "/xPmFJ5QqoHezvUbrYhL5UDIwQAtKoKYXPA2HLjKGG0JBfSn4D3kBA7tGC1LGEnygbHr1esQA3YsYWO0",
+ "Ljh6edG56Hg8tUHFjWRd9qq+lDDDaVQ/0AJAo9vq4pfrjx9AOuAV6ZKTzHlRTKHk1o14gQKkIu1DrHJy",
+ "F6z2ZOvC+FlE7bcxlQmLxfdai+kxCqqu25Vyv+x0TlS384RdBWdtNhZBZSsNWJsZ8Kpoyfmt+qz0RAFa",
+ "q218sqysCpKGW1rFaj3bvzUiu6R8YS8baFumghM/UtYP5enciU8tFpz8OHkSgF6Q3A+HFfNHReHf+Dkr",
+ "BnEet86p65GeOBjpCZAGgbyAiaQRNIobA1Yq4OCkGhYITVBJK5gFxtfij0r04rPceBtHn2fJmpX7dDKZ",
+ "pHUDVbZAlWvxdRAmTJZ8iJlRw3V1b5sT67L+lHzJbr/gDtTICSO8p8wUXG4kZtPliUb6f5k+WGOHdlU6",
+ "jRClK4SuvXE/LGThu8vO1ffQGA4NrGs5XgBXAlRVFJ6WLmWiefj7z78A79Hm0qEDGnGCSjmkhQC3CLqU",
+ "5EnVwOoSaLQ0s9X7H/SbENNPMfytOrxqexKIWutEtok65mIdiOZmw1G3a6HJQKv6dscEBBrqm/qeSPtx",
+ "QrUjEAcceClP9RrdBJyGUjo/J8NNN9JVIYAXEz51YUJvc75eVPfcrx6NRyd+yQbT/7aJ4AJa39vngfYG",
+ "7+lJaPcYPfvCd+qptj9E9VYm0qFOP+N0oq1IDbe8RELrspmPc+5tDbHF5O8LSci5gj6C4iUK4ANCC+80",
+ "RJOuBZ/g951+H0SWpuqVb/Gn+8eM+eTVayBLmHfAuiF/yR7r9t1xoWqyGT5GpGuuHir4KNKkzuLAeUrY",
+ "hnFL/oKn3orEeZbWx2tz6/PMKYraI/nw6uNHwi7rzgGp33OfAlW4+HDOotYuaftKJrlDFsdSoM5Kc7Wn",
+ "5bMl1RnM5UCiWHDMENtDI+GNVrlFWl8B/ctQaYKFMehPa0oYMlC/HycIZeUIDHcOJNVTpJDha53Y5oy3",
+ "y8giDbxZjtPHUH1xJExfnAvRq87L/VVeHblu1la5B/qx9+vbILPvN8uD7Yx7bryH83umdvY73tM7YtzC",
+ "lu/0HOXYMyIlwCJVVqGAseTNh+it3owGlrC2caG4Xy3YUHMAsQ8hSh61dckePYS4+4Y/kZ/vaCc58QJ+",
+ "qq6plHzs4ObW34bI6DffVFKrZ3oswwtCqzjJMf5wmO9521a0wo+Duu830Et29HD3/I4vj11184SFk8Yw",
+ "MCtb+KlGZLpZFk4oL9yED4doL6TOuJE+S/8EAAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -1160,7 +1688,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -1178,12 +1706,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -1209,3 +1737,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/strict-server/fiber/server.go b/internal/test/strict-server/fiber/server.go
index 669d4da4f4..1f4c633fae 100644
--- a/internal/test/strict-server/fiber/server.go
+++ b/internal/test/strict-server/fiber/server.go
@@ -1,5 +1,5 @@
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
package api
@@ -41,6 +41,30 @@ func (s StrictServer) MultipartExample(ctx context.Context, request MultipartExa
}), nil
}
+func (s StrictServer) MultipartRelatedExample(ctx context.Context, request MultipartRelatedExampleRequestObject) (MultipartRelatedExampleResponseObject, error) {
+ return MultipartRelatedExample200MultipartResponse(func(writer *multipart.Writer) error {
+ for {
+ part, err := request.Body.NextPart()
+ if err == io.EOF {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ w, err := writer.CreatePart(part.Header)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(w, part)
+ if err != nil {
+ return err
+ }
+ if err = part.Close(); err != nil {
+ return err
+ }
+ }
+ }), nil
+}
+
func (s StrictServer) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error) {
switch {
case request.Body != nil:
@@ -98,10 +122,22 @@ func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExample
return HeadersExample200JSONResponse{Body: *request.Body, Headers: HeadersExample200ResponseHeaders{Header1: request.Params.Header1, Header2: *request.Params.Header2}}, nil
}
+func (s StrictServer) NoContentHeaders(ctx context.Context, request NoContentHeadersRequestObject) (NoContentHeadersResponseObject, error) {
+ return NoContentHeaders204Response{}, nil
+}
+
func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) {
return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil
}
+func (s StrictServer) RequiredJSONBody(ctx context.Context, request RequiredJSONBodyRequestObject) (RequiredJSONBodyResponseObject, error) {
+ return RequiredJSONBody200JSONResponse(*request.Body), nil
+}
+
+func (s StrictServer) RequiredTextBody(ctx context.Context, request RequiredTextBodyRequestObject) (RequiredTextBodyResponseObject, error) {
+ return RequiredTextBody200TextResponse(*request.Body), nil
+}
+
func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) {
return ReservedGoKeywordParameters200TextResponse(""), nil
}
diff --git a/internal/test/strict-server/fiber/types.cfg.yaml b/internal/test/strict-server/fiber/types.cfg.yaml
index 4ea1d8aa5b..2ed9740ea7 100644
--- a/internal/test/strict-server/fiber/types.cfg.yaml
+++ b/internal/test/strict-server/fiber/types.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
models: true
diff --git a/internal/test/strict-server/fiber/types.gen.go b/internal/test/strict-server/fiber/types.gen.go
index 6a0de0c970..08ae8548e1 100644
--- a/internal/test/strict-server/fiber/types.gen.go
+++ b/internal/test/strict-server/fiber/types.gen.go
@@ -1,8 +1,14 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
+import (
+ "encoding/json"
+
+ "github.com/oapi-codegen/runtime"
+)
+
// Example defines model for example.
type Example struct {
Value *string `json:"value,omitempty"`
@@ -14,6 +20,9 @@ type Reusableresponse = Example
// MultipleRequestAndResponseTypesTextBody defines parameters for MultipleRequestAndResponseTypes.
type MultipleRequestAndResponseTypesTextBody = string
+// RequiredTextBodyTextBody defines parameters for RequiredTextBody.
+type RequiredTextBodyTextBody = string
+
// TextExampleTextBody defines parameters for TextExample.
type TextExampleTextBody = string
@@ -23,12 +32,23 @@ type HeadersExampleParams struct {
Header2 *int `json:"header2,omitempty"`
}
+// UnionExample200JSONResponseBody0 defines parameters for UnionExample.
+type UnionExample200JSONResponseBody0 = string
+
+// UnionExample200JSONResponseBody defines parameters for UnionExample.
+type UnionExample200JSONResponseBody struct {
+ union json.RawMessage
+}
+
// JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType.
type JSONExampleJSONRequestBody = Example
// MultipartExampleMultipartRequestBody defines body for MultipartExample for multipart/form-data ContentType.
type MultipartExampleMultipartRequestBody = Example
+// MultipartRelatedExampleMultipartRequestBody defines body for MultipartRelatedExample for multipart/related ContentType.
+type MultipartRelatedExampleMultipartRequestBody = Example
+
// MultipleRequestAndResponseTypesJSONRequestBody defines body for MultipleRequestAndResponseTypes for application/json ContentType.
type MultipleRequestAndResponseTypesJSONRequestBody = Example
@@ -41,6 +61,12 @@ type MultipleRequestAndResponseTypesMultipartRequestBody = Example
// MultipleRequestAndResponseTypesTextRequestBody defines body for MultipleRequestAndResponseTypes for text/plain ContentType.
type MultipleRequestAndResponseTypesTextRequestBody = MultipleRequestAndResponseTypesTextBody
+// RequiredJSONBodyJSONRequestBody defines body for RequiredJSONBody for application/json ContentType.
+type RequiredJSONBodyJSONRequestBody = Example
+
+// RequiredTextBodyTextRequestBody defines body for RequiredTextBody for text/plain ContentType.
+type RequiredTextBodyTextRequestBody = RequiredTextBodyTextBody
+
// ReusableResponsesJSONRequestBody defines body for ReusableResponses for application/json ContentType.
type ReusableResponsesJSONRequestBody = Example
@@ -55,3 +81,65 @@ type HeadersExampleJSONRequestBody = Example
// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType.
type UnionExampleJSONRequestBody = Example
+
+// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0
+func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) {
+ var body UnionExample200JSONResponseBody0
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example
+func (t UnionExample200JSONResponseBody) AsExample() (Example, error) {
+ var body Example
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example
+func (t *UnionExample200JSONResponseBody) FromExample(v Example) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example
+func (t *UnionExample200JSONResponseBody) MergeExample(v Example) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
diff --git a/internal/test/strict-server/gin/server.cfg.yaml b/internal/test/strict-server/gin/server.cfg.yaml
index 66ffd5795f..a79bf0e85d 100644
--- a/internal/test/strict-server/gin/server.cfg.yaml
+++ b/internal/test/strict-server/gin/server.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
gin-server: true
diff --git a/internal/test/strict-server/gin/server.gen.go b/internal/test/strict-server/gin/server.gen.go
index 9c54408223..b5294a5b54 100644
--- a/internal/test/strict-server/gin/server.gen.go
+++ b/internal/test/strict-server/gin/server.gen.go
@@ -1,16 +1,18 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
+ "errors"
"fmt"
"io"
+ "mime"
"mime/multipart"
"net/http"
"net/url"
@@ -20,7 +22,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/gin-gonic/gin"
"github.com/oapi-codegen/runtime"
- strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin"
)
// ServerInterface represents all server handlers.
@@ -32,9 +33,21 @@ type ServerInterface interface {
// (POST /multipart)
MultipartExample(c *gin.Context)
+ // (POST /multipart-related)
+ MultipartRelatedExample(c *gin.Context)
+
// (POST /multiple)
MultipleRequestAndResponseTypes(c *gin.Context)
+ // (POST /no-content-headers)
+ NoContentHeaders(c *gin.Context)
+
+ // (POST /required-json-body)
+ RequiredJSONBody(c *gin.Context)
+
+ // (POST /required-text-body)
+ RequiredTextBody(c *gin.Context)
+
// (GET /reserved-go-keyword-parameters/{type})
ReservedGoKeywordParameters(c *gin.Context, pType string)
@@ -95,6 +108,19 @@ func (siw *ServerInterfaceWrapper) MultipartExample(c *gin.Context) {
siw.Handler.MultipartExample(c)
}
+// MultipartRelatedExample operation middleware
+func (siw *ServerInterfaceWrapper) MultipartRelatedExample(c *gin.Context) {
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.MultipartRelatedExample(c)
+}
+
// MultipleRequestAndResponseTypes operation middleware
func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(c *gin.Context) {
@@ -108,15 +134,55 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(c *gin.Contex
siw.Handler.MultipleRequestAndResponseTypes(c)
}
+// NoContentHeaders operation middleware
+func (siw *ServerInterfaceWrapper) NoContentHeaders(c *gin.Context) {
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.NoContentHeaders(c)
+}
+
+// RequiredJSONBody operation middleware
+func (siw *ServerInterfaceWrapper) RequiredJSONBody(c *gin.Context) {
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.RequiredJSONBody(c)
+}
+
+// RequiredTextBody operation middleware
+func (siw *ServerInterfaceWrapper) RequiredTextBody(c *gin.Context) {
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ middleware(c)
+ if c.IsAborted() {
+ return
+ }
+ }
+
+ siw.Handler.RequiredTextBody(c)
+}
+
// ReservedGoKeywordParameters operation middleware
func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(c *gin.Context) {
var err error
+ _ = err
// ------------- Path parameter "type" -------------
var pType string
- err = runtime.BindStyledParameter("simple", false, "type", c.Param("type"), &pType)
+ err = runtime.BindStyledParameterWithOptions("simple", "type", c.Param("type"), &pType, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter type: %w", err), http.StatusBadRequest)
return
@@ -201,6 +267,7 @@ func (siw *ServerInterfaceWrapper) URLEncodedExample(c *gin.Context) {
func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) {
var err error
+ _ = err
// Parameter object where we will unmarshal all parameters from the context
var params HeadersExampleParams
@@ -216,7 +283,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) {
return
}
- err = runtime.BindStyledParameterWithLocation("simple", false, "header1", runtime.ParamLocationHeader, valueList[0], &Header1)
+ err = runtime.BindStyledParameterWithOptions("simple", "header1", valueList[0], &Header1, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter header1: %w", err), http.StatusBadRequest)
return
@@ -238,7 +305,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) {
return
}
- err = runtime.BindStyledParameterWithLocation("simple", false, "header2", runtime.ParamLocationHeader, valueList[0], &Header2)
+ err = runtime.BindStyledParameterWithOptions("simple", "header2", valueList[0], &Header2, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: ""})
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter header2: %w", err), http.StatusBadRequest)
return
@@ -300,7 +367,11 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options
router.POST(options.BaseURL+"/json", wrapper.JSONExample)
router.POST(options.BaseURL+"/multipart", wrapper.MultipartExample)
+ router.POST(options.BaseURL+"/multipart-related", wrapper.MultipartRelatedExample)
router.POST(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes)
+ router.POST(options.BaseURL+"/no-content-headers", wrapper.NoContentHeaders)
+ router.POST(options.BaseURL+"/required-json-body", wrapper.RequiredJSONBody)
+ router.POST(options.BaseURL+"/required-text-body", wrapper.RequiredTextBody)
router.GET(options.BaseURL+"/reserved-go-keyword-parameters/:type", wrapper.ReservedGoKeywordParameters)
router.POST(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses)
router.POST(options.BaseURL+"/text", wrapper.TextExample)
@@ -335,10 +406,15 @@ type JSONExampleResponseObject interface {
type JSONExample200JSONResponse Example
func (response JSONExample200JSONResponse) VisitJSONExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type JSONExample400Response = BadrequestResponse
@@ -369,6 +445,7 @@ type MultipartExample200MultipartResponse func(writer *multipart.Writer) error
func (response MultipartExample200MultipartResponse) VisitMultipartExampleResponse(w http.ResponseWriter) error {
writer := multipart.NewWriter(w)
+
w.Header().Set("Content-Type", writer.FormDataContentType())
w.WriteHeader(200)
@@ -392,6 +469,42 @@ func (response MultipartExampledefaultResponse) VisitMultipartExampleResponse(w
return nil
}
+type MultipartRelatedExampleRequestObject struct {
+ Body *multipart.Reader
+}
+
+type MultipartRelatedExampleResponseObject interface {
+ VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error
+}
+
+type MultipartRelatedExample200MultipartResponse func(writer *multipart.Writer) error
+
+func (response MultipartRelatedExample200MultipartResponse) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ writer := multipart.NewWriter(w)
+
+ w.Header().Set("Content-Type", mime.FormatMediaType("multipart/related", map[string]string{"boundary": writer.Boundary()}))
+ w.WriteHeader(200)
+
+ defer writer.Close()
+ return response(writer)
+}
+
+type MultipartRelatedExample400Response = BadrequestResponse
+
+func (response MultipartRelatedExample400Response) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type MultipartRelatedExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response MultipartRelatedExampledefaultResponse) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
type MultipleRequestAndResponseTypesRequestObject struct {
JSONBody *MultipleRequestAndResponseTypesJSONRequestBody
FormdataBody *MultipleRequestAndResponseTypesFormdataRequestBody
@@ -407,24 +520,29 @@ type MultipleRequestAndResponseTypesResponseObject interface {
type MultipleRequestAndResponseTypes200JSONResponse Example
func (response MultipleRequestAndResponseTypes200JSONResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type MultipleRequestAndResponseTypes200FormdataResponse Example
func (response MultipleRequestAndResponseTypes200FormdataResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
- w.WriteHeader(200)
- if form, err := runtime.MarshalForm(response, nil); err != nil {
- return err
- } else {
- _, err := w.Write([]byte(form.Encode()))
+ form, err := runtime.MarshalForm(response, nil)
+ if err != nil {
return err
}
+ w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
+ w.WriteHeader(200)
+ _, err = w.Write([]byte(form.Encode()))
+ return err
}
type MultipleRequestAndResponseTypes200ImagepngResponse struct {
@@ -433,6 +551,7 @@ type MultipleRequestAndResponseTypes200ImagepngResponse struct {
}
func (response MultipleRequestAndResponseTypes200ImagepngResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "image/png")
if response.ContentLength != 0 {
w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
@@ -450,6 +569,7 @@ type MultipleRequestAndResponseTypes200MultipartResponse func(writer *multipart.
func (response MultipleRequestAndResponseTypes200MultipartResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
writer := multipart.NewWriter(w)
+
w.Header().Set("Content-Type", writer.FormDataContentType())
w.WriteHeader(200)
@@ -460,6 +580,7 @@ func (response MultipleRequestAndResponseTypes200MultipartResponse) VisitMultipl
type MultipleRequestAndResponseTypes200TextResponse string
func (response MultipleRequestAndResponseTypes200TextResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(200)
@@ -474,6 +595,106 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA
return nil
}
+type NoContentHeadersRequestObject struct {
+}
+
+type NoContentHeadersResponseObject interface {
+ VisitNoContentHeadersResponse(w http.ResponseWriter) error
+}
+
+type NoContentHeaders204ResponseHeaders struct {
+ NullableHeader *string
+ OptionalHeader *string
+}
+
+type NoContentHeaders204Response struct {
+ Headers NoContentHeaders204ResponseHeaders
+}
+
+func (response NoContentHeaders204Response) VisitNoContentHeadersResponse(w http.ResponseWriter) error {
+ if response.Headers.NullableHeader != nil {
+ w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader))
+ }
+ if response.Headers.OptionalHeader != nil {
+ w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader))
+ }
+ w.WriteHeader(204)
+ return nil
+}
+
+type RequiredJSONBodyRequestObject struct {
+ Body *RequiredJSONBodyJSONRequestBody
+}
+
+type RequiredJSONBodyResponseObject interface {
+ VisitRequiredJSONBodyResponse(w http.ResponseWriter) error
+}
+
+type RequiredJSONBody200JSONResponse Example
+
+func (response RequiredJSONBody200JSONResponse) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type RequiredJSONBody400Response = BadrequestResponse
+
+func (response RequiredJSONBody400Response) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type RequiredJSONBodydefaultResponse struct {
+ StatusCode int
+}
+
+func (response RequiredJSONBodydefaultResponse) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type RequiredTextBodyRequestObject struct {
+ Body *RequiredTextBodyTextRequestBody
+}
+
+type RequiredTextBodyResponseObject interface {
+ VisitRequiredTextBodyResponse(w http.ResponseWriter) error
+}
+
+type RequiredTextBody200TextResponse string
+
+func (response RequiredTextBody200TextResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "text/plain")
+ w.WriteHeader(200)
+
+ _, err := w.Write([]byte(response))
+ return err
+}
+
+type RequiredTextBody400Response = BadrequestResponse
+
+func (response RequiredTextBody400Response) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type RequiredTextBodydefaultResponse struct {
+ StatusCode int
+}
+
+func (response RequiredTextBodydefaultResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
type ReservedGoKeywordParametersRequestObject struct {
Type string `json:"type"`
}
@@ -485,6 +706,7 @@ type ReservedGoKeywordParametersResponseObject interface {
type ReservedGoKeywordParameters200TextResponse string
func (response ReservedGoKeywordParameters200TextResponse) VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(200)
@@ -503,12 +725,17 @@ type ReusableResponsesResponseObject interface {
type ReusableResponses200JSONResponse struct{ ReusableresponseJSONResponse }
func (response ReusableResponses200JSONResponse) VisitReusableResponsesResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type ReusableResponses400Response = BadrequestResponse
@@ -538,6 +765,7 @@ type TextExampleResponseObject interface {
type TextExample200TextResponse string
func (response TextExample200TextResponse) VisitTextExampleResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(200)
@@ -575,6 +803,7 @@ type UnknownExample200Videomp4Response struct {
}
func (response UnknownExample200Videomp4Response) VisitUnknownExampleResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "video/mp4")
if response.ContentLength != 0 {
w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
@@ -620,6 +849,7 @@ type UnspecifiedContentType200VideoResponse struct {
}
func (response UnspecifiedContentType200VideoResponse) VisitUnspecifiedContentTypeResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", response.ContentType)
if response.ContentLength != 0 {
w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
@@ -676,15 +906,15 @@ type URLEncodedExampleResponseObject interface {
type URLEncodedExample200FormdataResponse Example
func (response URLEncodedExample200FormdataResponse) VisitURLEncodedExampleResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
- w.WriteHeader(200)
- if form, err := runtime.MarshalForm(response, nil); err != nil {
- return err
- } else {
- _, err := w.Write([]byte(form.Encode()))
+ form, err := runtime.MarshalForm(response, nil)
+ if err != nil {
return err
}
+ w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
+ w.WriteHeader(200)
+ _, err = w.Write([]byte(form.Encode()))
+ return err
}
type URLEncodedExample400Response = BadrequestResponse
@@ -713,8 +943,10 @@ type HeadersExampleResponseObject interface {
}
type HeadersExample200ResponseHeaders struct {
- Header1 string
- Header2 int
+ Header1 string
+ Header2 int
+ NullableHeader *string
+ OptionalHeader *string
}
type HeadersExample200JSONResponse struct {
@@ -723,12 +955,23 @@ type HeadersExample200JSONResponse struct {
}
func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
+ if response.Headers.NullableHeader != nil {
+ w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader))
+ }
+ if response.Headers.OptionalHeader != nil {
+ w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader))
+ }
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type HeadersExample400Response = BadrequestResponse
@@ -766,28 +1009,36 @@ type UnionExample200ApplicationAlternativePlusJSONResponse struct {
}
func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/alternative+json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type UnionExample200JSONResponse struct {
- Body struct {
- union json.RawMessage
- }
+ Body UnionExample200JSONResponseBody
Headers UnionExample200ResponseHeaders
}
func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body.union); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body.union)
+ _, err := buf.WriteTo(w)
+ return err
}
type UnionExample400Response = BadrequestResponse
@@ -815,9 +1066,21 @@ type StrictServerInterface interface {
// (POST /multipart)
MultipartExample(ctx context.Context, request MultipartExampleRequestObject) (MultipartExampleResponseObject, error)
+ // (POST /multipart-related)
+ MultipartRelatedExample(ctx context.Context, request MultipartRelatedExampleRequestObject) (MultipartRelatedExampleResponseObject, error)
+
// (POST /multiple)
MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error)
+ // (POST /no-content-headers)
+ NoContentHeaders(ctx context.Context, request NoContentHeadersRequestObject) (NoContentHeadersResponseObject, error)
+
+ // (POST /required-json-body)
+ RequiredJSONBody(ctx context.Context, request RequiredJSONBodyRequestObject) (RequiredJSONBodyResponseObject, error)
+
+ // (POST /required-text-body)
+ RequiredTextBody(ctx context.Context, request RequiredTextBodyRequestObject) (RequiredTextBodyResponseObject, error)
+
// (GET /reserved-go-keyword-parameters/{type})
ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error)
@@ -843,16 +1106,61 @@ type StrictServerInterface interface {
UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error)
}
-type StrictHandlerFunc = strictgin.StrictGinHandlerFunc
-type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc
+type StrictHandlerFunc func(ctx *gin.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictGinServerOptions struct {
+ // RequestErrorHandlerFunc is called when a request cannot be parsed or
+ // decoded. It is invoked for JSON bind failures, form parse/bind errors,
+ // multipart reader errors, media type parse errors, missing multipart
+ // boundaries, and request body read errors. The default returns 400.
+ RequestErrorHandlerFunc func(ctx *gin.Context, err error)
+ // HandlerErrorFunc is called when the application handler (or any
+ // middleware wrapping it) returns a non-nil error. The default returns 500.
+ HandlerErrorFunc func(ctx *gin.Context, err error)
+ // ResponseErrorHandlerFunc is called when the response object fails to
+ // serialize (Visit*Response returns an error) or when the handler returns
+ // an unexpected response type. The default returns 500.
+ ResponseErrorHandlerFunc func(ctx *gin.Context, err error)
+}
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
- return &strictHandler{ssi: ssi, middlewares: middlewares}
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictGinServerOptions{
+ RequestErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ },
+ HandlerErrorFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ ResponseErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictGinServerOptions) ServerInterface {
+ if options.RequestErrorHandlerFunc == nil {
+ options.RequestErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.HandlerErrorFunc == nil {
+ options.HandlerErrorFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.ResponseErrorHandlerFunc == nil {
+ options.ResponseErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
}
type strictHandler struct {
ssi StrictServerInterface
middlewares []StrictMiddlewareFunc
+ options StrictGinServerOptions
}
// JSONExample operation middleware
@@ -860,12 +1168,14 @@ func (sh *strictHandler) JSONExample(ctx *gin.Context) {
var request JSONExampleRequestObject
var body JSONExampleJSONRequestBody
- if err := ctx.ShouldBind(&body); err != nil {
- ctx.Status(http.StatusBadRequest)
- ctx.Error(err)
- return
+ if err := ctx.ShouldBindJSON(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
return sh.ssi.JSONExample(ctx, request.(JSONExampleRequestObject))
@@ -877,14 +1187,13 @@ func (sh *strictHandler) JSONExample(ctx *gin.Context) {
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(JSONExampleResponseObject); ok {
if err := validResponse.VisitJSONExampleResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
@@ -892,11 +1201,11 @@ func (sh *strictHandler) JSONExample(ctx *gin.Context) {
func (sh *strictHandler) MultipartExample(ctx *gin.Context) {
var request MultipartExampleRequestObject
- if reader, err := ctx.Request.MultipartReader(); err == nil {
- request.Body = reader
- } else {
- ctx.Error(err)
+ if reader, err := ctx.Request.MultipartReader(); err != nil {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
+ } else {
+ request.Body = reader
}
handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
@@ -909,14 +1218,47 @@ func (sh *strictHandler) MultipartExample(ctx *gin.Context) {
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(MultipartExampleResponseObject); ok {
if err := validResponse.VisitMultipartExampleResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// MultipartRelatedExample operation middleware
+func (sh *strictHandler) MultipartRelatedExample(ctx *gin.Context) {
+ var request MultipartRelatedExampleRequestObject
+
+ if _, params, err := mime.ParseMediaType(ctx.Request.Header.Get("Content-Type")); err != nil {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
+ } else if boundary := params["boundary"]; boundary == "" {
+ sh.options.RequestErrorHandlerFunc(ctx, http.ErrMissingBoundary)
+ return
+ } else {
+ request.Body = multipart.NewReader(ctx.Request.Body, boundary)
+ }
+
+ handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.MultipartRelatedExample(ctx, request.(MultipartRelatedExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "MultipartRelatedExample")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ sh.options.HandlerErrorFunc(ctx, err)
+ } else if validResponse, ok := response.(MultipartRelatedExampleResponseObject); ok {
+ if err := validResponse.VisitMultipartRelatedExampleResponse(ctx.Writer); err != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
@@ -927,21 +1269,23 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *gin.Context) {
if strings.HasPrefix(ctx.GetHeader("Content-Type"), "application/json") {
var body MultipleRequestAndResponseTypesJSONRequestBody
- if err := ctx.ShouldBind(&body); err != nil {
- ctx.Status(http.StatusBadRequest)
- ctx.Error(err)
- return
+ if err := ctx.ShouldBindJSON(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
+ }
+ } else {
+ request.JSONBody = &body
}
- request.JSONBody = &body
}
if strings.HasPrefix(ctx.GetHeader("Content-Type"), "application/x-www-form-urlencoded") {
if err := ctx.Request.ParseForm(); err != nil {
- ctx.Error(err)
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
}
var body MultipleRequestAndResponseTypesFormdataRequestBody
if err := runtime.BindForm(&body, ctx.Request.Form, nil, nil); err != nil {
- ctx.Error(err)
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
}
request.FormdataBody = &body
@@ -950,21 +1294,23 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *gin.Context) {
request.Body = ctx.Request.Body
}
if strings.HasPrefix(ctx.GetHeader("Content-Type"), "multipart/form-data") {
- if reader, err := ctx.Request.MultipartReader(); err == nil {
- request.MultipartBody = reader
- } else {
- ctx.Error(err)
+ if reader, err := ctx.Request.MultipartReader(); err != nil {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
+ } else {
+ request.MultipartBody = reader
}
}
if strings.HasPrefix(ctx.GetHeader("Content-Type"), "text/plain") {
data, err := io.ReadAll(ctx.Request.Body)
if err != nil {
- ctx.Error(err)
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
}
- body := MultipleRequestAndResponseTypesTextRequestBody(data)
- request.TextBody = &body
+ if len(data) > 0 {
+ body := MultipleRequestAndResponseTypesTextRequestBody(data)
+ request.TextBody = &body
+ }
}
handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
@@ -977,14 +1323,100 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *gin.Context) {
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(MultipleRequestAndResponseTypesResponseObject); ok {
if err := validResponse.VisitMultipleRequestAndResponseTypesResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// NoContentHeaders operation middleware
+func (sh *strictHandler) NoContentHeaders(ctx *gin.Context) {
+ var request NoContentHeadersRequestObject
+
+ handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.NoContentHeaders(ctx, request.(NoContentHeadersRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "NoContentHeaders")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ sh.options.HandlerErrorFunc(ctx, err)
+ } else if validResponse, ok := response.(NoContentHeadersResponseObject); ok {
+ if err := validResponse.VisitNoContentHeadersResponse(ctx.Writer); err != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// RequiredJSONBody operation middleware
+func (sh *strictHandler) RequiredJSONBody(ctx *gin.Context) {
+ var request RequiredJSONBodyRequestObject
+
+ var body RequiredJSONBodyJSONRequestBody
+ if err := ctx.ShouldBindJSON(&body); err != nil {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
+ }
+ request.Body = &body
+
+ handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.RequiredJSONBody(ctx, request.(RequiredJSONBodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "RequiredJSONBody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ sh.options.HandlerErrorFunc(ctx, err)
+ } else if validResponse, ok := response.(RequiredJSONBodyResponseObject); ok {
+ if err := validResponse.VisitRequiredJSONBodyResponse(ctx.Writer); err != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// RequiredTextBody operation middleware
+func (sh *strictHandler) RequiredTextBody(ctx *gin.Context) {
+ var request RequiredTextBodyRequestObject
+
+ data, err := io.ReadAll(ctx.Request.Body)
+ if err != nil {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
+ }
+ body := RequiredTextBodyTextRequestBody(data)
+ request.Body = &body
+
+ handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.RequiredTextBody(ctx, request.(RequiredTextBodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "RequiredTextBody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ sh.options.HandlerErrorFunc(ctx, err)
+ } else if validResponse, ok := response.(RequiredTextBodyResponseObject); ok {
+ if err := validResponse.VisitRequiredTextBodyResponse(ctx.Writer); err != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
@@ -1004,14 +1436,13 @@ func (sh *strictHandler) ReservedGoKeywordParameters(ctx *gin.Context, pType str
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(ReservedGoKeywordParametersResponseObject); ok {
if err := validResponse.VisitReservedGoKeywordParametersResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
@@ -1020,12 +1451,14 @@ func (sh *strictHandler) ReusableResponses(ctx *gin.Context) {
var request ReusableResponsesRequestObject
var body ReusableResponsesJSONRequestBody
- if err := ctx.ShouldBind(&body); err != nil {
- ctx.Status(http.StatusBadRequest)
- ctx.Error(err)
- return
+ if err := ctx.ShouldBindJSON(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
return sh.ssi.ReusableResponses(ctx, request.(ReusableResponsesRequestObject))
@@ -1037,14 +1470,13 @@ func (sh *strictHandler) ReusableResponses(ctx *gin.Context) {
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(ReusableResponsesResponseObject); ok {
if err := validResponse.VisitReusableResponsesResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
@@ -1054,11 +1486,13 @@ func (sh *strictHandler) TextExample(ctx *gin.Context) {
data, err := io.ReadAll(ctx.Request.Body)
if err != nil {
- ctx.Error(err)
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
}
- body := TextExampleTextRequestBody(data)
- request.Body = &body
+ if len(data) > 0 {
+ body := TextExampleTextRequestBody(data)
+ request.Body = &body
+ }
handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
return sh.ssi.TextExample(ctx, request.(TextExampleRequestObject))
@@ -1070,14 +1504,13 @@ func (sh *strictHandler) TextExample(ctx *gin.Context) {
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(TextExampleResponseObject); ok {
if err := validResponse.VisitTextExampleResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
@@ -1097,14 +1530,13 @@ func (sh *strictHandler) UnknownExample(ctx *gin.Context) {
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(UnknownExampleResponseObject); ok {
if err := validResponse.VisitUnknownExampleResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
@@ -1126,14 +1558,13 @@ func (sh *strictHandler) UnspecifiedContentType(ctx *gin.Context) {
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(UnspecifiedContentTypeResponseObject); ok {
if err := validResponse.VisitUnspecifiedContentTypeResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
@@ -1142,12 +1573,12 @@ func (sh *strictHandler) URLEncodedExample(ctx *gin.Context) {
var request URLEncodedExampleRequestObject
if err := ctx.Request.ParseForm(); err != nil {
- ctx.Error(err)
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
}
var body URLEncodedExampleFormdataRequestBody
if err := runtime.BindForm(&body, ctx.Request.Form, nil, nil); err != nil {
- ctx.Error(err)
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
}
request.Body = &body
@@ -1162,14 +1593,13 @@ func (sh *strictHandler) URLEncodedExample(ctx *gin.Context) {
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(URLEncodedExampleResponseObject); ok {
if err := validResponse.VisitURLEncodedExampleResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
@@ -1180,12 +1610,14 @@ func (sh *strictHandler) HeadersExample(ctx *gin.Context, params HeadersExampleP
request.Params = params
var body HeadersExampleJSONRequestBody
- if err := ctx.ShouldBind(&body); err != nil {
- ctx.Status(http.StatusBadRequest)
- ctx.Error(err)
- return
+ if err := ctx.ShouldBindJSON(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
return sh.ssi.HeadersExample(ctx, request.(HeadersExampleRequestObject))
@@ -1197,14 +1629,13 @@ func (sh *strictHandler) HeadersExample(ctx *gin.Context, params HeadersExampleP
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(HeadersExampleResponseObject); ok {
if err := validResponse.VisitHeadersExampleResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
@@ -1213,12 +1644,14 @@ func (sh *strictHandler) UnionExample(ctx *gin.Context) {
var request UnionExampleRequestObject
var body UnionExampleJSONRequestBody
- if err := ctx.ShouldBind(&body); err != nil {
- ctx.Status(http.StatusBadRequest)
- ctx.Error(err)
- return
+ if err := ctx.ShouldBindJSON(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx *gin.Context, request interface{}) (interface{}, error) {
return sh.ssi.UnionExample(ctx, request.(UnionExampleRequestObject))
@@ -1230,54 +1663,59 @@ func (sh *strictHandler) UnionExample(ctx *gin.Context) {
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.(UnionExampleResponseObject); ok {
if err := validResponse.VisitUnionExampleResponse(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/+xYS2/jNhD+KwTb01aynGxOunWDxbbdtimc5FTkQIsjm7sSyQ5HVgzD/72gKL9ixbW3",
- "fhRBb3oMvxl+8+BwZjwzpTUaNDmezjiCs0Y7aF6GQiL8VYEj/ybBZagsKaN5yj8IOWj/zSOOUDkxLGCx",
- "3MtnRhPoZqmwtlCZ8EuTL86vn3GXjaEU/ul7hJyn/LtkZUoS/roEnkVpC+Dz+Tx6YcHdZx7xMQgJ2Fgb",
- "Hq82sWlqgafcESo94h4kiF13iilNMAL02rxoa4QXWNiRzrhFYwFJBY4moqigW1P7xQy/QEZhB0rnZpvL",
- "W6NJKO2YVHkOCJpYSx7zGI65ylqDBJINp8xryIg5wAkgjzgp8obx+/XvrDXY8YhPAF1QdNXr9/reX8aC",
- "FlbxlL9vPkXcCho3G1o6yJouv/9yf/c7U46JikwpSGWiKKasFOjGogDJlCbjTawycj3eaMLG8T/LdvXH",
- "lkofNU0AfTByeoqAaeJyLZyv+/0zxeU84jdBWRfG0qhkLcEamFxURQfnj/qrNrVmgGiw3VlSVgUpK5DW",
- "fbXJ9m8LkX0oX+IlucEyloLEiVg/lqaLEt/Wgs4cuR+b2rGxqRkZJkEUrFY0ZouFL5JbaSaYU3pUAFsY",
- "FXV6soC25P6o5aDdy4PHOHkuRRsoz3Fd13HjvAoL0JmRIL8NVpViBInVo83lHlsQT/lwSj5st4vrkYIo",
- "4gTPlNhCKL375DhTOfmf6aMldkhXhOZElPHIxF9hWhuUsRUoSiBAl8y89rkHHkFHKv+xlGSZ0GwITIsS",
- "JBM5AbJPhrWQbitlB63eT+ZzEFlBNcft8iX9c8Y9Jc0RzCPuFfA0sBLyWqF3OmEF0Q7anv4xPv+VAxZs",
- "hkYv3lDVXQYXJWpJHULufEns8lwHf0HTYE3iMg3D7ojban3PcQZ5T75+7j/A815H/hFL37lz+1DCqvDx",
- "dc7aVfvQ9o2VdA8WJ0qCSUp7cyDyxUh1FjKVK5Bxu4s42PZaSbg1OkOgzRbIXye0IbYE87ccGgMLDETM",
- "GVYDKytHzArnmKKmihQq3JQkbBWPx5Vlt0HTw6qc7vLquxP59N2lPHrTvzp8yfsTx81GK/NKPg5+/Rhk",
- "Dr0vHq1nOrDjO57eC6Wzv6TEawOV7hT+KQiszvQM1MR3RFoyBKpQg2QTJRZDgK3cbAFWbu3qhYIZq25o",
- "Mdw5pCGKdmJd82jXAOjpDY8nTjk2O1ecVlrtGlM9+t+s7aFfng3K6P/oEEoUBKgFqQn8cJwb5DaK0XCX",
- "N5n2wsvRnhqe3l5UzSMe5qahBFVY+DpBZNMkCfPWnqvFaATYUyYRVnkW/g4AAP//Pk3lbjwXAAA=",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "7Fnbcts2E36VHfz/RZuSpuL4SndNJpO2aZOObF91fAERKwkJCSDAUrJGo5k+RJ+wT9IBAepI21KqgyfT",
+ "O4ncE/fbXX5LzFiuS6MVKnKsO2MWndHKYf2nz4XFLxU68v8EutxKQ1Ir1mWvuejFe/OEWawc7xfYqHv5",
+ "XCtCVatyYwqZc6+afXJef8ZcPsKS+1//tzhgXfa/bBlKFu66DO95aQpk8/k82Yjg43uWsBFygbaONvx8",
+ "GZ7iSyUtCtYlW2Gy4oumBlmXObJSDZk3GtQud1KTinCI1kfjVWOQXqCJsztjxmqDlmTI4ZgXFbZ7jld0",
+ "/xPmFJ5QqoHezvUbrYhL5UDIwQAtKoKYXPA2HLjKGG0JBfSn4D3kBA7tGC1LGEnygbHr1esQA3YsYWO0",
+ "Ljh6edG56Hg8tUHFjWRd9qq+lDDDaVQ/0AJAo9vq4pfrjx9AOuAV6ZKTzHlRTKHk1o14gQKkIu1DrHJy",
+ "F6z2ZOvC+FlE7bcxlQmLxfdai+kxCqqu25Vyv+x0TlS384RdBWdtNhZBZSsNWJsZ8Kpoyfmt+qz0RAFa",
+ "q218sqysCpKGW1rFaj3bvzUiu6R8YS8baFumghM/UtYP5enciU8tFpz8OHkSgF6Q3A+HFfNHReHf+Dkr",
+ "BnEet86p65GeOBjpCZAGgbyAiaQRNIobA1Yq4OCkGhYITVBJK5gFxtfij0r04rPceBtHn2fJmpX7dDKZ",
+ "pHUDVbZAlWvxdRAmTJZ8iJlRw3V1b5sT67L+lHzJbr/gDtTICSO8p8wUXG4kZtPliUb6f5k+WGOHdlU6",
+ "jRClK4SuvXE/LGThu8vO1ffQGA4NrGs5XgBXAlRVFJ6WLmWiefj7z78A79Hm0qEDGnGCSjmkhQC3CLqU",
+ "5EnVwOoSaLQ0s9X7H/SbENNPMfytOrxqexKIWutEtok65mIdiOZmw1G3a6HJQKv6dscEBBrqm/qeSPtx",
+ "QrUjEAcceClP9RrdBJyGUjo/J8NNN9JVIYAXEz51YUJvc75eVPfcrx6NRyd+yQbT/7aJ4AJa39vngfYG",
+ "7+lJaPcYPfvCd+qptj9E9VYm0qFOP+N0oq1IDbe8RELrspmPc+5tDbHF5O8LSci5gj6C4iUK4ANCC+80",
+ "RJOuBZ/g951+H0SWpuqVb/Gn+8eM+eTVayBLmHfAuiF/yR7r9t1xoWqyGT5GpGuuHir4KNKkzuLAeUrY",
+ "hnFL/oKn3orEeZbWx2tz6/PMKYraI/nw6uNHwi7rzgGp33OfAlW4+HDOotYuaftKJrlDFsdSoM5Kc7Wn",
+ "5bMl1RnM5UCiWHDMENtDI+GNVrlFWl8B/ctQaYKFMehPa0oYMlC/HycIZeUIDHcOJNVTpJDha53Y5oy3",
+ "y8giDbxZjtPHUH1xJExfnAvRq87L/VVeHblu1la5B/qx9+vbILPvN8uD7Yx7bryH83umdvY73tM7YtzC",
+ "lu/0HOXYMyIlwCJVVqGAseTNh+it3owGlrC2caG4Xy3YUHMAsQ8hSh61dckePYS4+4Y/kZ/vaCc58QJ+",
+ "qq6plHzs4ObW34bI6DffVFKrZ3oswwtCqzjJMf5wmO9521a0wo+Duu830Et29HD3/I4vj11184SFk8Yw",
+ "MCtb+KlGZLpZFk4oL9yED4doL6TOuJE+S/8EAAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -1285,7 +1723,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -1303,12 +1741,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -1334,3 +1772,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/strict-server/gin/server.go b/internal/test/strict-server/gin/server.go
index 669d4da4f4..1f4c633fae 100644
--- a/internal/test/strict-server/gin/server.go
+++ b/internal/test/strict-server/gin/server.go
@@ -1,5 +1,5 @@
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
package api
@@ -41,6 +41,30 @@ func (s StrictServer) MultipartExample(ctx context.Context, request MultipartExa
}), nil
}
+func (s StrictServer) MultipartRelatedExample(ctx context.Context, request MultipartRelatedExampleRequestObject) (MultipartRelatedExampleResponseObject, error) {
+ return MultipartRelatedExample200MultipartResponse(func(writer *multipart.Writer) error {
+ for {
+ part, err := request.Body.NextPart()
+ if err == io.EOF {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ w, err := writer.CreatePart(part.Header)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(w, part)
+ if err != nil {
+ return err
+ }
+ if err = part.Close(); err != nil {
+ return err
+ }
+ }
+ }), nil
+}
+
func (s StrictServer) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error) {
switch {
case request.Body != nil:
@@ -98,10 +122,22 @@ func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExample
return HeadersExample200JSONResponse{Body: *request.Body, Headers: HeadersExample200ResponseHeaders{Header1: request.Params.Header1, Header2: *request.Params.Header2}}, nil
}
+func (s StrictServer) NoContentHeaders(ctx context.Context, request NoContentHeadersRequestObject) (NoContentHeadersResponseObject, error) {
+ return NoContentHeaders204Response{}, nil
+}
+
func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) {
return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil
}
+func (s StrictServer) RequiredJSONBody(ctx context.Context, request RequiredJSONBodyRequestObject) (RequiredJSONBodyResponseObject, error) {
+ return RequiredJSONBody200JSONResponse(*request.Body), nil
+}
+
+func (s StrictServer) RequiredTextBody(ctx context.Context, request RequiredTextBodyRequestObject) (RequiredTextBodyResponseObject, error) {
+ return RequiredTextBody200TextResponse(*request.Body), nil
+}
+
func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) {
return ReservedGoKeywordParameters200TextResponse(""), nil
}
diff --git a/internal/test/strict-server/gin/types.cfg.yaml b/internal/test/strict-server/gin/types.cfg.yaml
index 4ea1d8aa5b..2ed9740ea7 100644
--- a/internal/test/strict-server/gin/types.cfg.yaml
+++ b/internal/test/strict-server/gin/types.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
models: true
diff --git a/internal/test/strict-server/gin/types.gen.go b/internal/test/strict-server/gin/types.gen.go
index 6a0de0c970..08ae8548e1 100644
--- a/internal/test/strict-server/gin/types.gen.go
+++ b/internal/test/strict-server/gin/types.gen.go
@@ -1,8 +1,14 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
+import (
+ "encoding/json"
+
+ "github.com/oapi-codegen/runtime"
+)
+
// Example defines model for example.
type Example struct {
Value *string `json:"value,omitempty"`
@@ -14,6 +20,9 @@ type Reusableresponse = Example
// MultipleRequestAndResponseTypesTextBody defines parameters for MultipleRequestAndResponseTypes.
type MultipleRequestAndResponseTypesTextBody = string
+// RequiredTextBodyTextBody defines parameters for RequiredTextBody.
+type RequiredTextBodyTextBody = string
+
// TextExampleTextBody defines parameters for TextExample.
type TextExampleTextBody = string
@@ -23,12 +32,23 @@ type HeadersExampleParams struct {
Header2 *int `json:"header2,omitempty"`
}
+// UnionExample200JSONResponseBody0 defines parameters for UnionExample.
+type UnionExample200JSONResponseBody0 = string
+
+// UnionExample200JSONResponseBody defines parameters for UnionExample.
+type UnionExample200JSONResponseBody struct {
+ union json.RawMessage
+}
+
// JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType.
type JSONExampleJSONRequestBody = Example
// MultipartExampleMultipartRequestBody defines body for MultipartExample for multipart/form-data ContentType.
type MultipartExampleMultipartRequestBody = Example
+// MultipartRelatedExampleMultipartRequestBody defines body for MultipartRelatedExample for multipart/related ContentType.
+type MultipartRelatedExampleMultipartRequestBody = Example
+
// MultipleRequestAndResponseTypesJSONRequestBody defines body for MultipleRequestAndResponseTypes for application/json ContentType.
type MultipleRequestAndResponseTypesJSONRequestBody = Example
@@ -41,6 +61,12 @@ type MultipleRequestAndResponseTypesMultipartRequestBody = Example
// MultipleRequestAndResponseTypesTextRequestBody defines body for MultipleRequestAndResponseTypes for text/plain ContentType.
type MultipleRequestAndResponseTypesTextRequestBody = MultipleRequestAndResponseTypesTextBody
+// RequiredJSONBodyJSONRequestBody defines body for RequiredJSONBody for application/json ContentType.
+type RequiredJSONBodyJSONRequestBody = Example
+
+// RequiredTextBodyTextRequestBody defines body for RequiredTextBody for text/plain ContentType.
+type RequiredTextBodyTextRequestBody = RequiredTextBodyTextBody
+
// ReusableResponsesJSONRequestBody defines body for ReusableResponses for application/json ContentType.
type ReusableResponsesJSONRequestBody = Example
@@ -55,3 +81,65 @@ type HeadersExampleJSONRequestBody = Example
// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType.
type UnionExampleJSONRequestBody = Example
+
+// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0
+func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) {
+ var body UnionExample200JSONResponseBody0
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example
+func (t UnionExample200JSONResponseBody) AsExample() (Example, error) {
+ var body Example
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example
+func (t *UnionExample200JSONResponseBody) FromExample(v Example) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example
+func (t *UnionExample200JSONResponseBody) MergeExample(v Example) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
diff --git a/internal/test/strict-server/gorilla/server.cfg.yaml b/internal/test/strict-server/gorilla/server.cfg.yaml
index 4c40e5aee1..a39491cbef 100644
--- a/internal/test/strict-server/gorilla/server.cfg.yaml
+++ b/internal/test/strict-server/gorilla/server.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
gorilla-server: true
diff --git a/internal/test/strict-server/gorilla/server.gen.go b/internal/test/strict-server/gorilla/server.gen.go
index 234089ff0b..e8d9dc439d 100644
--- a/internal/test/strict-server/gorilla/server.gen.go
+++ b/internal/test/strict-server/gorilla/server.gen.go
@@ -1,16 +1,18 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
+ "errors"
"fmt"
"io"
+ "mime"
"mime/multipart"
"net/http"
"net/url"
@@ -20,7 +22,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/gorilla/mux"
"github.com/oapi-codegen/runtime"
- strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"
)
// ServerInterface represents all server handlers.
@@ -32,9 +33,21 @@ type ServerInterface interface {
// (POST /multipart)
MultipartExample(w http.ResponseWriter, r *http.Request)
+ // (POST /multipart-related)
+ MultipartRelatedExample(w http.ResponseWriter, r *http.Request)
+
// (POST /multiple)
MultipleRequestAndResponseTypes(w http.ResponseWriter, r *http.Request)
+ // (POST /no-content-headers)
+ NoContentHeaders(w http.ResponseWriter, r *http.Request)
+
+ // (POST /required-json-body)
+ RequiredJSONBody(w http.ResponseWriter, r *http.Request)
+
+ // (POST /required-text-body)
+ RequiredTextBody(w http.ResponseWriter, r *http.Request)
+
// (GET /reserved-go-keyword-parameters/{type})
ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request, pType string)
@@ -71,7 +84,6 @@ type MiddlewareFunc func(http.Handler) http.Handler
// JSONExample operation middleware
func (siw *ServerInterfaceWrapper) JSONExample(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.JSONExample(w, r)
@@ -81,12 +93,11 @@ func (siw *ServerInterfaceWrapper) JSONExample(w http.ResponseWriter, r *http.Re
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// MultipartExample operation middleware
func (siw *ServerInterfaceWrapper) MultipartExample(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.MultipartExample(w, r)
@@ -96,12 +107,25 @@ func (siw *ServerInterfaceWrapper) MultipartExample(w http.ResponseWriter, r *ht
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
+}
+
+// MultipartRelatedExample operation middleware
+func (siw *ServerInterfaceWrapper) MultipartRelatedExample(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.MultipartRelatedExample(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
}
// MultipleRequestAndResponseTypes operation middleware
func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.MultipleRequestAndResponseTypes(w, r)
@@ -111,19 +135,61 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(w http.Respon
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
+}
+
+// NoContentHeaders operation middleware
+func (siw *ServerInterfaceWrapper) NoContentHeaders(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.NoContentHeaders(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// RequiredJSONBody operation middleware
+func (siw *ServerInterfaceWrapper) RequiredJSONBody(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.RequiredJSONBody(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// RequiredTextBody operation middleware
+func (siw *ServerInterfaceWrapper) RequiredTextBody(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.RequiredTextBody(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
}
// ReservedGoKeywordParameters operation middleware
func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// ------------- Path parameter "type" -------------
var pType string
- err = runtime.BindStyledParameter("simple", false, "type", mux.Vars(r)["type"], &pType)
+ err = runtime.BindStyledParameterWithOptions("simple", "type", mux.Vars(r)["type"], &pType, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "type", Err: err})
return
@@ -137,12 +203,11 @@ func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(w http.ResponseWr
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// ReusableResponses operation middleware
func (siw *ServerInterfaceWrapper) ReusableResponses(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.ReusableResponses(w, r)
@@ -152,12 +217,11 @@ func (siw *ServerInterfaceWrapper) ReusableResponses(w http.ResponseWriter, r *h
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// TextExample operation middleware
func (siw *ServerInterfaceWrapper) TextExample(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.TextExample(w, r)
@@ -167,12 +231,11 @@ func (siw *ServerInterfaceWrapper) TextExample(w http.ResponseWriter, r *http.Re
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// UnknownExample operation middleware
func (siw *ServerInterfaceWrapper) UnknownExample(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.UnknownExample(w, r)
@@ -182,12 +245,11 @@ func (siw *ServerInterfaceWrapper) UnknownExample(w http.ResponseWriter, r *http
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// UnspecifiedContentType operation middleware
func (siw *ServerInterfaceWrapper) UnspecifiedContentType(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.UnspecifiedContentType(w, r)
@@ -197,12 +259,11 @@ func (siw *ServerInterfaceWrapper) UnspecifiedContentType(w http.ResponseWriter,
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// URLEncodedExample operation middleware
func (siw *ServerInterfaceWrapper) URLEncodedExample(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.URLEncodedExample(w, r)
@@ -212,14 +273,14 @@ func (siw *ServerInterfaceWrapper) URLEncodedExample(w http.ResponseWriter, r *h
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// HeadersExample operation middleware
func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
var err error
+ _ = err
// Parameter object where we will unmarshal all parameters from the context
var params HeadersExampleParams
@@ -235,7 +296,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http
return
}
- err = runtime.BindStyledParameterWithLocation("simple", false, "header1", runtime.ParamLocationHeader, valueList[0], &Header1)
+ err = runtime.BindStyledParameterWithOptions("simple", "header1", valueList[0], &Header1, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "header1", Err: err})
return
@@ -258,7 +319,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http
return
}
- err = runtime.BindStyledParameterWithLocation("simple", false, "header2", runtime.ParamLocationHeader, valueList[0], &Header2)
+ err = runtime.BindStyledParameterWithOptions("simple", "header2", valueList[0], &Header2, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: ""})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "header2", Err: err})
return
@@ -276,12 +337,11 @@ func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
// UnionExample operation middleware
func (siw *ServerInterfaceWrapper) UnionExample(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
siw.Handler.UnionExample(w, r)
@@ -291,7 +351,7 @@ func (siw *ServerInterfaceWrapper) UnionExample(w http.ResponseWriter, r *http.R
handler = middleware(handler)
}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
type UnescapedCookieParamError struct {
@@ -407,27 +467,35 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
- r.HandleFunc(options.BaseURL+"/json", wrapper.JSONExample).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/json", wrapper.JSONExample).Methods(http.MethodPost)
+
+ r.HandleFunc(options.BaseURL+"/multipart", wrapper.MultipartExample).Methods(http.MethodPost)
+
+ r.HandleFunc(options.BaseURL+"/multipart-related", wrapper.MultipartRelatedExample).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/multipart", wrapper.MultipartExample).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/no-content-headers", wrapper.NoContentHeaders).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/reserved-go-keyword-parameters/{type}", wrapper.ReservedGoKeywordParameters).Methods("GET")
+ r.HandleFunc(options.BaseURL+"/required-json-body", wrapper.RequiredJSONBody).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/required-text-body", wrapper.RequiredTextBody).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/text", wrapper.TextExample).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/reserved-go-keyword-parameters/{type}", wrapper.ReservedGoKeywordParameters).Methods(http.MethodGet)
- r.HandleFunc(options.BaseURL+"/unknown", wrapper.UnknownExample).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/text", wrapper.TextExample).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/unknown", wrapper.UnknownExample).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/with-headers", wrapper.HeadersExample).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/with-union", wrapper.UnionExample).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample).Methods(http.MethodPost)
+
+ r.HandleFunc(options.BaseURL+"/with-headers", wrapper.HeadersExample).Methods(http.MethodPost)
+
+ r.HandleFunc(options.BaseURL+"/with-union", wrapper.UnionExample).Methods(http.MethodPost)
return r
}
@@ -456,10 +524,15 @@ type JSONExampleResponseObject interface {
type JSONExample200JSONResponse Example
func (response JSONExample200JSONResponse) VisitJSONExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type JSONExample400Response = BadrequestResponse
@@ -490,6 +563,7 @@ type MultipartExample200MultipartResponse func(writer *multipart.Writer) error
func (response MultipartExample200MultipartResponse) VisitMultipartExampleResponse(w http.ResponseWriter) error {
writer := multipart.NewWriter(w)
+
w.Header().Set("Content-Type", writer.FormDataContentType())
w.WriteHeader(200)
@@ -513,6 +587,42 @@ func (response MultipartExampledefaultResponse) VisitMultipartExampleResponse(w
return nil
}
+type MultipartRelatedExampleRequestObject struct {
+ Body *multipart.Reader
+}
+
+type MultipartRelatedExampleResponseObject interface {
+ VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error
+}
+
+type MultipartRelatedExample200MultipartResponse func(writer *multipart.Writer) error
+
+func (response MultipartRelatedExample200MultipartResponse) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ writer := multipart.NewWriter(w)
+
+ w.Header().Set("Content-Type", mime.FormatMediaType("multipart/related", map[string]string{"boundary": writer.Boundary()}))
+ w.WriteHeader(200)
+
+ defer writer.Close()
+ return response(writer)
+}
+
+type MultipartRelatedExample400Response = BadrequestResponse
+
+func (response MultipartRelatedExample400Response) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type MultipartRelatedExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response MultipartRelatedExampledefaultResponse) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
type MultipleRequestAndResponseTypesRequestObject struct {
JSONBody *MultipleRequestAndResponseTypesJSONRequestBody
FormdataBody *MultipleRequestAndResponseTypesFormdataRequestBody
@@ -528,24 +638,29 @@ type MultipleRequestAndResponseTypesResponseObject interface {
type MultipleRequestAndResponseTypes200JSONResponse Example
func (response MultipleRequestAndResponseTypes200JSONResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
type MultipleRequestAndResponseTypes200FormdataResponse Example
func (response MultipleRequestAndResponseTypes200FormdataResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
- w.WriteHeader(200)
- if form, err := runtime.MarshalForm(response, nil); err != nil {
- return err
- } else {
- _, err := w.Write([]byte(form.Encode()))
+ form, err := runtime.MarshalForm(response, nil)
+ if err != nil {
return err
}
+ w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
+ w.WriteHeader(200)
+ _, err = w.Write([]byte(form.Encode()))
+ return err
}
type MultipleRequestAndResponseTypes200ImagepngResponse struct {
@@ -554,6 +669,7 @@ type MultipleRequestAndResponseTypes200ImagepngResponse struct {
}
func (response MultipleRequestAndResponseTypes200ImagepngResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "image/png")
if response.ContentLength != 0 {
w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
@@ -571,6 +687,7 @@ type MultipleRequestAndResponseTypes200MultipartResponse func(writer *multipart.
func (response MultipleRequestAndResponseTypes200MultipartResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
writer := multipart.NewWriter(w)
+
w.Header().Set("Content-Type", writer.FormDataContentType())
w.WriteHeader(200)
@@ -581,6 +698,7 @@ func (response MultipleRequestAndResponseTypes200MultipartResponse) VisitMultipl
type MultipleRequestAndResponseTypes200TextResponse string
func (response MultipleRequestAndResponseTypes200TextResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(200)
@@ -595,6 +713,106 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA
return nil
}
+type NoContentHeadersRequestObject struct {
+}
+
+type NoContentHeadersResponseObject interface {
+ VisitNoContentHeadersResponse(w http.ResponseWriter) error
+}
+
+type NoContentHeaders204ResponseHeaders struct {
+ NullableHeader *string
+ OptionalHeader *string
+}
+
+type NoContentHeaders204Response struct {
+ Headers NoContentHeaders204ResponseHeaders
+}
+
+func (response NoContentHeaders204Response) VisitNoContentHeadersResponse(w http.ResponseWriter) error {
+ if response.Headers.NullableHeader != nil {
+ w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader))
+ }
+ if response.Headers.OptionalHeader != nil {
+ w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader))
+ }
+ w.WriteHeader(204)
+ return nil
+}
+
+type RequiredJSONBodyRequestObject struct {
+ Body *RequiredJSONBodyJSONRequestBody
+}
+
+type RequiredJSONBodyResponseObject interface {
+ VisitRequiredJSONBodyResponse(w http.ResponseWriter) error
+}
+
+type RequiredJSONBody200JSONResponse Example
+
+func (response RequiredJSONBody200JSONResponse) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type RequiredJSONBody400Response = BadrequestResponse
+
+func (response RequiredJSONBody400Response) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type RequiredJSONBodydefaultResponse struct {
+ StatusCode int
+}
+
+func (response RequiredJSONBodydefaultResponse) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type RequiredTextBodyRequestObject struct {
+ Body *RequiredTextBodyTextRequestBody
+}
+
+type RequiredTextBodyResponseObject interface {
+ VisitRequiredTextBodyResponse(w http.ResponseWriter) error
+}
+
+type RequiredTextBody200TextResponse string
+
+func (response RequiredTextBody200TextResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "text/plain")
+ w.WriteHeader(200)
+
+ _, err := w.Write([]byte(response))
+ return err
+}
+
+type RequiredTextBody400Response = BadrequestResponse
+
+func (response RequiredTextBody400Response) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type RequiredTextBodydefaultResponse struct {
+ StatusCode int
+}
+
+func (response RequiredTextBodydefaultResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
type ReservedGoKeywordParametersRequestObject struct {
Type string `json:"type"`
}
@@ -606,6 +824,7 @@ type ReservedGoKeywordParametersResponseObject interface {
type ReservedGoKeywordParameters200TextResponse string
func (response ReservedGoKeywordParameters200TextResponse) VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(200)
@@ -624,12 +843,17 @@ type ReusableResponsesResponseObject interface {
type ReusableResponses200JSONResponse struct{ ReusableresponseJSONResponse }
func (response ReusableResponses200JSONResponse) VisitReusableResponsesResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type ReusableResponses400Response = BadrequestResponse
@@ -659,6 +883,7 @@ type TextExampleResponseObject interface {
type TextExample200TextResponse string
func (response TextExample200TextResponse) VisitTextExampleResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "text/plain")
w.WriteHeader(200)
@@ -696,6 +921,7 @@ type UnknownExample200Videomp4Response struct {
}
func (response UnknownExample200Videomp4Response) VisitUnknownExampleResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", "video/mp4")
if response.ContentLength != 0 {
w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
@@ -741,6 +967,7 @@ type UnspecifiedContentType200VideoResponse struct {
}
func (response UnspecifiedContentType200VideoResponse) VisitUnspecifiedContentTypeResponse(w http.ResponseWriter) error {
+
w.Header().Set("Content-Type", response.ContentType)
if response.ContentLength != 0 {
w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
@@ -797,15 +1024,15 @@ type URLEncodedExampleResponseObject interface {
type URLEncodedExample200FormdataResponse Example
func (response URLEncodedExample200FormdataResponse) VisitURLEncodedExampleResponse(w http.ResponseWriter) error {
- w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
- w.WriteHeader(200)
- if form, err := runtime.MarshalForm(response, nil); err != nil {
- return err
- } else {
- _, err := w.Write([]byte(form.Encode()))
+ form, err := runtime.MarshalForm(response, nil)
+ if err != nil {
return err
}
+ w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
+ w.WriteHeader(200)
+ _, err = w.Write([]byte(form.Encode()))
+ return err
}
type URLEncodedExample400Response = BadrequestResponse
@@ -834,8 +1061,10 @@ type HeadersExampleResponseObject interface {
}
type HeadersExample200ResponseHeaders struct {
- Header1 string
- Header2 int
+ Header1 string
+ Header2 int
+ NullableHeader *string
+ OptionalHeader *string
}
type HeadersExample200JSONResponse struct {
@@ -844,12 +1073,23 @@ type HeadersExample200JSONResponse struct {
}
func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
+ if response.Headers.NullableHeader != nil {
+ w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader))
+ }
+ if response.Headers.OptionalHeader != nil {
+ w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader))
+ }
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type HeadersExample400Response = BadrequestResponse
@@ -887,28 +1127,36 @@ type UnionExample200ApplicationAlternativePlusJSONResponse struct {
}
func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/alternative+json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body)
+ _, err := buf.WriteTo(w)
+ return err
}
type UnionExample200JSONResponse struct {
- Body struct {
- union json.RawMessage
- }
+ Body UnionExample200JSONResponseBody
Headers UnionExample200ResponseHeaders
}
func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body.union); err != nil {
+ return err
+ }
w.Header().Set("Content-Type", "application/json")
w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
w.WriteHeader(200)
-
- return json.NewEncoder(w).Encode(response.Body.union)
+ _, err := buf.WriteTo(w)
+ return err
}
type UnionExample400Response = BadrequestResponse
@@ -936,9 +1184,21 @@ type StrictServerInterface interface {
// (POST /multipart)
MultipartExample(ctx context.Context, request MultipartExampleRequestObject) (MultipartExampleResponseObject, error)
+ // (POST /multipart-related)
+ MultipartRelatedExample(ctx context.Context, request MultipartRelatedExampleRequestObject) (MultipartRelatedExampleResponseObject, error)
+
// (POST /multiple)
MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error)
+ // (POST /no-content-headers)
+ NoContentHeaders(ctx context.Context, request NoContentHeadersRequestObject) (NoContentHeadersResponseObject, error)
+
+ // (POST /required-json-body)
+ RequiredJSONBody(ctx context.Context, request RequiredJSONBodyRequestObject) (RequiredJSONBodyResponseObject, error)
+
+ // (POST /required-text-body)
+ RequiredTextBody(ctx context.Context, request RequiredTextBodyRequestObject) (RequiredTextBodyResponseObject, error)
+
// (GET /reserved-go-keyword-parameters/{type})
ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error)
@@ -964,8 +1224,8 @@ type StrictServerInterface interface {
UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error)
}
-type StrictHandlerFunc = strictnethttp.StrictHttpHandlerFunc
-type StrictMiddlewareFunc = strictnethttp.StrictHttpMiddlewareFunc
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
type StrictHTTPServerOptions struct {
RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
@@ -999,10 +1259,13 @@ func (sh *strictHandler) JSONExample(w http.ResponseWriter, r *http.Request) {
var body JSONExampleJSONRequestBody
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
- sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
- return
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
return sh.ssi.JSONExample(ctx, request.(JSONExampleRequestObject))
@@ -1055,6 +1318,40 @@ func (sh *strictHandler) MultipartExample(w http.ResponseWriter, r *http.Request
}
}
+// MultipartRelatedExample operation middleware
+func (sh *strictHandler) MultipartRelatedExample(w http.ResponseWriter, r *http.Request) {
+ var request MultipartRelatedExampleRequestObject
+
+ if _, params, err := mime.ParseMediaType(r.Header.Get("Content-Type")); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, err)
+ return
+ } else if boundary := params["boundary"]; boundary == "" {
+ sh.options.RequestErrorHandlerFunc(w, r, http.ErrMissingBoundary)
+ return
+ } else {
+ request.Body = multipart.NewReader(r.Body, boundary)
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.MultipartRelatedExample(ctx, request.(MultipartRelatedExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "MultipartRelatedExample")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(MultipartRelatedExampleResponseObject); ok {
+ if err := validResponse.VisitMultipartRelatedExampleResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
// MultipleRequestAndResponseTypes operation middleware
func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter, r *http.Request) {
var request MultipleRequestAndResponseTypesRequestObject
@@ -1063,10 +1360,13 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter,
var body MultipleRequestAndResponseTypesJSONRequestBody
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
- sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
- return
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.JSONBody = &body
}
- request.JSONBody = &body
}
if strings.HasPrefix(r.Header.Get("Content-Type"), "application/x-www-form-urlencoded") {
if err := r.ParseForm(); err != nil {
@@ -1097,8 +1397,10 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter,
sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't read body: %w", err))
return
}
- body := MultipleRequestAndResponseTypesTextRequestBody(data)
- request.TextBody = &body
+ if len(data) > 0 {
+ body := MultipleRequestAndResponseTypesTextRequestBody(data)
+ request.TextBody = &body
+ }
}
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
@@ -1121,6 +1423,93 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter,
}
}
+// NoContentHeaders operation middleware
+func (sh *strictHandler) NoContentHeaders(w http.ResponseWriter, r *http.Request) {
+ var request NoContentHeadersRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.NoContentHeaders(ctx, request.(NoContentHeadersRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "NoContentHeaders")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(NoContentHeadersResponseObject); ok {
+ if err := validResponse.VisitNoContentHeadersResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// RequiredJSONBody operation middleware
+func (sh *strictHandler) RequiredJSONBody(w http.ResponseWriter, r *http.Request) {
+ var request RequiredJSONBodyRequestObject
+
+ var body RequiredJSONBodyJSONRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ request.Body = &body
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.RequiredJSONBody(ctx, request.(RequiredJSONBodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "RequiredJSONBody")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(RequiredJSONBodyResponseObject); ok {
+ if err := validResponse.VisitRequiredJSONBodyResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// RequiredTextBody operation middleware
+func (sh *strictHandler) RequiredTextBody(w http.ResponseWriter, r *http.Request) {
+ var request RequiredTextBodyRequestObject
+
+ data, err := io.ReadAll(r.Body)
+ if err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't read body: %w", err))
+ return
+ }
+ body := RequiredTextBodyTextRequestBody(data)
+ request.Body = &body
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.RequiredTextBody(ctx, request.(RequiredTextBodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "RequiredTextBody")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(RequiredTextBodyResponseObject); ok {
+ if err := validResponse.VisitRequiredTextBodyResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
// ReservedGoKeywordParameters operation middleware
func (sh *strictHandler) ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request, pType string) {
var request ReservedGoKeywordParametersRequestObject
@@ -1153,10 +1542,13 @@ func (sh *strictHandler) ReusableResponses(w http.ResponseWriter, r *http.Reques
var body ReusableResponsesJSONRequestBody
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
- sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
- return
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
return sh.ssi.ReusableResponses(ctx, request.(ReusableResponsesRequestObject))
@@ -1187,8 +1579,10 @@ func (sh *strictHandler) TextExample(w http.ResponseWriter, r *http.Request) {
sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't read body: %w", err))
return
}
- body := TextExampleTextRequestBody(data)
- request.Body = &body
+ if len(data) > 0 {
+ body := TextExampleTextRequestBody(data)
+ request.Body = &body
+ }
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
return sh.ssi.TextExample(ctx, request.(TextExampleRequestObject))
@@ -1307,10 +1701,13 @@ func (sh *strictHandler) HeadersExample(w http.ResponseWriter, r *http.Request,
var body HeadersExampleJSONRequestBody
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
- sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
- return
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
return sh.ssi.HeadersExample(ctx, request.(HeadersExampleRequestObject))
@@ -1338,10 +1735,13 @@ func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) {
var body UnionExampleJSONRequestBody
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
- sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
- return
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
return sh.ssi.UnionExample(ctx, request.(UnionExampleRequestObject))
@@ -1363,43 +1763,49 @@ func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) {
}
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/+xYS2/jNhD+KwTb01aynGxOunWDxbbdtimc5FTkQIsjm7sSyQ5HVgzD/72gKL9ixbW3",
- "fhRBb3oMvxl+8+BwZjwzpTUaNDmezjiCs0Y7aF6GQiL8VYEj/ybBZagsKaN5yj8IOWj/zSOOUDkxLGCx",
- "3MtnRhPoZqmwtlCZ8EuTL86vn3GXjaEU/ul7hJyn/LtkZUoS/roEnkVpC+Dz+Tx6YcHdZx7xMQgJ2Fgb",
- "Hq82sWlqgafcESo94h4kiF13iilNMAL02rxoa4QXWNiRzrhFYwFJBY4moqigW1P7xQy/QEZhB0rnZpvL",
- "W6NJKO2YVHkOCJpYSx7zGI65ylqDBJINp8xryIg5wAkgjzgp8obx+/XvrDXY8YhPAF1QdNXr9/reX8aC",
- "FlbxlL9vPkXcCho3G1o6yJouv/9yf/c7U46JikwpSGWiKKasFOjGogDJlCbjTawycj3eaMLG8T/LdvXH",
- "lkofNU0AfTByeoqAaeJyLZyv+/0zxeU84jdBWRfG0qhkLcEamFxURQfnj/qrNrVmgGiw3VlSVgUpK5DW",
- "fbXJ9m8LkX0oX+IlucEyloLEiVg/lqaLEt/Wgs4cuR+b2rGxqRkZJkEUrFY0ZouFL5JbaSaYU3pUAFsY",
- "FXV6soC25P6o5aDdy4PHOHkuRRsoz3Fd13HjvAoL0JmRIL8NVpViBInVo83lHlsQT/lwSj5st4vrkYIo",
- "4gTPlNhCKL375DhTOfmf6aMldkhXhOZElPHIxF9hWhuUsRUoSiBAl8y89rkHHkFHKv+xlGSZ0GwITIsS",
- "JBM5AbJPhrWQbitlB63eT+ZzEFlBNcft8iX9c8Y9Jc0RzCPuFfA0sBLyWqF3OmEF0Q7anv4xPv+VAxZs",
- "hkYv3lDVXQYXJWpJHULufEns8lwHf0HTYE3iMg3D7ojban3PcQZ5T75+7j/A815H/hFL37lz+1DCqvDx",
- "dc7aVfvQ9o2VdA8WJ0qCSUp7cyDyxUh1FjKVK5Bxu4s42PZaSbg1OkOgzRbIXye0IbYE87ccGgMLDETM",
- "GVYDKytHzArnmKKmihQq3JQkbBWPx5Vlt0HTw6qc7vLquxP59N2lPHrTvzp8yfsTx81GK/NKPg5+/Rhk",
- "Dr0vHq1nOrDjO57eC6Wzv6TEawOV7hT+KQiszvQM1MR3RFoyBKpQg2QTJRZDgK3cbAFWbu3qhYIZq25o",
- "Mdw5pCGKdmJd82jXAOjpDY8nTjk2O1ecVlrtGlM9+t+s7aFfng3K6P/oEEoUBKgFqQn8cJwb5DaK0XCX",
- "N5n2wsvRnhqe3l5UzSMe5qahBFVY+DpBZNMkCfPWnqvFaATYUyYRVnkW/g4AAP//Pk3lbjwXAAA=",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "7Fnbcts2E36VHfz/RZuSpuL4SndNJpO2aZOObF91fAERKwkJCSDAUrJGo5k+RJ+wT9IBAepI21KqgyfT",
+ "O4ncE/fbXX5LzFiuS6MVKnKsO2MWndHKYf2nz4XFLxU68v8EutxKQ1Ir1mWvuejFe/OEWawc7xfYqHv5",
+ "XCtCVatyYwqZc6+afXJef8ZcPsKS+1//tzhgXfa/bBlKFu66DO95aQpk8/k82Yjg43uWsBFygbaONvx8",
+ "GZ7iSyUtCtYlW2Gy4oumBlmXObJSDZk3GtQud1KTinCI1kfjVWOQXqCJsztjxmqDlmTI4ZgXFbZ7jld0",
+ "/xPmFJ5QqoHezvUbrYhL5UDIwQAtKoKYXPA2HLjKGG0JBfSn4D3kBA7tGC1LGEnygbHr1esQA3YsYWO0",
+ "Ljh6edG56Hg8tUHFjWRd9qq+lDDDaVQ/0AJAo9vq4pfrjx9AOuAV6ZKTzHlRTKHk1o14gQKkIu1DrHJy",
+ "F6z2ZOvC+FlE7bcxlQmLxfdai+kxCqqu25Vyv+x0TlS384RdBWdtNhZBZSsNWJsZ8Kpoyfmt+qz0RAFa",
+ "q218sqysCpKGW1rFaj3bvzUiu6R8YS8baFumghM/UtYP5enciU8tFpz8OHkSgF6Q3A+HFfNHReHf+Dkr",
+ "BnEet86p65GeOBjpCZAGgbyAiaQRNIobA1Yq4OCkGhYITVBJK5gFxtfij0r04rPceBtHn2fJmpX7dDKZ",
+ "pHUDVbZAlWvxdRAmTJZ8iJlRw3V1b5sT67L+lHzJbr/gDtTICSO8p8wUXG4kZtPliUb6f5k+WGOHdlU6",
+ "jRClK4SuvXE/LGThu8vO1ffQGA4NrGs5XgBXAlRVFJ6WLmWiefj7z78A79Hm0qEDGnGCSjmkhQC3CLqU",
+ "5EnVwOoSaLQ0s9X7H/SbENNPMfytOrxqexKIWutEtok65mIdiOZmw1G3a6HJQKv6dscEBBrqm/qeSPtx",
+ "QrUjEAcceClP9RrdBJyGUjo/J8NNN9JVIYAXEz51YUJvc75eVPfcrx6NRyd+yQbT/7aJ4AJa39vngfYG",
+ "7+lJaPcYPfvCd+qptj9E9VYm0qFOP+N0oq1IDbe8RELrspmPc+5tDbHF5O8LSci5gj6C4iUK4ANCC+80",
+ "RJOuBZ/g951+H0SWpuqVb/Gn+8eM+eTVayBLmHfAuiF/yR7r9t1xoWqyGT5GpGuuHir4KNKkzuLAeUrY",
+ "hnFL/oKn3orEeZbWx2tz6/PMKYraI/nw6uNHwi7rzgGp33OfAlW4+HDOotYuaftKJrlDFsdSoM5Kc7Wn",
+ "5bMl1RnM5UCiWHDMENtDI+GNVrlFWl8B/ctQaYKFMehPa0oYMlC/HycIZeUIDHcOJNVTpJDha53Y5oy3",
+ "y8giDbxZjtPHUH1xJExfnAvRq87L/VVeHblu1la5B/qx9+vbILPvN8uD7Yx7bryH83umdvY73tM7YtzC",
+ "lu/0HOXYMyIlwCJVVqGAseTNh+it3owGlrC2caG4Xy3YUHMAsQ8hSh61dckePYS4+4Y/kZ/vaCc58QJ+",
+ "qq6plHzs4ObW34bI6DffVFKrZ3oswwtCqzjJMf5wmO9521a0wo+Duu830Et29HD3/I4vj11184SFk8Yw",
+ "MCtb+KlGZLpZFk4oL9yED4doL6TOuJE+S/8EAAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -1407,7 +1813,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -1425,12 +1831,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -1456,3 +1862,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/strict-server/gorilla/server.go b/internal/test/strict-server/gorilla/server.go
index 669d4da4f4..3d3890d982 100644
--- a/internal/test/strict-server/gorilla/server.go
+++ b/internal/test/strict-server/gorilla/server.go
@@ -1,5 +1,5 @@
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
package api
@@ -98,10 +98,22 @@ func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExample
return HeadersExample200JSONResponse{Body: *request.Body, Headers: HeadersExample200ResponseHeaders{Header1: request.Params.Header1, Header2: *request.Params.Header2}}, nil
}
+func (s StrictServer) NoContentHeaders(ctx context.Context, request NoContentHeadersRequestObject) (NoContentHeadersResponseObject, error) {
+ return NoContentHeaders204Response{}, nil
+}
+
func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) {
return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil
}
+func (s StrictServer) RequiredJSONBody(ctx context.Context, request RequiredJSONBodyRequestObject) (RequiredJSONBodyResponseObject, error) {
+ return RequiredJSONBody200JSONResponse(*request.Body), nil
+}
+
+func (s StrictServer) RequiredTextBody(ctx context.Context, request RequiredTextBodyRequestObject) (RequiredTextBodyResponseObject, error) {
+ return RequiredTextBody200TextResponse(*request.Body), nil
+}
+
func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) {
return ReservedGoKeywordParameters200TextResponse(""), nil
}
diff --git a/internal/test/strict-server/gorilla/types.cfg.yaml b/internal/test/strict-server/gorilla/types.cfg.yaml
index 4ea1d8aa5b..2ed9740ea7 100644
--- a/internal/test/strict-server/gorilla/types.cfg.yaml
+++ b/internal/test/strict-server/gorilla/types.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
models: true
diff --git a/internal/test/strict-server/gorilla/types.gen.go b/internal/test/strict-server/gorilla/types.gen.go
index 6a0de0c970..08ae8548e1 100644
--- a/internal/test/strict-server/gorilla/types.gen.go
+++ b/internal/test/strict-server/gorilla/types.gen.go
@@ -1,8 +1,14 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
+import (
+ "encoding/json"
+
+ "github.com/oapi-codegen/runtime"
+)
+
// Example defines model for example.
type Example struct {
Value *string `json:"value,omitempty"`
@@ -14,6 +20,9 @@ type Reusableresponse = Example
// MultipleRequestAndResponseTypesTextBody defines parameters for MultipleRequestAndResponseTypes.
type MultipleRequestAndResponseTypesTextBody = string
+// RequiredTextBodyTextBody defines parameters for RequiredTextBody.
+type RequiredTextBodyTextBody = string
+
// TextExampleTextBody defines parameters for TextExample.
type TextExampleTextBody = string
@@ -23,12 +32,23 @@ type HeadersExampleParams struct {
Header2 *int `json:"header2,omitempty"`
}
+// UnionExample200JSONResponseBody0 defines parameters for UnionExample.
+type UnionExample200JSONResponseBody0 = string
+
+// UnionExample200JSONResponseBody defines parameters for UnionExample.
+type UnionExample200JSONResponseBody struct {
+ union json.RawMessage
+}
+
// JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType.
type JSONExampleJSONRequestBody = Example
// MultipartExampleMultipartRequestBody defines body for MultipartExample for multipart/form-data ContentType.
type MultipartExampleMultipartRequestBody = Example
+// MultipartRelatedExampleMultipartRequestBody defines body for MultipartRelatedExample for multipart/related ContentType.
+type MultipartRelatedExampleMultipartRequestBody = Example
+
// MultipleRequestAndResponseTypesJSONRequestBody defines body for MultipleRequestAndResponseTypes for application/json ContentType.
type MultipleRequestAndResponseTypesJSONRequestBody = Example
@@ -41,6 +61,12 @@ type MultipleRequestAndResponseTypesMultipartRequestBody = Example
// MultipleRequestAndResponseTypesTextRequestBody defines body for MultipleRequestAndResponseTypes for text/plain ContentType.
type MultipleRequestAndResponseTypesTextRequestBody = MultipleRequestAndResponseTypesTextBody
+// RequiredJSONBodyJSONRequestBody defines body for RequiredJSONBody for application/json ContentType.
+type RequiredJSONBodyJSONRequestBody = Example
+
+// RequiredTextBodyTextRequestBody defines body for RequiredTextBody for text/plain ContentType.
+type RequiredTextBodyTextRequestBody = RequiredTextBodyTextBody
+
// ReusableResponsesJSONRequestBody defines body for ReusableResponses for application/json ContentType.
type ReusableResponsesJSONRequestBody = Example
@@ -55,3 +81,65 @@ type HeadersExampleJSONRequestBody = Example
// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType.
type UnionExampleJSONRequestBody = Example
+
+// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0
+func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) {
+ var body UnionExample200JSONResponseBody0
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example
+func (t UnionExample200JSONResponseBody) AsExample() (Example, error) {
+ var body Example
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example
+func (t *UnionExample200JSONResponseBody) FromExample(v Example) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example
+func (t *UnionExample200JSONResponseBody) MergeExample(v Example) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
diff --git a/internal/test/strict-server/iris/server.cfg.yaml b/internal/test/strict-server/iris/server.cfg.yaml
index e1d7782024..481f842dc6 100644
--- a/internal/test/strict-server/iris/server.cfg.yaml
+++ b/internal/test/strict-server/iris/server.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
iris-server: true
diff --git a/internal/test/strict-server/iris/server.gen.go b/internal/test/strict-server/iris/server.gen.go
index fd67694173..54c401bab9 100644
--- a/internal/test/strict-server/iris/server.gen.go
+++ b/internal/test/strict-server/iris/server.gen.go
@@ -1,16 +1,17 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
- "encoding/json"
+ "errors"
"fmt"
"io"
+ "mime"
"mime/multipart"
"net/http"
"net/url"
@@ -20,7 +21,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/kataras/iris/v12"
"github.com/oapi-codegen/runtime"
- strictiris "github.com/oapi-codegen/runtime/strictmiddleware/iris"
)
// ServerInterface represents all server handlers.
@@ -32,9 +32,21 @@ type ServerInterface interface {
// (POST /multipart)
MultipartExample(ctx iris.Context)
+ // (POST /multipart-related)
+ MultipartRelatedExample(ctx iris.Context)
+
// (POST /multiple)
MultipleRequestAndResponseTypes(ctx iris.Context)
+ // (POST /no-content-headers)
+ NoContentHeaders(ctx iris.Context)
+
+ // (POST /required-json-body)
+ RequiredJSONBody(ctx iris.Context)
+
+ // (POST /required-text-body)
+ RequiredTextBody(ctx iris.Context)
+
// (GET /reserved-go-keyword-parameters/{type})
ReservedGoKeywordParameters(ctx iris.Context, pType string)
@@ -81,6 +93,13 @@ func (w *ServerInterfaceWrapper) MultipartExample(ctx iris.Context) {
w.Handler.MultipartExample(ctx)
}
+// MultipartRelatedExample converts iris context to params.
+func (w *ServerInterfaceWrapper) MultipartRelatedExample(ctx iris.Context) {
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.MultipartRelatedExample(ctx)
+}
+
// MultipleRequestAndResponseTypes converts iris context to params.
func (w *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(ctx iris.Context) {
@@ -88,15 +107,37 @@ func (w *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(ctx iris.Contex
w.Handler.MultipleRequestAndResponseTypes(ctx)
}
+// NoContentHeaders converts iris context to params.
+func (w *ServerInterfaceWrapper) NoContentHeaders(ctx iris.Context) {
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.NoContentHeaders(ctx)
+}
+
+// RequiredJSONBody converts iris context to params.
+func (w *ServerInterfaceWrapper) RequiredJSONBody(ctx iris.Context) {
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.RequiredJSONBody(ctx)
+}
+
+// RequiredTextBody converts iris context to params.
+func (w *ServerInterfaceWrapper) RequiredTextBody(ctx iris.Context) {
+
+ // Invoke the callback with all the unmarshaled arguments
+ w.Handler.RequiredTextBody(ctx)
+}
+
// ReservedGoKeywordParameters converts iris context to params.
func (w *ServerInterfaceWrapper) ReservedGoKeywordParameters(ctx iris.Context) {
var err error
+ _ = err
// ------------- Path parameter "type" -------------
var pType string
- err = runtime.BindStyledParameterWithLocation("simple", false, "type", runtime.ParamLocationPath, ctx.Params().Get("type"), &pType)
+ err = runtime.BindStyledParameterWithOptions("simple", "type", ctx.Params().Get("type"), &pType, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
ctx.StatusCode(http.StatusBadRequest)
ctx.Writef("Invalid format for parameter type: %s", err)
@@ -146,6 +187,7 @@ func (w *ServerInterfaceWrapper) URLEncodedExample(ctx iris.Context) {
func (w *ServerInterfaceWrapper) HeadersExample(ctx iris.Context) {
var err error
+ _ = err
// Parameter object where we will unmarshal all parameters from the context
var params HeadersExampleParams
@@ -161,7 +203,7 @@ func (w *ServerInterfaceWrapper) HeadersExample(ctx iris.Context) {
return
}
- err = runtime.BindStyledParameterWithLocation("simple", false, "header1", runtime.ParamLocationHeader, valueList[0], &Header1)
+ err = runtime.BindStyledParameterWithOptions("simple", "header1", valueList[0], &Header1, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true, Type: "string", Format: ""})
if err != nil {
ctx.StatusCode(http.StatusBadRequest)
ctx.Writef("Invalid format for parameter header1: %s", err)
@@ -184,7 +226,7 @@ func (w *ServerInterfaceWrapper) HeadersExample(ctx iris.Context) {
return
}
- err = runtime.BindStyledParameterWithLocation("simple", false, "header2", runtime.ParamLocationHeader, valueList[0], &Header2)
+ err = runtime.BindStyledParameterWithOptions("simple", "header2", valueList[0], &Header2, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: ""})
if err != nil {
ctx.StatusCode(http.StatusBadRequest)
ctx.Writef("Invalid format for parameter header2: %s", err)
@@ -225,7 +267,11 @@ func RegisterHandlersWithOptions(router *iris.Application, si ServerInterface, o
router.Post(options.BaseURL+"/json", wrapper.JSONExample)
router.Post(options.BaseURL+"/multipart", wrapper.MultipartExample)
+ router.Post(options.BaseURL+"/multipart-related", wrapper.MultipartRelatedExample)
router.Post(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes)
+ router.Post(options.BaseURL+"/no-content-headers", wrapper.NoContentHeaders)
+ router.Post(options.BaseURL+"/required-json-body", wrapper.RequiredJSONBody)
+ router.Post(options.BaseURL+"/required-text-body", wrapper.RequiredTextBody)
router.Get(options.BaseURL+"/reserved-go-keyword-parameters/:type", wrapper.ReservedGoKeywordParameters)
router.Post(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses)
router.Post(options.BaseURL+"/text", wrapper.TextExample)
@@ -319,6 +365,41 @@ func (response MultipartExampledefaultResponse) VisitMultipartExampleResponse(ct
return nil
}
+type MultipartRelatedExampleRequestObject struct {
+ Body *multipart.Reader
+}
+
+type MultipartRelatedExampleResponseObject interface {
+ VisitMultipartRelatedExampleResponse(ctx iris.Context) error
+}
+
+type MultipartRelatedExample200MultipartResponse func(writer *multipart.Writer) error
+
+func (response MultipartRelatedExample200MultipartResponse) VisitMultipartRelatedExampleResponse(ctx iris.Context) error {
+ writer := multipart.NewWriter(ctx.ResponseWriter())
+ ctx.ResponseWriter().Header().Set("Content-Type", mime.FormatMediaType("multipart/related", map[string]string{"boundary": writer.Boundary()}))
+ ctx.StatusCode(200)
+
+ defer writer.Close()
+ return response(writer)
+}
+
+type MultipartRelatedExample400Response = BadrequestResponse
+
+func (response MultipartRelatedExample400Response) VisitMultipartRelatedExampleResponse(ctx iris.Context) error {
+ ctx.StatusCode(400)
+ return nil
+}
+
+type MultipartRelatedExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response MultipartRelatedExampledefaultResponse) VisitMultipartRelatedExampleResponse(ctx iris.Context) error {
+ ctx.StatusCode(response.StatusCode)
+ return nil
+}
+
type MultipleRequestAndResponseTypesRequestObject struct {
JSONBody *MultipleRequestAndResponseTypesJSONRequestBody
FormdataBody *MultipleRequestAndResponseTypesFormdataRequestBody
@@ -401,6 +482,100 @@ func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestA
return nil
}
+type NoContentHeadersRequestObject struct {
+}
+
+type NoContentHeadersResponseObject interface {
+ VisitNoContentHeadersResponse(ctx iris.Context) error
+}
+
+type NoContentHeaders204ResponseHeaders struct {
+ NullableHeader *string
+ OptionalHeader *string
+}
+
+type NoContentHeaders204Response struct {
+ Headers NoContentHeaders204ResponseHeaders
+}
+
+func (response NoContentHeaders204Response) VisitNoContentHeadersResponse(ctx iris.Context) error {
+ if response.Headers.NullableHeader != nil {
+ ctx.ResponseWriter().Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader))
+ }
+ if response.Headers.OptionalHeader != nil {
+ ctx.ResponseWriter().Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader))
+ }
+ ctx.StatusCode(204)
+ return nil
+}
+
+type RequiredJSONBodyRequestObject struct {
+ Body *RequiredJSONBodyJSONRequestBody
+}
+
+type RequiredJSONBodyResponseObject interface {
+ VisitRequiredJSONBodyResponse(ctx iris.Context) error
+}
+
+type RequiredJSONBody200JSONResponse Example
+
+func (response RequiredJSONBody200JSONResponse) VisitRequiredJSONBodyResponse(ctx iris.Context) error {
+ ctx.ResponseWriter().Header().Set("Content-Type", "application/json")
+ ctx.StatusCode(200)
+
+ return ctx.JSON(&response)
+}
+
+type RequiredJSONBody400Response = BadrequestResponse
+
+func (response RequiredJSONBody400Response) VisitRequiredJSONBodyResponse(ctx iris.Context) error {
+ ctx.StatusCode(400)
+ return nil
+}
+
+type RequiredJSONBodydefaultResponse struct {
+ StatusCode int
+}
+
+func (response RequiredJSONBodydefaultResponse) VisitRequiredJSONBodyResponse(ctx iris.Context) error {
+ ctx.StatusCode(response.StatusCode)
+ return nil
+}
+
+type RequiredTextBodyRequestObject struct {
+ Body *RequiredTextBodyTextRequestBody
+}
+
+type RequiredTextBodyResponseObject interface {
+ VisitRequiredTextBodyResponse(ctx iris.Context) error
+}
+
+type RequiredTextBody200TextResponse string
+
+func (response RequiredTextBody200TextResponse) VisitRequiredTextBodyResponse(ctx iris.Context) error {
+ ctx.ResponseWriter().Header().Set("Content-Type", "text/plain")
+ ctx.StatusCode(200)
+
+ _, err := ctx.WriteString(string(response))
+ return err
+}
+
+type RequiredTextBody400Response = BadrequestResponse
+
+func (response RequiredTextBody400Response) VisitRequiredTextBodyResponse(ctx iris.Context) error {
+ ctx.StatusCode(400)
+ return nil
+}
+
+type RequiredTextBodydefaultResponse struct {
+ StatusCode int
+}
+
+func (response RequiredTextBodydefaultResponse) VisitRequiredTextBodyResponse(ctx iris.Context) error {
+ ctx.StatusCode(response.StatusCode)
+ return nil
+}
+
type ReservedGoKeywordParametersRequestObject struct {
Type string `json:"type"`
}
@@ -640,8 +815,10 @@ type HeadersExampleResponseObject interface {
}
type HeadersExample200ResponseHeaders struct {
- Header1 string
- Header2 int
+ Header1 string
+ Header2 int
+ NullableHeader *string
+ OptionalHeader *string
}
type HeadersExample200JSONResponse struct {
@@ -652,6 +829,12 @@ type HeadersExample200JSONResponse struct {
func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(ctx iris.Context) error {
ctx.ResponseWriter().Header().Set("header1", fmt.Sprint(response.Headers.Header1))
ctx.ResponseWriter().Header().Set("header2", fmt.Sprint(response.Headers.Header2))
+ if response.Headers.NullableHeader != nil {
+ ctx.ResponseWriter().Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader))
+ }
+ if response.Headers.OptionalHeader != nil {
+ ctx.ResponseWriter().Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader))
+ }
ctx.ResponseWriter().Header().Set("Content-Type", "application/json")
ctx.StatusCode(200)
@@ -702,9 +885,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion
}
type UnionExample200JSONResponse struct {
- Body struct {
- union json.RawMessage
- }
+ Body UnionExample200JSONResponseBody
Headers UnionExample200ResponseHeaders
}
@@ -742,9 +923,21 @@ type StrictServerInterface interface {
// (POST /multipart)
MultipartExample(ctx context.Context, request MultipartExampleRequestObject) (MultipartExampleResponseObject, error)
+ // (POST /multipart-related)
+ MultipartRelatedExample(ctx context.Context, request MultipartRelatedExampleRequestObject) (MultipartRelatedExampleResponseObject, error)
+
// (POST /multiple)
MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error)
+ // (POST /no-content-headers)
+ NoContentHeaders(ctx context.Context, request NoContentHeadersRequestObject) (NoContentHeadersResponseObject, error)
+
+ // (POST /required-json-body)
+ RequiredJSONBody(ctx context.Context, request RequiredJSONBodyRequestObject) (RequiredJSONBodyResponseObject, error)
+
+ // (POST /required-text-body)
+ RequiredTextBody(ctx context.Context, request RequiredTextBodyRequestObject) (RequiredTextBodyResponseObject, error)
+
// (GET /reserved-go-keyword-parameters/{type})
ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error)
@@ -770,8 +963,8 @@ type StrictServerInterface interface {
UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error)
}
-type StrictHandlerFunc = strictiris.StrictIrisHandlerFunc
-type StrictMiddlewareFunc = strictiris.StrictIrisMiddlewareFunc
+type StrictHandlerFunc func(ctx iris.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
return &strictHandler{ssi: ssi, middlewares: middlewares}
@@ -788,10 +981,13 @@ func (sh *strictHandler) JSONExample(ctx iris.Context) {
var body JSONExampleJSONRequestBody
if err := ctx.ReadJSON(&body); err != nil {
- ctx.StopWithError(http.StatusBadRequest, err)
- return
+ if !errors.Is(err, io.EOF) {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
return sh.ssi.JSONExample(ctx, request.(JSONExampleRequestObject))
@@ -850,6 +1046,43 @@ func (sh *strictHandler) MultipartExample(ctx iris.Context) {
}
}
+// MultipartRelatedExample operation middleware
+func (sh *strictHandler) MultipartRelatedExample(ctx iris.Context) {
+ var request MultipartRelatedExampleRequestObject
+
+ if _, params, err := mime.ParseMediaType(ctx.Request().Header.Get("Content-Type")); err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ } else if boundary := params["boundary"]; boundary == "" {
+ ctx.StopWithError(http.StatusBadRequest, http.ErrMissingBoundary)
+ return
+ } else {
+ request.Body = multipart.NewReader(ctx.Request().Body, boundary)
+ }
+
+ handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.MultipartRelatedExample(ctx, request.(MultipartRelatedExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "MultipartRelatedExample")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ } else if validResponse, ok := response.(MultipartRelatedExampleResponseObject); ok {
+ if err := validResponse.VisitMultipartRelatedExampleResponse(ctx); err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else if response != nil {
+ ctx.Writef("Unexpected response type: %T", response)
+ return
+ }
+}
+
// MultipleRequestAndResponseTypes operation middleware
func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx iris.Context) {
var request MultipleRequestAndResponseTypesRequestObject
@@ -858,10 +1091,13 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx iris.Context) {
var body MultipleRequestAndResponseTypesJSONRequestBody
if err := ctx.ReadJSON(&body); err != nil {
- ctx.StopWithError(http.StatusBadRequest, err)
- return
+ if !errors.Is(err, io.EOF) {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else {
+ request.JSONBody = &body
}
- request.JSONBody = &body
}
if strings.HasPrefix(ctx.GetHeader("Content-Type"), "application/x-www-form-urlencoded") {
if err := ctx.Request().ParseForm(); err != nil {
@@ -892,8 +1128,10 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx iris.Context) {
ctx.StopWithError(http.StatusBadRequest, err)
return
}
- body := MultipleRequestAndResponseTypesTextRequestBody(data)
- request.TextBody = &body
+ if len(data) > 0 {
+ body := MultipleRequestAndResponseTypesTextRequestBody(data)
+ request.TextBody = &body
+ }
}
handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
@@ -919,6 +1157,102 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx iris.Context) {
}
}
+// NoContentHeaders operation middleware
+func (sh *strictHandler) NoContentHeaders(ctx iris.Context) {
+ var request NoContentHeadersRequestObject
+
+ handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.NoContentHeaders(ctx, request.(NoContentHeadersRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "NoContentHeaders")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ } else if validResponse, ok := response.(NoContentHeadersResponseObject); ok {
+ if err := validResponse.VisitNoContentHeadersResponse(ctx); err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else if response != nil {
+ ctx.Writef("Unexpected response type: %T", response)
+ return
+ }
+}
+
+// RequiredJSONBody operation middleware
+func (sh *strictHandler) RequiredJSONBody(ctx iris.Context) {
+ var request RequiredJSONBodyRequestObject
+
+ var body RequiredJSONBodyJSONRequestBody
+ if err := ctx.ReadJSON(&body); err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ request.Body = &body
+
+ handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.RequiredJSONBody(ctx, request.(RequiredJSONBodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "RequiredJSONBody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ } else if validResponse, ok := response.(RequiredJSONBodyResponseObject); ok {
+ if err := validResponse.VisitRequiredJSONBodyResponse(ctx); err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else if response != nil {
+ ctx.Writef("Unexpected response type: %T", response)
+ return
+ }
+}
+
+// RequiredTextBody operation middleware
+func (sh *strictHandler) RequiredTextBody(ctx iris.Context) {
+ var request RequiredTextBodyRequestObject
+
+ data, err := io.ReadAll(ctx.Request().Body)
+ if err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ body := RequiredTextBodyTextRequestBody(data)
+ request.Body = &body
+
+ handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
+ return sh.ssi.RequiredTextBody(ctx, request.(RequiredTextBodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "RequiredTextBody")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ } else if validResponse, ok := response.(RequiredTextBodyResponseObject); ok {
+ if err := validResponse.VisitRequiredTextBodyResponse(ctx); err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else if response != nil {
+ ctx.Writef("Unexpected response type: %T", response)
+ return
+ }
+}
+
// ReservedGoKeywordParameters operation middleware
func (sh *strictHandler) ReservedGoKeywordParameters(ctx iris.Context, pType string) {
var request ReservedGoKeywordParametersRequestObject
@@ -954,10 +1288,13 @@ func (sh *strictHandler) ReusableResponses(ctx iris.Context) {
var body ReusableResponsesJSONRequestBody
if err := ctx.ReadJSON(&body); err != nil {
- ctx.StopWithError(http.StatusBadRequest, err)
- return
+ if !errors.Is(err, io.EOF) {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
return sh.ssi.ReusableResponses(ctx, request.(ReusableResponsesRequestObject))
@@ -991,8 +1328,10 @@ func (sh *strictHandler) TextExample(ctx iris.Context) {
ctx.StopWithError(http.StatusBadRequest, err)
return
}
- body := TextExampleTextRequestBody(data)
- request.Body = &body
+ if len(data) > 0 {
+ body := TextExampleTextRequestBody(data)
+ request.Body = &body
+ }
handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
return sh.ssi.TextExample(ctx, request.(TextExampleRequestObject))
@@ -1123,10 +1462,13 @@ func (sh *strictHandler) HeadersExample(ctx iris.Context, params HeadersExampleP
var body HeadersExampleJSONRequestBody
if err := ctx.ReadJSON(&body); err != nil {
- ctx.StopWithError(http.StatusBadRequest, err)
- return
+ if !errors.Is(err, io.EOF) {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
return sh.ssi.HeadersExample(ctx, request.(HeadersExampleRequestObject))
@@ -1157,10 +1499,13 @@ func (sh *strictHandler) UnionExample(ctx iris.Context) {
var body UnionExampleJSONRequestBody
if err := ctx.ReadJSON(&body); err != nil {
- ctx.StopWithError(http.StatusBadRequest, err)
- return
+ if !errors.Is(err, io.EOF) {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ } else {
+ request.Body = &body
}
- request.Body = &body
handler := func(ctx iris.Context, request interface{}) (interface{}, error) {
return sh.ssi.UnionExample(ctx, request.(UnionExampleRequestObject))
@@ -1185,43 +1530,49 @@ func (sh *strictHandler) UnionExample(ctx iris.Context) {
}
}
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-
- "H4sIAAAAAAAC/+xYS2/jNhD+KwTb01aynGxOunWDxbbdtimc5FTkQIsjm7sSyQ5HVgzD/72gKL9ixbW3",
- "fhRBb3oMvxl+8+BwZjwzpTUaNDmezjiCs0Y7aF6GQiL8VYEj/ybBZagsKaN5yj8IOWj/zSOOUDkxLGCx",
- "3MtnRhPoZqmwtlCZ8EuTL86vn3GXjaEU/ul7hJyn/LtkZUoS/roEnkVpC+Dz+Tx6YcHdZx7xMQgJ2Fgb",
- "Hq82sWlqgafcESo94h4kiF13iilNMAL02rxoa4QXWNiRzrhFYwFJBY4moqigW1P7xQy/QEZhB0rnZpvL",
- "W6NJKO2YVHkOCJpYSx7zGI65ylqDBJINp8xryIg5wAkgjzgp8obx+/XvrDXY8YhPAF1QdNXr9/reX8aC",
- "FlbxlL9vPkXcCho3G1o6yJouv/9yf/c7U46JikwpSGWiKKasFOjGogDJlCbjTawycj3eaMLG8T/LdvXH",
- "lkofNU0AfTByeoqAaeJyLZyv+/0zxeU84jdBWRfG0qhkLcEamFxURQfnj/qrNrVmgGiw3VlSVgUpK5DW",
- "fbXJ9m8LkX0oX+IlucEyloLEiVg/lqaLEt/Wgs4cuR+b2rGxqRkZJkEUrFY0ZouFL5JbaSaYU3pUAFsY",
- "FXV6soC25P6o5aDdy4PHOHkuRRsoz3Fd13HjvAoL0JmRIL8NVpViBInVo83lHlsQT/lwSj5st4vrkYIo",
- "4gTPlNhCKL375DhTOfmf6aMldkhXhOZElPHIxF9hWhuUsRUoSiBAl8y89rkHHkFHKv+xlGSZ0GwITIsS",
- "JBM5AbJPhrWQbitlB63eT+ZzEFlBNcft8iX9c8Y9Jc0RzCPuFfA0sBLyWqF3OmEF0Q7anv4xPv+VAxZs",
- "hkYv3lDVXQYXJWpJHULufEns8lwHf0HTYE3iMg3D7ojban3PcQZ5T75+7j/A815H/hFL37lz+1DCqvDx",
- "dc7aVfvQ9o2VdA8WJ0qCSUp7cyDyxUh1FjKVK5Bxu4s42PZaSbg1OkOgzRbIXye0IbYE87ccGgMLDETM",
- "GVYDKytHzArnmKKmihQq3JQkbBWPx5Vlt0HTw6qc7vLquxP59N2lPHrTvzp8yfsTx81GK/NKPg5+/Rhk",
- "Dr0vHq1nOrDjO57eC6Wzv6TEawOV7hT+KQiszvQM1MR3RFoyBKpQg2QTJRZDgK3cbAFWbu3qhYIZq25o",
- "Mdw5pCGKdmJd82jXAOjpDY8nTjk2O1ecVlrtGlM9+t+s7aFfng3K6P/oEEoUBKgFqQn8cJwb5DaK0XCX",
- "N5n2wsvRnhqe3l5UzSMe5qahBFVY+DpBZNMkCfPWnqvFaATYUyYRVnkW/g4AAP//Pk3lbjwXAAA=",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "7Fnbcts2E36VHfz/RZuSpuL4SndNJpO2aZOObF91fAERKwkJCSDAUrJGo5k+RJ+wT9IBAepI21KqgyfT",
+ "O4ncE/fbXX5LzFiuS6MVKnKsO2MWndHKYf2nz4XFLxU68v8EutxKQ1Ir1mWvuejFe/OEWawc7xfYqHv5",
+ "XCtCVatyYwqZc6+afXJef8ZcPsKS+1//tzhgXfa/bBlKFu66DO95aQpk8/k82Yjg43uWsBFygbaONvx8",
+ "GZ7iSyUtCtYlW2Gy4oumBlmXObJSDZk3GtQud1KTinCI1kfjVWOQXqCJsztjxmqDlmTI4ZgXFbZ7jld0",
+ "/xPmFJ5QqoHezvUbrYhL5UDIwQAtKoKYXPA2HLjKGG0JBfSn4D3kBA7tGC1LGEnygbHr1esQA3YsYWO0",
+ "Ljh6edG56Hg8tUHFjWRd9qq+lDDDaVQ/0AJAo9vq4pfrjx9AOuAV6ZKTzHlRTKHk1o14gQKkIu1DrHJy",
+ "F6z2ZOvC+FlE7bcxlQmLxfdai+kxCqqu25Vyv+x0TlS384RdBWdtNhZBZSsNWJsZ8Kpoyfmt+qz0RAFa",
+ "q218sqysCpKGW1rFaj3bvzUiu6R8YS8baFumghM/UtYP5enciU8tFpz8OHkSgF6Q3A+HFfNHReHf+Dkr",
+ "BnEet86p65GeOBjpCZAGgbyAiaQRNIobA1Yq4OCkGhYITVBJK5gFxtfij0r04rPceBtHn2fJmpX7dDKZ",
+ "pHUDVbZAlWvxdRAmTJZ8iJlRw3V1b5sT67L+lHzJbr/gDtTICSO8p8wUXG4kZtPliUb6f5k+WGOHdlU6",
+ "jRClK4SuvXE/LGThu8vO1ffQGA4NrGs5XgBXAlRVFJ6WLmWiefj7z78A79Hm0qEDGnGCSjmkhQC3CLqU",
+ "5EnVwOoSaLQ0s9X7H/SbENNPMfytOrxqexKIWutEtok65mIdiOZmw1G3a6HJQKv6dscEBBrqm/qeSPtx",
+ "QrUjEAcceClP9RrdBJyGUjo/J8NNN9JVIYAXEz51YUJvc75eVPfcrx6NRyd+yQbT/7aJ4AJa39vngfYG",
+ "7+lJaPcYPfvCd+qptj9E9VYm0qFOP+N0oq1IDbe8RELrspmPc+5tDbHF5O8LSci5gj6C4iUK4ANCC+80",
+ "RJOuBZ/g951+H0SWpuqVb/Gn+8eM+eTVayBLmHfAuiF/yR7r9t1xoWqyGT5GpGuuHir4KNKkzuLAeUrY",
+ "hnFL/oKn3orEeZbWx2tz6/PMKYraI/nw6uNHwi7rzgGp33OfAlW4+HDOotYuaftKJrlDFsdSoM5Kc7Wn",
+ "5bMl1RnM5UCiWHDMENtDI+GNVrlFWl8B/ctQaYKFMehPa0oYMlC/HycIZeUIDHcOJNVTpJDha53Y5oy3",
+ "y8giDbxZjtPHUH1xJExfnAvRq87L/VVeHblu1la5B/qx9+vbILPvN8uD7Yx7bryH83umdvY73tM7YtzC",
+ "lu/0HOXYMyIlwCJVVqGAseTNh+it3owGlrC2caG4Xy3YUHMAsQ8hSh61dckePYS4+4Y/kZ/vaCc58QJ+",
+ "qq6plHzs4ObW34bI6DffVFKrZ3oswwtCqzjJMf5wmO9521a0wo+Duu830Et29HD3/I4vj11184SFk8Yw",
+ "MCtb+KlGZLpZFk4oL9yED4doL6TOuJE+S/8EAAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -1229,7 +1580,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -1247,12 +1598,12 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -1278,3 +1629,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/strict-server/iris/server.go b/internal/test/strict-server/iris/server.go
index c59b796476..12b000d733 100644
--- a/internal/test/strict-server/iris/server.go
+++ b/internal/test/strict-server/iris/server.go
@@ -1,5 +1,5 @@
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
-//go:generate go run github.com/deepmap/oapi-codegen/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
package api
@@ -40,6 +40,30 @@ func (s StrictServer) MultipartExample(ctx context.Context, request MultipartExa
}), nil
}
+func (s StrictServer) MultipartRelatedExample(ctx context.Context, request MultipartRelatedExampleRequestObject) (MultipartRelatedExampleResponseObject, error) {
+ return MultipartRelatedExample200MultipartResponse(func(writer *multipart.Writer) error {
+ for {
+ part, err := request.Body.NextPart()
+ if err == io.EOF {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ w, err := writer.CreatePart(part.Header)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(w, part)
+ if err != nil {
+ return err
+ }
+ if err = part.Close(); err != nil {
+ return err
+ }
+ }
+ }), nil
+}
+
func (s StrictServer) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error) {
switch {
case request.Body != nil:
@@ -97,10 +121,22 @@ func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExample
return HeadersExample200JSONResponse{Body: *request.Body, Headers: HeadersExample200ResponseHeaders{Header1: request.Params.Header1, Header2: *request.Params.Header2}}, nil
}
+func (s StrictServer) NoContentHeaders(ctx context.Context, request NoContentHeadersRequestObject) (NoContentHeadersResponseObject, error) {
+ return NoContentHeaders204Response{}, nil
+}
+
func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) {
return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil
}
+func (s StrictServer) RequiredJSONBody(ctx context.Context, request RequiredJSONBodyRequestObject) (RequiredJSONBodyResponseObject, error) {
+ return RequiredJSONBody200JSONResponse(*request.Body), nil
+}
+
+func (s StrictServer) RequiredTextBody(ctx context.Context, request RequiredTextBodyRequestObject) (RequiredTextBodyResponseObject, error) {
+ return RequiredTextBody200TextResponse(*request.Body), nil
+}
+
func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) {
return ReservedGoKeywordParameters200TextResponse(""), nil
}
diff --git a/internal/test/strict-server/iris/types.cfg.yaml b/internal/test/strict-server/iris/types.cfg.yaml
index 4ea1d8aa5b..2ed9740ea7 100644
--- a/internal/test/strict-server/iris/types.cfg.yaml
+++ b/internal/test/strict-server/iris/types.cfg.yaml
@@ -1,3 +1,4 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
package: api
generate:
models: true
diff --git a/internal/test/strict-server/iris/types.gen.go b/internal/test/strict-server/iris/types.gen.go
index 6a0de0c970..08ae8548e1 100644
--- a/internal/test/strict-server/iris/types.gen.go
+++ b/internal/test/strict-server/iris/types.gen.go
@@ -1,8 +1,14 @@
// Package api provides primitives to interact with the openapi HTTP API.
//
-// Code generated by github.com/deepmap/oapi-codegen version v0.0.0-00010101000000-000000000000 DO NOT EDIT.
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
package api
+import (
+ "encoding/json"
+
+ "github.com/oapi-codegen/runtime"
+)
+
// Example defines model for example.
type Example struct {
Value *string `json:"value,omitempty"`
@@ -14,6 +20,9 @@ type Reusableresponse = Example
// MultipleRequestAndResponseTypesTextBody defines parameters for MultipleRequestAndResponseTypes.
type MultipleRequestAndResponseTypesTextBody = string
+// RequiredTextBodyTextBody defines parameters for RequiredTextBody.
+type RequiredTextBodyTextBody = string
+
// TextExampleTextBody defines parameters for TextExample.
type TextExampleTextBody = string
@@ -23,12 +32,23 @@ type HeadersExampleParams struct {
Header2 *int `json:"header2,omitempty"`
}
+// UnionExample200JSONResponseBody0 defines parameters for UnionExample.
+type UnionExample200JSONResponseBody0 = string
+
+// UnionExample200JSONResponseBody defines parameters for UnionExample.
+type UnionExample200JSONResponseBody struct {
+ union json.RawMessage
+}
+
// JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType.
type JSONExampleJSONRequestBody = Example
// MultipartExampleMultipartRequestBody defines body for MultipartExample for multipart/form-data ContentType.
type MultipartExampleMultipartRequestBody = Example
+// MultipartRelatedExampleMultipartRequestBody defines body for MultipartRelatedExample for multipart/related ContentType.
+type MultipartRelatedExampleMultipartRequestBody = Example
+
// MultipleRequestAndResponseTypesJSONRequestBody defines body for MultipleRequestAndResponseTypes for application/json ContentType.
type MultipleRequestAndResponseTypesJSONRequestBody = Example
@@ -41,6 +61,12 @@ type MultipleRequestAndResponseTypesMultipartRequestBody = Example
// MultipleRequestAndResponseTypesTextRequestBody defines body for MultipleRequestAndResponseTypes for text/plain ContentType.
type MultipleRequestAndResponseTypesTextRequestBody = MultipleRequestAndResponseTypesTextBody
+// RequiredJSONBodyJSONRequestBody defines body for RequiredJSONBody for application/json ContentType.
+type RequiredJSONBodyJSONRequestBody = Example
+
+// RequiredTextBodyTextRequestBody defines body for RequiredTextBody for text/plain ContentType.
+type RequiredTextBodyTextRequestBody = RequiredTextBodyTextBody
+
// ReusableResponsesJSONRequestBody defines body for ReusableResponses for application/json ContentType.
type ReusableResponsesJSONRequestBody = Example
@@ -55,3 +81,65 @@ type HeadersExampleJSONRequestBody = Example
// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType.
type UnionExampleJSONRequestBody = Example
+
+// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0
+func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) {
+ var body UnionExample200JSONResponseBody0
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example
+func (t UnionExample200JSONResponseBody) AsExample() (Example, error) {
+ var body Example
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example
+func (t *UnionExample200JSONResponseBody) FromExample(v Example) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example
+func (t *UnionExample200JSONResponseBody) MergeExample(v Example) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
diff --git a/internal/test/strict-server/stdhttp/server.cfg.yaml b/internal/test/strict-server/stdhttp/server.cfg.yaml
new file mode 100644
index 0000000000..fb4ed1a461
--- /dev/null
+++ b/internal/test/strict-server/stdhttp/server.cfg.yaml
@@ -0,0 +1,7 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: api
+generate:
+ std-http-server: true
+ strict-server: true
+ embedded-spec: true
+output: server.gen.go
diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go
new file mode 100644
index 0000000000..f3073a462b
--- /dev/null
+++ b/internal/test/strict-server/stdhttp/server.gen.go
@@ -0,0 +1,1877 @@
+//go:build go1.22
+
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "bytes"
+ "compress/flate"
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "mime"
+ "mime/multipart"
+ "net/http"
+ "net/url"
+ "path"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/oapi-codegen/runtime"
+)
+
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+
+ // (POST /json)
+ JSONExample(w http.ResponseWriter, r *http.Request)
+
+ // (POST /multipart)
+ MultipartExample(w http.ResponseWriter, r *http.Request)
+
+ // (POST /multipart-related)
+ MultipartRelatedExample(w http.ResponseWriter, r *http.Request)
+
+ // (POST /multiple)
+ MultipleRequestAndResponseTypes(w http.ResponseWriter, r *http.Request)
+
+ // (POST /no-content-headers)
+ NoContentHeaders(w http.ResponseWriter, r *http.Request)
+
+ // (POST /required-json-body)
+ RequiredJSONBody(w http.ResponseWriter, r *http.Request)
+
+ // (POST /required-text-body)
+ RequiredTextBody(w http.ResponseWriter, r *http.Request)
+
+ // (GET /reserved-go-keyword-parameters/{type})
+ ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request, pType string)
+
+ // (POST /reusable-responses)
+ ReusableResponses(w http.ResponseWriter, r *http.Request)
+
+ // (POST /text)
+ TextExample(w http.ResponseWriter, r *http.Request)
+
+ // (POST /unknown)
+ UnknownExample(w http.ResponseWriter, r *http.Request)
+
+ // (POST /unspecified-content-type)
+ UnspecifiedContentType(w http.ResponseWriter, r *http.Request)
+
+ // (POST /urlencoded)
+ URLEncodedExample(w http.ResponseWriter, r *http.Request)
+
+ // (POST /with-headers)
+ HeadersExample(w http.ResponseWriter, r *http.Request, params HeadersExampleParams)
+
+ // (POST /with-union)
+ UnionExample(w http.ResponseWriter, r *http.Request)
+}
+
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+// JSONExample operation middleware
+func (siw *ServerInterfaceWrapper) JSONExample(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.JSONExample(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// MultipartExample operation middleware
+func (siw *ServerInterfaceWrapper) MultipartExample(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.MultipartExample(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// MultipartRelatedExample operation middleware
+func (siw *ServerInterfaceWrapper) MultipartRelatedExample(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.MultipartRelatedExample(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// MultipleRequestAndResponseTypes operation middleware
+func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.MultipleRequestAndResponseTypes(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// NoContentHeaders operation middleware
+func (siw *ServerInterfaceWrapper) NoContentHeaders(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.NoContentHeaders(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// RequiredJSONBody operation middleware
+func (siw *ServerInterfaceWrapper) RequiredJSONBody(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.RequiredJSONBody(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// RequiredTextBody operation middleware
+func (siw *ServerInterfaceWrapper) RequiredTextBody(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.RequiredTextBody(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// ReservedGoKeywordParameters operation middleware
+func (siw *ServerInterfaceWrapper) ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // ------------- Path parameter "type" -------------
+ var pType string
+
+ err = runtime.BindStyledParameterWithOptions("simple", "type", r.PathValue("type"), &pType, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "type", Err: err})
+ return
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.ReservedGoKeywordParameters(w, r, pType)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// ReusableResponses operation middleware
+func (siw *ServerInterfaceWrapper) ReusableResponses(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.ReusableResponses(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// TextExample operation middleware
+func (siw *ServerInterfaceWrapper) TextExample(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.TextExample(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// UnknownExample operation middleware
+func (siw *ServerInterfaceWrapper) UnknownExample(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.UnknownExample(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// UnspecifiedContentType operation middleware
+func (siw *ServerInterfaceWrapper) UnspecifiedContentType(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.UnspecifiedContentType(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// URLEncodedExample operation middleware
+func (siw *ServerInterfaceWrapper) URLEncodedExample(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.URLEncodedExample(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// HeadersExample operation middleware
+func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http.Request) {
+
+ var err error
+ _ = err
+
+ // Parameter object where we will unmarshal all parameters from the context
+ var params HeadersExampleParams
+
+ headers := r.Header
+
+ // ------------- Required header parameter "header1" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("header1")]; found {
+ var Header1 string
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "header1", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "header1", valueList[0], &Header1, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true, Type: "string", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "header1", Err: err})
+ return
+ }
+
+ params.Header1 = Header1
+
+ } else {
+ err := fmt.Errorf("Header parameter header1 is required, but not found")
+ siw.ErrorHandlerFunc(w, r, &RequiredHeaderError{ParamName: "header1", Err: err})
+ return
+ }
+
+ // ------------- Optional header parameter "header2" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("header2")]; found {
+ var Header2 int
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "header2", Count: n})
+ return
+ }
+
+ err = runtime.BindStyledParameterWithOptions("simple", "header2", valueList[0], &Header2, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false, Type: "integer", Format: ""})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "header2", Err: err})
+ return
+ }
+
+ params.Header2 = &Header2
+
+ }
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.HeadersExample(w, r, params)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+// UnionExample operation middleware
+func (siw *ServerInterfaceWrapper) UnionExample(w http.ResponseWriter, r *http.Request) {
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.UnionExample(w, r)
+ }))
+
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+
+ handler.ServeHTTP(w, r)
+}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
+
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{})
+}
+
+// ServeMux is an abstraction of [http.ServeMux].
+type ServeMux interface {
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+ http.Handler
+}
+
+type StdHTTPServerOptions struct {
+ BaseURL string
+ BaseRouter ServeMux
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseRouter: m,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{
+ BaseURL: baseURL,
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/json", wrapper.JSONExample)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/multipart", wrapper.MultipartExample)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/multipart-related", wrapper.MultipartRelatedExample)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/no-content-headers", wrapper.NoContentHeaders)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/required-json-body", wrapper.RequiredJSONBody)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/required-text-body", wrapper.RequiredTextBody)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/reserved-go-keyword-parameters/{type}", wrapper.ReservedGoKeywordParameters)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/reusable-responses", wrapper.ReusableResponses)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/text", wrapper.TextExample)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/unknown", wrapper.UnknownExample)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/urlencoded", wrapper.URLEncodedExample)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/with-headers", wrapper.HeadersExample)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/with-union", wrapper.UnionExample)
+
+ return m
+}
+
+type BadrequestResponse struct {
+}
+
+type ReusableresponseResponseHeaders struct {
+ Header1 string
+ Header2 int
+}
+type ReusableresponseJSONResponse struct {
+ Body Example
+
+ Headers ReusableresponseResponseHeaders
+}
+
+type JSONExampleRequestObject struct {
+ Body *JSONExampleJSONRequestBody
+}
+
+type JSONExampleResponseObject interface {
+ VisitJSONExampleResponse(w http.ResponseWriter) error
+}
+
+type JSONExample200JSONResponse Example
+
+func (response JSONExample200JSONResponse) VisitJSONExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type JSONExample400Response = BadrequestResponse
+
+func (response JSONExample400Response) VisitJSONExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type JSONExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response JSONExampledefaultResponse) VisitJSONExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type MultipartExampleRequestObject struct {
+ Body *multipart.Reader
+}
+
+type MultipartExampleResponseObject interface {
+ VisitMultipartExampleResponse(w http.ResponseWriter) error
+}
+
+type MultipartExample200MultipartResponse func(writer *multipart.Writer) error
+
+func (response MultipartExample200MultipartResponse) VisitMultipartExampleResponse(w http.ResponseWriter) error {
+ writer := multipart.NewWriter(w)
+
+ w.Header().Set("Content-Type", writer.FormDataContentType())
+ w.WriteHeader(200)
+
+ defer writer.Close()
+ return response(writer)
+}
+
+type MultipartExample400Response = BadrequestResponse
+
+func (response MultipartExample400Response) VisitMultipartExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type MultipartExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response MultipartExampledefaultResponse) VisitMultipartExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type MultipartRelatedExampleRequestObject struct {
+ Body *multipart.Reader
+}
+
+type MultipartRelatedExampleResponseObject interface {
+ VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error
+}
+
+type MultipartRelatedExample200MultipartResponse func(writer *multipart.Writer) error
+
+func (response MultipartRelatedExample200MultipartResponse) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ writer := multipart.NewWriter(w)
+
+ w.Header().Set("Content-Type", mime.FormatMediaType("multipart/related", map[string]string{"boundary": writer.Boundary()}))
+ w.WriteHeader(200)
+
+ defer writer.Close()
+ return response(writer)
+}
+
+type MultipartRelatedExample400Response = BadrequestResponse
+
+func (response MultipartRelatedExample400Response) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type MultipartRelatedExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response MultipartRelatedExampledefaultResponse) VisitMultipartRelatedExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type MultipleRequestAndResponseTypesRequestObject struct {
+ JSONBody *MultipleRequestAndResponseTypesJSONRequestBody
+ FormdataBody *MultipleRequestAndResponseTypesFormdataRequestBody
+ Body io.Reader
+ MultipartBody *multipart.Reader
+ TextBody *MultipleRequestAndResponseTypesTextRequestBody
+}
+
+type MultipleRequestAndResponseTypesResponseObject interface {
+ VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error
+}
+
+type MultipleRequestAndResponseTypes200JSONResponse Example
+
+func (response MultipleRequestAndResponseTypes200JSONResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type MultipleRequestAndResponseTypes200FormdataResponse Example
+
+func (response MultipleRequestAndResponseTypes200FormdataResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
+ form, err := runtime.MarshalForm(response, nil)
+ if err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
+ w.WriteHeader(200)
+ _, err = w.Write([]byte(form.Encode()))
+ return err
+}
+
+type MultipleRequestAndResponseTypes200ImagepngResponse struct {
+ Body io.Reader
+ ContentLength int64
+}
+
+func (response MultipleRequestAndResponseTypes200ImagepngResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "image/png")
+ if response.ContentLength != 0 {
+ w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
+ }
+ w.WriteHeader(200)
+
+ if closer, ok := response.Body.(io.ReadCloser); ok {
+ defer closer.Close()
+ }
+ _, err := io.Copy(w, response.Body)
+ return err
+}
+
+type MultipleRequestAndResponseTypes200MultipartResponse func(writer *multipart.Writer) error
+
+func (response MultipleRequestAndResponseTypes200MultipartResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+ writer := multipart.NewWriter(w)
+
+ w.Header().Set("Content-Type", writer.FormDataContentType())
+ w.WriteHeader(200)
+
+ defer writer.Close()
+ return response(writer)
+}
+
+type MultipleRequestAndResponseTypes200TextResponse string
+
+func (response MultipleRequestAndResponseTypes200TextResponse) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "text/plain")
+ w.WriteHeader(200)
+
+ _, err := w.Write([]byte(response))
+ return err
+}
+
+type MultipleRequestAndResponseTypes400Response = BadrequestResponse
+
+func (response MultipleRequestAndResponseTypes400Response) VisitMultipleRequestAndResponseTypesResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type NoContentHeadersRequestObject struct {
+}
+
+type NoContentHeadersResponseObject interface {
+ VisitNoContentHeadersResponse(w http.ResponseWriter) error
+}
+
+type NoContentHeaders204ResponseHeaders struct {
+ NullableHeader *string
+ OptionalHeader *string
+}
+
+type NoContentHeaders204Response struct {
+ Headers NoContentHeaders204ResponseHeaders
+}
+
+func (response NoContentHeaders204Response) VisitNoContentHeadersResponse(w http.ResponseWriter) error {
+ if response.Headers.NullableHeader != nil {
+ w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader))
+ }
+ if response.Headers.OptionalHeader != nil {
+ w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader))
+ }
+ w.WriteHeader(204)
+ return nil
+}
+
+type RequiredJSONBodyRequestObject struct {
+ Body *RequiredJSONBodyJSONRequestBody
+}
+
+type RequiredJSONBodyResponseObject interface {
+ VisitRequiredJSONBodyResponse(w http.ResponseWriter) error
+}
+
+type RequiredJSONBody200JSONResponse Example
+
+func (response RequiredJSONBody200JSONResponse) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type RequiredJSONBody400Response = BadrequestResponse
+
+func (response RequiredJSONBody400Response) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type RequiredJSONBodydefaultResponse struct {
+ StatusCode int
+}
+
+func (response RequiredJSONBodydefaultResponse) VisitRequiredJSONBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type RequiredTextBodyRequestObject struct {
+ Body *RequiredTextBodyTextRequestBody
+}
+
+type RequiredTextBodyResponseObject interface {
+ VisitRequiredTextBodyResponse(w http.ResponseWriter) error
+}
+
+type RequiredTextBody200TextResponse string
+
+func (response RequiredTextBody200TextResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "text/plain")
+ w.WriteHeader(200)
+
+ _, err := w.Write([]byte(response))
+ return err
+}
+
+type RequiredTextBody400Response = BadrequestResponse
+
+func (response RequiredTextBody400Response) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type RequiredTextBodydefaultResponse struct {
+ StatusCode int
+}
+
+func (response RequiredTextBodydefaultResponse) VisitRequiredTextBodyResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type ReservedGoKeywordParametersRequestObject struct {
+ Type string `json:"type"`
+}
+
+type ReservedGoKeywordParametersResponseObject interface {
+ VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error
+}
+
+type ReservedGoKeywordParameters200TextResponse string
+
+func (response ReservedGoKeywordParameters200TextResponse) VisitReservedGoKeywordParametersResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "text/plain")
+ w.WriteHeader(200)
+
+ _, err := w.Write([]byte(response))
+ return err
+}
+
+type ReusableResponsesRequestObject struct {
+ Body *ReusableResponsesJSONRequestBody
+}
+
+type ReusableResponsesResponseObject interface {
+ VisitReusableResponsesResponse(w http.ResponseWriter) error
+}
+
+type ReusableResponses200JSONResponse struct{ ReusableresponseJSONResponse }
+
+func (response ReusableResponses200JSONResponse) VisitReusableResponsesResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
+ w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type ReusableResponses400Response = BadrequestResponse
+
+func (response ReusableResponses400Response) VisitReusableResponsesResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type ReusableResponsesdefaultResponse struct {
+ StatusCode int
+}
+
+func (response ReusableResponsesdefaultResponse) VisitReusableResponsesResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type TextExampleRequestObject struct {
+ Body *TextExampleTextRequestBody
+}
+
+type TextExampleResponseObject interface {
+ VisitTextExampleResponse(w http.ResponseWriter) error
+}
+
+type TextExample200TextResponse string
+
+func (response TextExample200TextResponse) VisitTextExampleResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "text/plain")
+ w.WriteHeader(200)
+
+ _, err := w.Write([]byte(response))
+ return err
+}
+
+type TextExample400Response = BadrequestResponse
+
+func (response TextExample400Response) VisitTextExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type TextExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response TextExampledefaultResponse) VisitTextExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type UnknownExampleRequestObject struct {
+ Body io.Reader
+}
+
+type UnknownExampleResponseObject interface {
+ VisitUnknownExampleResponse(w http.ResponseWriter) error
+}
+
+type UnknownExample200Videomp4Response struct {
+ Body io.Reader
+ ContentLength int64
+}
+
+func (response UnknownExample200Videomp4Response) VisitUnknownExampleResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", "video/mp4")
+ if response.ContentLength != 0 {
+ w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
+ }
+ w.WriteHeader(200)
+
+ if closer, ok := response.Body.(io.ReadCloser); ok {
+ defer closer.Close()
+ }
+ _, err := io.Copy(w, response.Body)
+ return err
+}
+
+type UnknownExample400Response = BadrequestResponse
+
+func (response UnknownExample400Response) VisitUnknownExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type UnknownExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response UnknownExampledefaultResponse) VisitUnknownExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type UnspecifiedContentTypeRequestObject struct {
+ ContentType string
+ Body io.Reader
+}
+
+type UnspecifiedContentTypeResponseObject interface {
+ VisitUnspecifiedContentTypeResponse(w http.ResponseWriter) error
+}
+
+type UnspecifiedContentType200VideoResponse struct {
+ Body io.Reader
+ ContentType string
+ ContentLength int64
+}
+
+func (response UnspecifiedContentType200VideoResponse) VisitUnspecifiedContentTypeResponse(w http.ResponseWriter) error {
+
+ w.Header().Set("Content-Type", response.ContentType)
+ if response.ContentLength != 0 {
+ w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
+ }
+ w.WriteHeader(200)
+
+ if closer, ok := response.Body.(io.ReadCloser); ok {
+ defer closer.Close()
+ }
+ _, err := io.Copy(w, response.Body)
+ return err
+}
+
+type UnspecifiedContentType400Response = BadrequestResponse
+
+func (response UnspecifiedContentType400Response) VisitUnspecifiedContentTypeResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type UnspecifiedContentType401Response struct {
+}
+
+func (response UnspecifiedContentType401Response) VisitUnspecifiedContentTypeResponse(w http.ResponseWriter) error {
+ w.WriteHeader(401)
+ return nil
+}
+
+type UnspecifiedContentType403Response struct {
+}
+
+func (response UnspecifiedContentType403Response) VisitUnspecifiedContentTypeResponse(w http.ResponseWriter) error {
+ w.WriteHeader(403)
+ return nil
+}
+
+type UnspecifiedContentTypedefaultResponse struct {
+ StatusCode int
+}
+
+func (response UnspecifiedContentTypedefaultResponse) VisitUnspecifiedContentTypeResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type URLEncodedExampleRequestObject struct {
+ Body *URLEncodedExampleFormdataRequestBody
+}
+
+type URLEncodedExampleResponseObject interface {
+ VisitURLEncodedExampleResponse(w http.ResponseWriter) error
+}
+
+type URLEncodedExample200FormdataResponse Example
+
+func (response URLEncodedExample200FormdataResponse) VisitURLEncodedExampleResponse(w http.ResponseWriter) error {
+
+ form, err := runtime.MarshalForm(response, nil)
+ if err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/x-www-form-urlencoded")
+ w.WriteHeader(200)
+ _, err = w.Write([]byte(form.Encode()))
+ return err
+}
+
+type URLEncodedExample400Response = BadrequestResponse
+
+func (response URLEncodedExample400Response) VisitURLEncodedExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type URLEncodedExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response URLEncodedExampledefaultResponse) VisitURLEncodedExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type HeadersExampleRequestObject struct {
+ Params HeadersExampleParams
+ Body *HeadersExampleJSONRequestBody
+}
+
+type HeadersExampleResponseObject interface {
+ VisitHeadersExampleResponse(w http.ResponseWriter) error
+}
+
+type HeadersExample200ResponseHeaders struct {
+ Header1 string
+ Header2 int
+ NullableHeader *string
+ OptionalHeader *string
+}
+
+type HeadersExample200JSONResponse struct {
+ Body Example
+ Headers HeadersExample200ResponseHeaders
+}
+
+func (response HeadersExample200JSONResponse) VisitHeadersExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
+ w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
+ if response.Headers.NullableHeader != nil {
+ w.Header().Set("nullable-header", fmt.Sprint(*response.Headers.NullableHeader))
+ }
+ if response.Headers.OptionalHeader != nil {
+ w.Header().Set("optional-header", fmt.Sprint(*response.Headers.OptionalHeader))
+ }
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type HeadersExample400Response = BadrequestResponse
+
+func (response HeadersExample400Response) VisitHeadersExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type HeadersExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response HeadersExampledefaultResponse) VisitHeadersExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+type UnionExampleRequestObject struct {
+ Body *UnionExampleJSONRequestBody
+}
+
+type UnionExampleResponseObject interface {
+ VisitUnionExampleResponse(w http.ResponseWriter) error
+}
+
+type UnionExample200ResponseHeaders struct {
+ Header1 string
+ Header2 int
+}
+
+type UnionExample200ApplicationAlternativePlusJSONResponse struct {
+ Body Example
+ Headers UnionExample200ResponseHeaders
+}
+
+func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/alternative+json")
+ w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
+ w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type UnionExample200JSONResponse struct {
+ Body UnionExample200JSONResponseBody
+ Headers UnionExample200ResponseHeaders
+}
+
+func (response UnionExample200JSONResponse) VisitUnionExampleResponse(w http.ResponseWriter) error {
+
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response.Body.union); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", "application/json")
+ w.Header().Set("header1", fmt.Sprint(response.Headers.Header1))
+ w.Header().Set("header2", fmt.Sprint(response.Headers.Header2))
+ w.WriteHeader(200)
+ _, err := buf.WriteTo(w)
+ return err
+}
+
+type UnionExample400Response = BadrequestResponse
+
+func (response UnionExample400Response) VisitUnionExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(400)
+ return nil
+}
+
+type UnionExampledefaultResponse struct {
+ StatusCode int
+}
+
+func (response UnionExampledefaultResponse) VisitUnionExampleResponse(w http.ResponseWriter) error {
+ w.WriteHeader(response.StatusCode)
+ return nil
+}
+
+// StrictServerInterface represents all server handlers.
+type StrictServerInterface interface {
+
+ // (POST /json)
+ JSONExample(ctx context.Context, request JSONExampleRequestObject) (JSONExampleResponseObject, error)
+
+ // (POST /multipart)
+ MultipartExample(ctx context.Context, request MultipartExampleRequestObject) (MultipartExampleResponseObject, error)
+
+ // (POST /multipart-related)
+ MultipartRelatedExample(ctx context.Context, request MultipartRelatedExampleRequestObject) (MultipartRelatedExampleResponseObject, error)
+
+ // (POST /multiple)
+ MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error)
+
+ // (POST /no-content-headers)
+ NoContentHeaders(ctx context.Context, request NoContentHeadersRequestObject) (NoContentHeadersResponseObject, error)
+
+ // (POST /required-json-body)
+ RequiredJSONBody(ctx context.Context, request RequiredJSONBodyRequestObject) (RequiredJSONBodyResponseObject, error)
+
+ // (POST /required-text-body)
+ RequiredTextBody(ctx context.Context, request RequiredTextBodyRequestObject) (RequiredTextBodyResponseObject, error)
+
+ // (GET /reserved-go-keyword-parameters/{type})
+ ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error)
+
+ // (POST /reusable-responses)
+ ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error)
+
+ // (POST /text)
+ TextExample(ctx context.Context, request TextExampleRequestObject) (TextExampleResponseObject, error)
+
+ // (POST /unknown)
+ UnknownExample(ctx context.Context, request UnknownExampleRequestObject) (UnknownExampleResponseObject, error)
+
+ // (POST /unspecified-content-type)
+ UnspecifiedContentType(ctx context.Context, request UnspecifiedContentTypeRequestObject) (UnspecifiedContentTypeResponseObject, error)
+
+ // (POST /urlencoded)
+ URLEncodedExample(ctx context.Context, request URLEncodedExampleRequestObject) (URLEncodedExampleResponseObject, error)
+
+ // (POST /with-headers)
+ HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error)
+
+ // (POST /with-union)
+ UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error)
+}
+
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictHTTPServerOptions struct {
+ RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+ ResponseErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictHTTPServerOptions{
+ RequestErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ },
+ ResponseErrorHandlerFunc: func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictHTTPServerOptions) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+ options StrictHTTPServerOptions
+}
+
+// JSONExample operation middleware
+func (sh *strictHandler) JSONExample(w http.ResponseWriter, r *http.Request) {
+ var request JSONExampleRequestObject
+
+ var body JSONExampleJSONRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.JSONExample(ctx, request.(JSONExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "JSONExample")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(JSONExampleResponseObject); ok {
+ if err := validResponse.VisitJSONExampleResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// MultipartExample operation middleware
+func (sh *strictHandler) MultipartExample(w http.ResponseWriter, r *http.Request) {
+ var request MultipartExampleRequestObject
+
+ if reader, err := r.MultipartReader(); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode multipart body: %w", err))
+ return
+ } else {
+ request.Body = reader
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.MultipartExample(ctx, request.(MultipartExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "MultipartExample")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(MultipartExampleResponseObject); ok {
+ if err := validResponse.VisitMultipartExampleResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// MultipartRelatedExample operation middleware
+func (sh *strictHandler) MultipartRelatedExample(w http.ResponseWriter, r *http.Request) {
+ var request MultipartRelatedExampleRequestObject
+
+ if _, params, err := mime.ParseMediaType(r.Header.Get("Content-Type")); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, err)
+ return
+ } else if boundary := params["boundary"]; boundary == "" {
+ sh.options.RequestErrorHandlerFunc(w, r, http.ErrMissingBoundary)
+ return
+ } else {
+ request.Body = multipart.NewReader(r.Body, boundary)
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.MultipartRelatedExample(ctx, request.(MultipartRelatedExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "MultipartRelatedExample")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(MultipartRelatedExampleResponseObject); ok {
+ if err := validResponse.VisitMultipartRelatedExampleResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// MultipleRequestAndResponseTypes operation middleware
+func (sh *strictHandler) MultipleRequestAndResponseTypes(w http.ResponseWriter, r *http.Request) {
+ var request MultipleRequestAndResponseTypesRequestObject
+
+ if strings.HasPrefix(r.Header.Get("Content-Type"), "application/json") {
+
+ var body MultipleRequestAndResponseTypesJSONRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.JSONBody = &body
+ }
+ }
+ if strings.HasPrefix(r.Header.Get("Content-Type"), "application/x-www-form-urlencoded") {
+ if err := r.ParseForm(); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode formdata: %w", err))
+ return
+ }
+ var body MultipleRequestAndResponseTypesFormdataRequestBody
+ if err := runtime.BindForm(&body, r.Form, nil, nil); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't bind formdata: %w", err))
+ return
+ }
+ request.FormdataBody = &body
+ }
+ if strings.HasPrefix(r.Header.Get("Content-Type"), "image/png") {
+ request.Body = r.Body
+ }
+ if strings.HasPrefix(r.Header.Get("Content-Type"), "multipart/form-data") {
+ if reader, err := r.MultipartReader(); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode multipart body: %w", err))
+ return
+ } else {
+ request.MultipartBody = reader
+ }
+ }
+ if strings.HasPrefix(r.Header.Get("Content-Type"), "text/plain") {
+ data, err := io.ReadAll(r.Body)
+ if err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't read body: %w", err))
+ return
+ }
+ if len(data) > 0 {
+ body := MultipleRequestAndResponseTypesTextRequestBody(data)
+ request.TextBody = &body
+ }
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.MultipleRequestAndResponseTypes(ctx, request.(MultipleRequestAndResponseTypesRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "MultipleRequestAndResponseTypes")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(MultipleRequestAndResponseTypesResponseObject); ok {
+ if err := validResponse.VisitMultipleRequestAndResponseTypesResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// NoContentHeaders operation middleware
+func (sh *strictHandler) NoContentHeaders(w http.ResponseWriter, r *http.Request) {
+ var request NoContentHeadersRequestObject
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.NoContentHeaders(ctx, request.(NoContentHeadersRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "NoContentHeaders")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(NoContentHeadersResponseObject); ok {
+ if err := validResponse.VisitNoContentHeadersResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// RequiredJSONBody operation middleware
+func (sh *strictHandler) RequiredJSONBody(w http.ResponseWriter, r *http.Request) {
+ var request RequiredJSONBodyRequestObject
+
+ var body RequiredJSONBodyJSONRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ request.Body = &body
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.RequiredJSONBody(ctx, request.(RequiredJSONBodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "RequiredJSONBody")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(RequiredJSONBodyResponseObject); ok {
+ if err := validResponse.VisitRequiredJSONBodyResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// RequiredTextBody operation middleware
+func (sh *strictHandler) RequiredTextBody(w http.ResponseWriter, r *http.Request) {
+ var request RequiredTextBodyRequestObject
+
+ data, err := io.ReadAll(r.Body)
+ if err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't read body: %w", err))
+ return
+ }
+ body := RequiredTextBodyTextRequestBody(data)
+ request.Body = &body
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.RequiredTextBody(ctx, request.(RequiredTextBodyRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "RequiredTextBody")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(RequiredTextBodyResponseObject); ok {
+ if err := validResponse.VisitRequiredTextBodyResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// ReservedGoKeywordParameters operation middleware
+func (sh *strictHandler) ReservedGoKeywordParameters(w http.ResponseWriter, r *http.Request, pType string) {
+ var request ReservedGoKeywordParametersRequestObject
+
+ request.Type = pType
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.ReservedGoKeywordParameters(ctx, request.(ReservedGoKeywordParametersRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "ReservedGoKeywordParameters")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(ReservedGoKeywordParametersResponseObject); ok {
+ if err := validResponse.VisitReservedGoKeywordParametersResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// ReusableResponses operation middleware
+func (sh *strictHandler) ReusableResponses(w http.ResponseWriter, r *http.Request) {
+ var request ReusableResponsesRequestObject
+
+ var body ReusableResponsesJSONRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.ReusableResponses(ctx, request.(ReusableResponsesRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "ReusableResponses")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(ReusableResponsesResponseObject); ok {
+ if err := validResponse.VisitReusableResponsesResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// TextExample operation middleware
+func (sh *strictHandler) TextExample(w http.ResponseWriter, r *http.Request) {
+ var request TextExampleRequestObject
+
+ data, err := io.ReadAll(r.Body)
+ if err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't read body: %w", err))
+ return
+ }
+ if len(data) > 0 {
+ body := TextExampleTextRequestBody(data)
+ request.Body = &body
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.TextExample(ctx, request.(TextExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "TextExample")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(TextExampleResponseObject); ok {
+ if err := validResponse.VisitTextExampleResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// UnknownExample operation middleware
+func (sh *strictHandler) UnknownExample(w http.ResponseWriter, r *http.Request) {
+ var request UnknownExampleRequestObject
+
+ request.Body = r.Body
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.UnknownExample(ctx, request.(UnknownExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "UnknownExample")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(UnknownExampleResponseObject); ok {
+ if err := validResponse.VisitUnknownExampleResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// UnspecifiedContentType operation middleware
+func (sh *strictHandler) UnspecifiedContentType(w http.ResponseWriter, r *http.Request) {
+ var request UnspecifiedContentTypeRequestObject
+
+ request.ContentType = r.Header.Get("Content-Type")
+
+ request.Body = r.Body
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.UnspecifiedContentType(ctx, request.(UnspecifiedContentTypeRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "UnspecifiedContentType")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(UnspecifiedContentTypeResponseObject); ok {
+ if err := validResponse.VisitUnspecifiedContentTypeResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// URLEncodedExample operation middleware
+func (sh *strictHandler) URLEncodedExample(w http.ResponseWriter, r *http.Request) {
+ var request URLEncodedExampleRequestObject
+
+ if err := r.ParseForm(); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode formdata: %w", err))
+ return
+ }
+ var body URLEncodedExampleFormdataRequestBody
+ if err := runtime.BindForm(&body, r.Form, nil, nil); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't bind formdata: %w", err))
+ return
+ }
+ request.Body = &body
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.URLEncodedExample(ctx, request.(URLEncodedExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "URLEncodedExample")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(URLEncodedExampleResponseObject); ok {
+ if err := validResponse.VisitURLEncodedExampleResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// HeadersExample operation middleware
+func (sh *strictHandler) HeadersExample(w http.ResponseWriter, r *http.Request, params HeadersExampleParams) {
+ var request HeadersExampleRequestObject
+
+ request.Params = params
+
+ var body HeadersExampleJSONRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.HeadersExample(ctx, request.(HeadersExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "HeadersExample")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(HeadersExampleResponseObject); ok {
+ if err := validResponse.VisitHeadersExampleResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// UnionExample operation middleware
+func (sh *strictHandler) UnionExample(w http.ResponseWriter, r *http.Request) {
+ var request UnionExampleRequestObject
+
+ var body UnionExampleJSONRequestBody
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ } else {
+ request.Body = &body
+ }
+
+ handler := func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (interface{}, error) {
+ return sh.ssi.UnionExample(ctx, request.(UnionExampleRequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "UnionExample")
+ }
+
+ response, err := handler(r.Context(), w, r, request)
+
+ if err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ } else if validResponse, ok := response.(UnionExampleResponseObject); ok {
+ if err := validResponse.VisitUnionExampleResponse(w); err != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, err)
+ }
+ } else if response != nil {
+ sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
+ }
+}
+
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
+var swaggerSpec = []string{
+ "7Fnbcts2E36VHfz/RZuSpuL4SndNJpO2aZOObF91fAERKwkJCSDAUrJGo5k+RJ+wT9IBAepI21KqgyfT",
+ "O4ncE/fbXX5LzFiuS6MVKnKsO2MWndHKYf2nz4XFLxU68v8EutxKQ1Ir1mWvuejFe/OEWawc7xfYqHv5",
+ "XCtCVatyYwqZc6+afXJef8ZcPsKS+1//tzhgXfa/bBlKFu66DO95aQpk8/k82Yjg43uWsBFygbaONvx8",
+ "GZ7iSyUtCtYlW2Gy4oumBlmXObJSDZk3GtQud1KTinCI1kfjVWOQXqCJsztjxmqDlmTI4ZgXFbZ7jld0",
+ "/xPmFJ5QqoHezvUbrYhL5UDIwQAtKoKYXPA2HLjKGG0JBfSn4D3kBA7tGC1LGEnygbHr1esQA3YsYWO0",
+ "Ljh6edG56Hg8tUHFjWRd9qq+lDDDaVQ/0AJAo9vq4pfrjx9AOuAV6ZKTzHlRTKHk1o14gQKkIu1DrHJy",
+ "F6z2ZOvC+FlE7bcxlQmLxfdai+kxCqqu25Vyv+x0TlS384RdBWdtNhZBZSsNWJsZ8Kpoyfmt+qz0RAFa",
+ "q218sqysCpKGW1rFaj3bvzUiu6R8YS8baFumghM/UtYP5enciU8tFpz8OHkSgF6Q3A+HFfNHReHf+Dkr",
+ "BnEet86p65GeOBjpCZAGgbyAiaQRNIobA1Yq4OCkGhYITVBJK5gFxtfij0r04rPceBtHn2fJmpX7dDKZ",
+ "pHUDVbZAlWvxdRAmTJZ8iJlRw3V1b5sT67L+lHzJbr/gDtTICSO8p8wUXG4kZtPliUb6f5k+WGOHdlU6",
+ "jRClK4SuvXE/LGThu8vO1ffQGA4NrGs5XgBXAlRVFJ6WLmWiefj7z78A79Hm0qEDGnGCSjmkhQC3CLqU",
+ "5EnVwOoSaLQ0s9X7H/SbENNPMfytOrxqexKIWutEtok65mIdiOZmw1G3a6HJQKv6dscEBBrqm/qeSPtx",
+ "QrUjEAcceClP9RrdBJyGUjo/J8NNN9JVIYAXEz51YUJvc75eVPfcrx6NRyd+yQbT/7aJ4AJa39vngfYG",
+ "7+lJaPcYPfvCd+qptj9E9VYm0qFOP+N0oq1IDbe8RELrspmPc+5tDbHF5O8LSci5gj6C4iUK4ANCC+80",
+ "RJOuBZ/g951+H0SWpuqVb/Gn+8eM+eTVayBLmHfAuiF/yR7r9t1xoWqyGT5GpGuuHir4KNKkzuLAeUrY",
+ "hnFL/oKn3orEeZbWx2tz6/PMKYraI/nw6uNHwi7rzgGp33OfAlW4+HDOotYuaftKJrlDFsdSoM5Kc7Wn",
+ "5bMl1RnM5UCiWHDMENtDI+GNVrlFWl8B/ctQaYKFMehPa0oYMlC/HycIZeUIDHcOJNVTpJDha53Y5oy3",
+ "y8giDbxZjtPHUH1xJExfnAvRq87L/VVeHblu1la5B/qx9+vbILPvN8uD7Yx7bryH83umdvY73tM7YtzC",
+ "lu/0HOXYMyIlwCJVVqGAseTNh+it3owGlrC2caG4Xy3YUHMAsQ8hSh61dckePYS4+4Y/kZ/vaCc58QJ+",
+ "qq6plHzs4ObW34bI6DffVFKrZ3oswwtCqzjJMf5wmO9521a0wo+Duu830Et29HD3/I4vj11184SFk8Yw",
+ "MCtb+KlGZLpZFk4oL9yED4doL6TOuJE+S/8EAAD//w==",
+}
+
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
+func decodeSpec() ([]byte, error) {
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
+ if err != nil {
+ return nil, fmt.Errorf("error base64 decoding spec: %w", err)
+ }
+ zr := flate.NewReader(bytes.NewReader(compressed))
+ var buf bytes.Buffer
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
+ }
+
+ return buf.Bytes(), nil
+}
+
+var rawSpec = decodeSpecCached()
+
+// a naive cache of the decoded OpenAPI spec
+func decodeSpecCached() func() ([]byte, error) {
+ data, err := decodeSpec()
+ return func() ([]byte, error) {
+ return data, err
+ }
+}
+
+// Constructs a synthetic filesystem for resolving external references when loading openapi specifications.
+func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
+ res := make(map[string]func() ([]byte, error))
+ if len(pathToFile) > 0 {
+ res[pathToFile] = rawSpec
+ }
+
+ return res
+}
+
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
+ resolvePath := PathToRawSpec("")
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+ loader.ReadFromURIFunc = func(loader *openapi3.Loader, url *url.URL) ([]byte, error) {
+ pathToFile := url.String()
+ pathToFile = path.Clean(pathToFile)
+ getSpec, ok := resolvePath[pathToFile]
+ if !ok {
+ err1 := fmt.Errorf("path not found: %s", pathToFile)
+ return nil, err1
+ }
+ return getSpec()
+ }
+ var specData []byte
+ specData, err = rawSpec()
+ if err != nil {
+ return
+ }
+ swagger, err = loader.LoadFromData(specData)
+ if err != nil {
+ return
+ }
+ return
+}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/internal/test/strict-server/stdhttp/server.go b/internal/test/strict-server/stdhttp/server.go
new file mode 100644
index 0000000000..3d24a5d272
--- /dev/null
+++ b/internal/test/strict-server/stdhttp/server.go
@@ -0,0 +1,158 @@
+//go:build go1.22
+
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=server.cfg.yaml ../strict-schema.yaml
+//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=types.cfg.yaml ../strict-schema.yaml
+
+package api
+
+import (
+ "context"
+ "encoding/json"
+ "io"
+ "mime/multipart"
+)
+
+type StrictServer struct {
+}
+
+func (s StrictServer) JSONExample(ctx context.Context, request JSONExampleRequestObject) (JSONExampleResponseObject, error) {
+ return JSONExample200JSONResponse(*request.Body), nil
+}
+
+func (s StrictServer) MultipartExample(ctx context.Context, request MultipartExampleRequestObject) (MultipartExampleResponseObject, error) {
+ return MultipartExample200MultipartResponse(func(writer *multipart.Writer) error {
+ for {
+ part, err := request.Body.NextPart()
+ if err == io.EOF {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ w, err := writer.CreatePart(part.Header)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(w, part)
+ if err != nil {
+ return err
+ }
+ if err = part.Close(); err != nil {
+ return err
+ }
+ }
+ }), nil
+}
+
+func (s StrictServer) MultipartRelatedExample(ctx context.Context, request MultipartRelatedExampleRequestObject) (MultipartRelatedExampleResponseObject, error) {
+ return MultipartRelatedExample200MultipartResponse(func(writer *multipart.Writer) error {
+ for {
+ part, err := request.Body.NextPart()
+ if err == io.EOF {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ w, err := writer.CreatePart(part.Header)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(w, part)
+ if err != nil {
+ return err
+ }
+ if err = part.Close(); err != nil {
+ return err
+ }
+ }
+ }), nil
+}
+
+func (s StrictServer) MultipleRequestAndResponseTypes(ctx context.Context, request MultipleRequestAndResponseTypesRequestObject) (MultipleRequestAndResponseTypesResponseObject, error) {
+ switch {
+ case request.Body != nil:
+ return MultipleRequestAndResponseTypes200ImagepngResponse{Body: request.Body}, nil
+ case request.JSONBody != nil:
+ return MultipleRequestAndResponseTypes200JSONResponse(*request.JSONBody), nil
+ case request.FormdataBody != nil:
+ return MultipleRequestAndResponseTypes200FormdataResponse(*request.FormdataBody), nil
+ case request.TextBody != nil:
+ return MultipleRequestAndResponseTypes200TextResponse(*request.TextBody), nil
+ case request.MultipartBody != nil:
+ return MultipleRequestAndResponseTypes200MultipartResponse(func(writer *multipart.Writer) error {
+ for {
+ part, err := request.MultipartBody.NextPart()
+ if err == io.EOF {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ w, err := writer.CreatePart(part.Header)
+ if err != nil {
+ return err
+ }
+ _, err = io.Copy(w, part)
+ if err != nil {
+ return err
+ }
+ if err = part.Close(); err != nil {
+ return err
+ }
+ }
+ }), nil
+ default:
+ return MultipleRequestAndResponseTypes400Response{}, nil
+ }
+}
+
+func (s StrictServer) TextExample(ctx context.Context, request TextExampleRequestObject) (TextExampleResponseObject, error) {
+ return TextExample200TextResponse(*request.Body), nil
+}
+
+func (s StrictServer) UnknownExample(ctx context.Context, request UnknownExampleRequestObject) (UnknownExampleResponseObject, error) {
+ return UnknownExample200Videomp4Response{Body: request.Body}, nil
+}
+
+func (s StrictServer) UnspecifiedContentType(ctx context.Context, request UnspecifiedContentTypeRequestObject) (UnspecifiedContentTypeResponseObject, error) {
+ return UnspecifiedContentType200VideoResponse{Body: request.Body, ContentType: request.ContentType}, nil
+}
+
+func (s StrictServer) URLEncodedExample(ctx context.Context, request URLEncodedExampleRequestObject) (URLEncodedExampleResponseObject, error) {
+ return URLEncodedExample200FormdataResponse(*request.Body), nil
+}
+
+func (s StrictServer) HeadersExample(ctx context.Context, request HeadersExampleRequestObject) (HeadersExampleResponseObject, error) {
+ return HeadersExample200JSONResponse{Body: *request.Body, Headers: HeadersExample200ResponseHeaders{Header1: request.Params.Header1, Header2: *request.Params.Header2}}, nil
+}
+
+func (s StrictServer) NoContentHeaders(ctx context.Context, request NoContentHeadersRequestObject) (NoContentHeadersResponseObject, error) {
+ return NoContentHeaders204Response{}, nil
+}
+
+func (s StrictServer) ReusableResponses(ctx context.Context, request ReusableResponsesRequestObject) (ReusableResponsesResponseObject, error) {
+ return ReusableResponses200JSONResponse{ReusableresponseJSONResponse: ReusableresponseJSONResponse{Body: *request.Body}}, nil
+}
+
+func (s StrictServer) RequiredJSONBody(ctx context.Context, request RequiredJSONBodyRequestObject) (RequiredJSONBodyResponseObject, error) {
+ return RequiredJSONBody200JSONResponse(*request.Body), nil
+}
+
+func (s StrictServer) RequiredTextBody(ctx context.Context, request RequiredTextBodyRequestObject) (RequiredTextBodyResponseObject, error) {
+ return RequiredTextBody200TextResponse(*request.Body), nil
+}
+
+func (s StrictServer) ReservedGoKeywordParameters(ctx context.Context, request ReservedGoKeywordParametersRequestObject) (ReservedGoKeywordParametersResponseObject, error) {
+ return ReservedGoKeywordParameters200TextResponse(""), nil
+}
+
+func (s StrictServer) UnionExample(ctx context.Context, request UnionExampleRequestObject) (UnionExampleResponseObject, error) {
+ union, err := json.Marshal(*request.Body)
+ if err != nil {
+ return nil, err
+ }
+
+ return UnionExample200JSONResponse{
+ Body: struct{ union json.RawMessage }{
+ union: union,
+ },
+ }, nil
+}
diff --git a/internal/test/strict-server/stdhttp/std_strict_test.go b/internal/test/strict-server/stdhttp/std_strict_test.go
new file mode 100644
index 0000000000..4c1e76e9ac
--- /dev/null
+++ b/internal/test/strict-server/stdhttp/std_strict_test.go
@@ -0,0 +1,235 @@
+//go:build go1.22
+
+package api
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+ "mime"
+ "mime/multipart"
+ "net/http"
+ "net/url"
+ "strings"
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+
+ clientAPI "github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/client"
+ "github.com/oapi-codegen/runtime"
+ "github.com/oapi-codegen/testutil"
+)
+
+func TestStdHTTPServer(t *testing.T) {
+ server := StrictServer{}
+ strictHandler := NewStrictHandler(server, nil)
+ m := http.NewServeMux()
+ HandlerFromMux(strictHandler, m)
+ testImpl(t, m)
+}
+
+func testImpl(t *testing.T, handler http.Handler) {
+ t.Run("JSONExample", func(t *testing.T) {
+ value := "123"
+ requestBody := clientAPI.Example{Value: &value}
+ rr := testutil.NewRequest().Post("/json").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
+ var responseBody clientAPI.Example
+ err := json.NewDecoder(rr.Body).Decode(&responseBody)
+ assert.NoError(t, err)
+ assert.Equal(t, requestBody, responseBody)
+ })
+ t.Run("URLEncodedExample", func(t *testing.T) {
+ value := "456"
+ requestBody := clientAPI.Example{Value: &value}
+ requestBodyEncoded, err := runtime.MarshalForm(&requestBody, nil)
+ assert.NoError(t, err)
+ rr := testutil.NewRequest().Post("/urlencoded").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(requestBodyEncoded.Encode())).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.Equal(t, "application/x-www-form-urlencoded", rr.Header().Get("Content-Type"))
+ values, err := url.ParseQuery(rr.Body.String())
+ assert.NoError(t, err)
+ var responseBody clientAPI.Example
+ err = runtime.BindForm(&responseBody, values, nil, nil)
+ assert.NoError(t, err)
+ assert.Equal(t, requestBody, responseBody)
+ })
+ t.Run("MultipartExample", func(t *testing.T) {
+ value := "789"
+ fieldName := "value"
+ var writer bytes.Buffer
+ mw := multipart.NewWriter(&writer)
+ field, err := mw.CreateFormField(fieldName)
+ assert.NoError(t, err)
+ _, _ = field.Write([]byte(value))
+ assert.NoError(t, mw.Close())
+ rr := testutil.NewRequest().Post("/multipart").WithContentType(mw.FormDataContentType()).WithBody(writer.Bytes()).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ contentType, params, err := mime.ParseMediaType(rr.Header().Get("Content-Type"))
+ assert.NoError(t, err)
+ assert.Equal(t, "multipart/form-data", contentType)
+ reader := multipart.NewReader(rr.Body, params["boundary"])
+ part, err := reader.NextPart()
+ assert.NoError(t, err)
+ assert.Equal(t, part.FormName(), fieldName)
+ readValue, err := io.ReadAll(part)
+ assert.NoError(t, err)
+ assert.Equal(t, value, string(readValue))
+ _, err = reader.NextPart()
+ assert.Equal(t, io.EOF, err)
+ })
+ t.Run("MultipartRelatedExample", func(t *testing.T) {
+ value := "789"
+ fieldName := "value"
+ var writer bytes.Buffer
+ mw := multipart.NewWriter(&writer)
+ field, err := mw.CreateFormField(fieldName)
+ assert.NoError(t, err)
+ _, _ = field.Write([]byte(value))
+ assert.NoError(t, mw.Close())
+ rr := testutil.NewRequest().Post("/multipart-related").WithContentType(mime.FormatMediaType("multipart/related", map[string]string{"boundary": mw.Boundary()})).WithBody(writer.Bytes()).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ contentType, params, err := mime.ParseMediaType(rr.Header().Get("Content-Type"))
+ assert.NoError(t, err)
+ assert.Equal(t, "multipart/related", contentType)
+ reader := multipart.NewReader(rr.Body, params["boundary"])
+ part, err := reader.NextPart()
+ assert.NoError(t, err)
+ assert.Equal(t, part.FormName(), fieldName)
+ readValue, err := io.ReadAll(part)
+ assert.NoError(t, err)
+ assert.Equal(t, value, string(readValue))
+ _, err = reader.NextPart()
+ assert.Equal(t, io.EOF, err)
+ })
+ t.Run("TextExample", func(t *testing.T) {
+ value := "text"
+ rr := testutil.NewRequest().Post("/text").WithContentType("text/plain").WithBody([]byte(value)).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.Equal(t, "text/plain", rr.Header().Get("Content-Type"))
+ assert.Equal(t, value, rr.Body.String())
+ })
+ t.Run("UnknownExample", func(t *testing.T) {
+ data := []byte("unknown data")
+ rr := testutil.NewRequest().Post("/unknown").WithContentType("image/png").WithBody(data).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.Equal(t, "video/mp4", rr.Header().Get("Content-Type"))
+ assert.Equal(t, data, rr.Body.Bytes())
+ })
+ t.Run("MultipleRequestAndResponseTypesJSON", func(t *testing.T) {
+ value := "123"
+ requestBody := clientAPI.Example{Value: &value}
+ rr := testutil.NewRequest().Post("/multiple").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
+ var responseBody clientAPI.Example
+ err := json.NewDecoder(rr.Body).Decode(&responseBody)
+ assert.NoError(t, err)
+ assert.Equal(t, requestBody, responseBody)
+ })
+ t.Run("MultipleRequestAndResponseTypesFormdata", func(t *testing.T) {
+ value := "456"
+ requestBody := clientAPI.Example{Value: &value}
+ requestBodyEncoded, err := runtime.MarshalForm(&requestBody, nil)
+ assert.NoError(t, err)
+ rr := testutil.NewRequest().Post("/multiple").WithContentType("application/x-www-form-urlencoded").WithBody([]byte(requestBodyEncoded.Encode())).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.Equal(t, "application/x-www-form-urlencoded", rr.Header().Get("Content-Type"))
+ values, err := url.ParseQuery(rr.Body.String())
+ assert.NoError(t, err)
+ var responseBody clientAPI.Example
+ err = runtime.BindForm(&responseBody, values, nil, nil)
+ assert.NoError(t, err)
+ assert.Equal(t, requestBody, responseBody)
+ })
+ t.Run("MultipleRequestAndResponseTypesMultipart", func(t *testing.T) {
+ value := "789"
+ fieldName := "value"
+ var writer bytes.Buffer
+ mw := multipart.NewWriter(&writer)
+ field, err := mw.CreateFormField(fieldName)
+ assert.NoError(t, err)
+ _, _ = field.Write([]byte(value))
+ assert.NoError(t, mw.Close())
+ rr := testutil.NewRequest().Post("/multiple").WithContentType(mw.FormDataContentType()).WithBody(writer.Bytes()).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ contentType, params, err := mime.ParseMediaType(rr.Header().Get("Content-Type"))
+ assert.NoError(t, err)
+ assert.Equal(t, "multipart/form-data", contentType)
+ reader := multipart.NewReader(rr.Body, params["boundary"])
+ part, err := reader.NextPart()
+ assert.NoError(t, err)
+ assert.Equal(t, part.FormName(), fieldName)
+ readValue, err := io.ReadAll(part)
+ assert.NoError(t, err)
+ assert.Equal(t, value, string(readValue))
+ _, err = reader.NextPart()
+ assert.Equal(t, io.EOF, err)
+ })
+ t.Run("MultipleRequestAndResponseTypesText", func(t *testing.T) {
+ value := "text"
+ rr := testutil.NewRequest().Post("/multiple").WithContentType("text/plain").WithBody([]byte(value)).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.Equal(t, "text/plain", rr.Header().Get("Content-Type"))
+ assert.Equal(t, value, rr.Body.String())
+ })
+ t.Run("MultipleRequestAndResponseTypesImage", func(t *testing.T) {
+ data := []byte("unknown data")
+ rr := testutil.NewRequest().Post("/multiple").WithContentType("image/png").WithBody(data).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.Equal(t, "image/png", rr.Header().Get("Content-Type"))
+ assert.Equal(t, data, rr.Body.Bytes())
+ })
+ t.Run("HeadersExample", func(t *testing.T) {
+ header1 := "value1"
+ header2 := "890"
+ value := "asdf"
+ requestBody := clientAPI.Example{Value: &value}
+ rr := testutil.NewRequest().Post("/with-headers").WithHeader("header1", header1).WithHeader("header2", header2).WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
+ var responseBody clientAPI.Example
+ err := json.NewDecoder(rr.Body).Decode(&responseBody)
+ assert.NoError(t, err)
+ assert.Equal(t, requestBody, responseBody)
+ assert.Equal(t, header1, rr.Header().Get("header1"))
+ assert.Equal(t, header2, rr.Header().Get("header2"))
+ })
+ t.Run("NoContentHeadersOmitUnset", func(t *testing.T) {
+ rr := testutil.NewRequest().Post("/no-content-headers").GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusNoContent, rr.Code)
+ assert.Empty(t, rr.Header().Values("optional-header"), "optional-header should be omitted when the response field is nil")
+ assert.Empty(t, rr.Header().Values("nullable-header"), "nullable-header should be omitted when the response field is unspecified")
+ })
+ t.Run("UnspecifiedContentType", func(t *testing.T) {
+ data := []byte("image data")
+ contentType := "image/jpeg"
+ rr := testutil.NewRequest().Post("/unspecified-content-type").WithContentType(contentType).WithBody(data).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.Equal(t, contentType, rr.Header().Get("Content-Type"))
+ assert.Equal(t, data, rr.Body.Bytes())
+ })
+ t.Run("ReusableResponses", func(t *testing.T) {
+ value := "jkl;"
+ requestBody := clientAPI.Example{Value: &value}
+ rr := testutil.NewRequest().Post("/reusable-responses").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
+ var responseBody clientAPI.Example
+ err := json.NewDecoder(rr.Body).Decode(&responseBody)
+ assert.NoError(t, err)
+ assert.Equal(t, requestBody, responseBody)
+ })
+ t.Run("UnionResponses", func(t *testing.T) {
+ value := "union"
+ requestBody := clientAPI.Example{Value: &value}
+ rr := testutil.NewRequest().Post("/with-union").WithJsonBody(requestBody).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ assert.True(t, strings.HasPrefix(rr.Header().Get("Content-Type"), "application/json"))
+ var responseBody clientAPI.Example
+ err := json.NewDecoder(rr.Body).Decode(&responseBody)
+ assert.NoError(t, err)
+ assert.Equal(t, requestBody, responseBody)
+ })
+}
diff --git a/internal/test/strict-server/stdhttp/tools/tools.go b/internal/test/strict-server/stdhttp/tools/tools.go
new file mode 100644
index 0000000000..8615cb4c57
--- /dev/null
+++ b/internal/test/strict-server/stdhttp/tools/tools.go
@@ -0,0 +1,8 @@
+//go:build tools
+// +build tools
+
+package tools
+
+import (
+ _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen"
+)
diff --git a/internal/test/strict-server/stdhttp/types.cfg.yaml b/internal/test/strict-server/stdhttp/types.cfg.yaml
new file mode 100644
index 0000000000..2ed9740ea7
--- /dev/null
+++ b/internal/test/strict-server/stdhttp/types.cfg.yaml
@@ -0,0 +1,5 @@
+# yaml-language-server: $schema=../../../../configuration-schema.json
+package: api
+generate:
+ models: true
+output: types.gen.go
diff --git a/internal/test/strict-server/stdhttp/types.gen.go b/internal/test/strict-server/stdhttp/types.gen.go
new file mode 100644
index 0000000000..08ae8548e1
--- /dev/null
+++ b/internal/test/strict-server/stdhttp/types.gen.go
@@ -0,0 +1,145 @@
+// Package api provides primitives to interact with the openapi HTTP API.
+//
+// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
+package api
+
+import (
+ "encoding/json"
+
+ "github.com/oapi-codegen/runtime"
+)
+
+// Example defines model for example.
+type Example struct {
+ Value *string `json:"value,omitempty"`
+}
+
+// Reusableresponse defines model for reusableresponse.
+type Reusableresponse = Example
+
+// MultipleRequestAndResponseTypesTextBody defines parameters for MultipleRequestAndResponseTypes.
+type MultipleRequestAndResponseTypesTextBody = string
+
+// RequiredTextBodyTextBody defines parameters for RequiredTextBody.
+type RequiredTextBodyTextBody = string
+
+// TextExampleTextBody defines parameters for TextExample.
+type TextExampleTextBody = string
+
+// HeadersExampleParams defines parameters for HeadersExample.
+type HeadersExampleParams struct {
+ Header1 string `json:"header1"`
+ Header2 *int `json:"header2,omitempty"`
+}
+
+// UnionExample200JSONResponseBody0 defines parameters for UnionExample.
+type UnionExample200JSONResponseBody0 = string
+
+// UnionExample200JSONResponseBody defines parameters for UnionExample.
+type UnionExample200JSONResponseBody struct {
+ union json.RawMessage
+}
+
+// JSONExampleJSONRequestBody defines body for JSONExample for application/json ContentType.
+type JSONExampleJSONRequestBody = Example
+
+// MultipartExampleMultipartRequestBody defines body for MultipartExample for multipart/form-data ContentType.
+type MultipartExampleMultipartRequestBody = Example
+
+// MultipartRelatedExampleMultipartRequestBody defines body for MultipartRelatedExample for multipart/related ContentType.
+type MultipartRelatedExampleMultipartRequestBody = Example
+
+// MultipleRequestAndResponseTypesJSONRequestBody defines body for MultipleRequestAndResponseTypes for application/json ContentType.
+type MultipleRequestAndResponseTypesJSONRequestBody = Example
+
+// MultipleRequestAndResponseTypesFormdataRequestBody defines body for MultipleRequestAndResponseTypes for application/x-www-form-urlencoded ContentType.
+type MultipleRequestAndResponseTypesFormdataRequestBody = Example
+
+// MultipleRequestAndResponseTypesMultipartRequestBody defines body for MultipleRequestAndResponseTypes for multipart/form-data ContentType.
+type MultipleRequestAndResponseTypesMultipartRequestBody = Example
+
+// MultipleRequestAndResponseTypesTextRequestBody defines body for MultipleRequestAndResponseTypes for text/plain ContentType.
+type MultipleRequestAndResponseTypesTextRequestBody = MultipleRequestAndResponseTypesTextBody
+
+// RequiredJSONBodyJSONRequestBody defines body for RequiredJSONBody for application/json ContentType.
+type RequiredJSONBodyJSONRequestBody = Example
+
+// RequiredTextBodyTextRequestBody defines body for RequiredTextBody for text/plain ContentType.
+type RequiredTextBodyTextRequestBody = RequiredTextBodyTextBody
+
+// ReusableResponsesJSONRequestBody defines body for ReusableResponses for application/json ContentType.
+type ReusableResponsesJSONRequestBody = Example
+
+// TextExampleTextRequestBody defines body for TextExample for text/plain ContentType.
+type TextExampleTextRequestBody = TextExampleTextBody
+
+// URLEncodedExampleFormdataRequestBody defines body for URLEncodedExample for application/x-www-form-urlencoded ContentType.
+type URLEncodedExampleFormdataRequestBody = Example
+
+// HeadersExampleJSONRequestBody defines body for HeadersExample for application/json ContentType.
+type HeadersExampleJSONRequestBody = Example
+
+// UnionExampleJSONRequestBody defines body for UnionExample for application/json ContentType.
+type UnionExampleJSONRequestBody = Example
+
+// AsUnionExample200JSONResponseBody0 returns the union data inside the UnionExample200JSONResponseBody as a UnionExample200JSONResponseBody0
+func (t UnionExample200JSONResponseBody) AsUnionExample200JSONResponseBody0() (UnionExample200JSONResponseBody0, error) {
+ var body UnionExample200JSONResponseBody0
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromUnionExample200JSONResponseBody0 overwrites any union data inside the UnionExample200JSONResponseBody as the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) FromUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeUnionExample200JSONResponseBody0 performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided UnionExample200JSONResponseBody0
+func (t *UnionExample200JSONResponseBody) MergeUnionExample200JSONResponseBody0(v UnionExample200JSONResponseBody0) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+// AsExample returns the union data inside the UnionExample200JSONResponseBody as a Example
+func (t UnionExample200JSONResponseBody) AsExample() (Example, error) {
+ var body Example
+ err := json.Unmarshal(t.union, &body)
+ return body, err
+}
+
+// FromExample overwrites any union data inside the UnionExample200JSONResponseBody as the provided Example
+func (t *UnionExample200JSONResponseBody) FromExample(v Example) error {
+ b, err := json.Marshal(v)
+ t.union = b
+ return err
+}
+
+// MergeExample performs a merge with any union data inside the UnionExample200JSONResponseBody, using the provided Example
+func (t *UnionExample200JSONResponseBody) MergeExample(v Example) error {
+ b, err := json.Marshal(v)
+ if err != nil {
+ return err
+ }
+
+ merged, err := runtime.JSONMerge(t.union, b)
+ t.union = merged
+ return err
+}
+
+func (t UnionExample200JSONResponseBody) MarshalJSON() ([]byte, error) {
+ b, err := t.union.MarshalJSON()
+ return b, err
+}
+
+func (t *UnionExample200JSONResponseBody) UnmarshalJSON(b []byte) error {
+ err := t.union.UnmarshalJSON(b)
+ return err
+}
diff --git a/internal/test/strict-server/strict-schema.yaml b/internal/test/strict-server/strict-schema.yaml
index b757592646..fd5f07feda 100644
--- a/internal/test/strict-server/strict-schema.yaml
+++ b/internal/test/strict-server/strict-schema.yaml
@@ -64,6 +64,25 @@ paths:
$ref: "#/components/responses/badrequest"
default:
description: Unknown error
+ /multipart-related:
+ post:
+ operationId: MultipartRelatedExample
+ requestBody:
+ content:
+ multipart/related:
+ schema:
+ $ref: "#/components/schemas/example"
+ responses:
+ 200:
+ description: OK
+ content:
+ multipart/related:
+ schema:
+ $ref: "#/components/schemas/example"
+ 400:
+ $ref: "#/components/responses/badrequest"
+ default:
+ description: Unknown error
/text:
post:
operationId: TextExample
@@ -173,11 +192,21 @@ paths:
description: OK
headers:
header1:
+ required: true
schema:
type: string
header2:
+ required: true
schema:
type: integer
+ optional-header:
+ required: false
+ schema:
+ type: string
+ nullable-header:
+ schema:
+ type: string
+ nullable: true
content:
application/json:
schema:
@@ -186,6 +215,22 @@ paths:
$ref: "#/components/responses/badrequest"
default:
description: Unknown error
+ /no-content-headers:
+ post:
+ operationId: NoContentHeaders
+ description: No-content (204) response with optional and nullable response headers — exercises that unset headers are omitted from the response
+ responses:
+ 204:
+ description: No Content
+ headers:
+ optional-header:
+ required: false
+ schema:
+ type: string
+ nullable-header:
+ schema:
+ type: string
+ nullable: true
/reusable-responses:
post:
operationId: ReusableResponses
@@ -228,6 +273,48 @@ paths:
$ref: "#/components/responses/badrequest"
default:
description: Unknown error
+ /required-json-body:
+ post:
+ operationId: RequiredJSONBody
+ description: Request body is required, so missing body should always error.
+ requestBody:
+ required: true
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/example"
+ responses:
+ 200:
+ description: OK
+ content:
+ application/json:
+ schema:
+ $ref: "#/components/schemas/example"
+ 400:
+ $ref: "#/components/responses/badrequest"
+ default:
+ description: Unknown error
+ /required-text-body:
+ post:
+ operationId: RequiredTextBody
+ description: Request body is required, so missing body should always error.
+ requestBody:
+ required: true
+ content:
+ text/plain:
+ schema:
+ type: string
+ responses:
+ 200:
+ description: OK
+ content:
+ text/plain:
+ schema:
+ type: string
+ 400:
+ $ref: "#/components/responses/badrequest"
+ default:
+ description: Unknown error
/reserved-go-keyword-parameters/{type}:
get:
operationId: ReservedGoKeywordParameters
@@ -259,9 +346,11 @@ paths:
description: OK
headers:
header1:
+ required: true
schema:
type: string
header2:
+ required: true
schema:
type: integer
content:
@@ -285,9 +374,11 @@ components:
description: OK
headers:
header1:
+ required: true
schema:
type: string
header2:
+ required: true
schema:
type: integer
content:
diff --git a/internal/test/strict-server/strict_test.go b/internal/test/strict-server/strict_test.go
index 04bd95172a..49a6abe25a 100644
--- a/internal/test/strict-server/strict_test.go
+++ b/internal/test/strict-server/strict_test.go
@@ -13,22 +13,18 @@ import (
"github.com/gin-gonic/gin"
"github.com/go-chi/chi/v5"
- "github.com/gofiber/fiber/v2"
- "github.com/gofiber/fiber/v2/middleware/adaptor"
"github.com/kataras/iris/v12"
"github.com/labstack/echo/v4"
"github.com/stretchr/testify/assert"
- chiAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/chi"
- clientAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/client"
- echoAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/echo"
- fiberAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/fiber"
- ginAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/gin"
- irisAPI "github.com/deepmap/oapi-codegen/internal/test/strict-server/iris"
+ chiAPI "github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/chi"
+ clientAPI "github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/client"
+ echoAPI "github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/echo"
+ ginAPI "github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/gin"
+ irisAPI "github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/iris"
- // "github.com/deepmap/oapi-codegen/pkg/runtime"
- "github.com/deepmap/oapi-codegen/pkg/runtime"
- "github.com/deepmap/oapi-codegen/pkg/testutil"
+ "github.com/oapi-codegen/runtime"
+ "github.com/oapi-codegen/testutil"
)
func TestIrisServer(t *testing.T) {
@@ -64,14 +60,6 @@ func TestGinServer(t *testing.T) {
testImpl(t, r)
}
-func TestFiberServer(t *testing.T) {
- server := fiberAPI.StrictServer{}
- strictHandler := fiberAPI.NewStrictHandler(server, nil)
- r := fiber.New()
- fiberAPI.RegisterHandlers(r, strictHandler)
- testImpl(t, adaptor.FiberApp(r))
-}
-
func testImpl(t *testing.T, handler http.Handler) {
t.Run("JSONExample", func(t *testing.T) {
value := "123"
@@ -123,6 +111,30 @@ func testImpl(t *testing.T, handler http.Handler) {
_, err = reader.NextPart()
assert.Equal(t, io.EOF, err)
})
+ t.Run("MultipartRelatedExample", func(t *testing.T) {
+ value := "789"
+ fieldName := "value"
+ var writer bytes.Buffer
+ mw := multipart.NewWriter(&writer)
+ field, err := mw.CreateFormField(fieldName)
+ assert.NoError(t, err)
+ _, _ = field.Write([]byte(value))
+ assert.NoError(t, mw.Close())
+ rr := testutil.NewRequest().Post("/multipart-related").WithContentType(mime.FormatMediaType("multipart/related", map[string]string{"boundary": mw.Boundary()})).WithBody(writer.Bytes()).GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusOK, rr.Code)
+ contentType, params, err := mime.ParseMediaType(rr.Header().Get("Content-Type"))
+ assert.NoError(t, err)
+ assert.Equal(t, "multipart/related", contentType)
+ reader := multipart.NewReader(rr.Body, params["boundary"])
+ part, err := reader.NextPart()
+ assert.NoError(t, err)
+ assert.Equal(t, part.FormName(), fieldName)
+ readValue, err := io.ReadAll(part)
+ assert.NoError(t, err)
+ assert.Equal(t, value, string(readValue))
+ _, err = reader.NextPart()
+ assert.Equal(t, io.EOF, err)
+ })
t.Run("TextExample", func(t *testing.T) {
value := "text"
rr := testutil.NewRequest().Post("/text").WithContentType("text/plain").WithBody([]byte(value)).GoWithHTTPHandler(t, handler).Recorder
@@ -216,6 +228,12 @@ func testImpl(t *testing.T, handler http.Handler) {
assert.Equal(t, header1, rr.Header().Get("header1"))
assert.Equal(t, header2, rr.Header().Get("header2"))
})
+ t.Run("NoContentHeadersOmitUnset", func(t *testing.T) {
+ rr := testutil.NewRequest().Post("/no-content-headers").GoWithHTTPHandler(t, handler).Recorder
+ assert.Equal(t, http.StatusNoContent, rr.Code)
+ assert.Empty(t, rr.Header().Values("optional-header"), "optional-header should be omitted when the response field is nil")
+ assert.Empty(t, rr.Header().Values("nullable-header"), "nullable-header should be omitted when the response field is unspecified")
+ })
t.Run("UnspecifiedContentType", func(t *testing.T) {
data := []byte("image data")
contentType := "image/jpeg"
diff --git a/pkg/chi-middleware/oapi_validate.go b/pkg/chi-middleware/oapi_validate.go
deleted file mode 100644
index 80b7f3a033..0000000000
--- a/pkg/chi-middleware/oapi_validate.go
+++ /dev/null
@@ -1,146 +0,0 @@
-// Package middleware implements middleware function for go-chi or net/http,
-// which validates incoming HTTP requests to make sure that they conform to the given OAPI 3.0 specification.
-// When OAPI validation fails on the request, we return an HTTP/400.
-package middleware
-
-import (
- "errors"
- "fmt"
- "log"
- "net/http"
- "strings"
-
- "github.com/getkin/kin-openapi/openapi3"
- "github.com/getkin/kin-openapi/openapi3filter"
- "github.com/getkin/kin-openapi/routers"
- "github.com/getkin/kin-openapi/routers/gorillamux"
-)
-
-// ErrorHandler is called when there is an error in validation
-// Deprecated: This has been replaced by github.com/oapi-codegen/nethttp-middleware#ErrorHandler
-type ErrorHandler func(w http.ResponseWriter, message string, statusCode int)
-
-// MultiErrorHandler is called when oapi returns a MultiError type
-// Deprecated: This has been replaced by github.com/oapi-codegen/nethttp-middleware#
-type MultiErrorHandler func(openapi3.MultiError) (int, error)
-
-// Options to customize request validation, openapi3filter specified options will be passed through.
-// Deprecated: This has been replaced by github.com/oapi-codegen/nethttp-middleware#Options
-type Options struct {
- Options openapi3filter.Options
- ErrorHandler ErrorHandler
- MultiErrorHandler MultiErrorHandler
- // SilenceServersWarning allows silencing a warning for https://github.com/deepmap/oapi-codegen/issues/882 that reports when an OpenAPI spec has `spec.Servers != nil`
- SilenceServersWarning bool
-}
-
-// OapiRequestValidator Creates middleware to validate request by swagger spec.
-// This middleware is good for net/http either since go-chi is 100% compatible with net/http.
-// Deprecated: This has been replaced by github.com/oapi-codegen/nethttp-middleware#OapiRequestValidator
-func OapiRequestValidator(swagger *openapi3.T) func(next http.Handler) http.Handler {
- return OapiRequestValidatorWithOptions(swagger, nil)
-}
-
-// OapiRequestValidatorWithOptions Creates middleware to validate request by swagger spec.
-// This middleware is good for net/http either since go-chi is 100% compatible with net/http.
-// Deprecated: This has been replaced by github.com/oapi-codegen/nethttp-middleware#OapiRequestValidatorWithOptions
-func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) func(next http.Handler) http.Handler {
- if swagger.Servers != nil && (options == nil || !options.SilenceServersWarning) {
- log.Println("WARN: OapiRequestValidatorWithOptions called with an OpenAPI spec that has `Servers` set. This may lead to an HTTP 400 with `no matching operation was found` when sending a valid request, as the validator performs `Host` header validation. If you're expecting `Host` header validation, you can silence this warning by setting `Options.SilenceServersWarning = true`. See https://github.com/deepmap/oapi-codegen/issues/882 for more information.")
- }
-
- router, err := gorillamux.NewRouter(swagger)
- if err != nil {
- panic(err)
- }
-
- return func(next http.Handler) http.Handler {
- return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-
- // validate request
- if statusCode, err := validateRequest(r, router, options); err != nil {
- if options != nil && options.ErrorHandler != nil {
- options.ErrorHandler(w, err.Error(), statusCode)
- } else {
- http.Error(w, err.Error(), statusCode)
- }
- return
- }
-
- // serve
- next.ServeHTTP(w, r)
- })
- }
-
-}
-
-// validateRequest is called from the middleware above and actually does the work
-// of validating a request.
-// Deprecated: This has been replaced by github.com/oapi-codegen/nethttp-middleware#validateRequest
-func validateRequest(r *http.Request, router routers.Router, options *Options) (int, error) {
-
- // Find route
- route, pathParams, err := router.FindRoute(r)
- if err != nil {
- return http.StatusNotFound, err // We failed to find a matching route for the request.
- }
-
- // Validate request
- requestValidationInput := &openapi3filter.RequestValidationInput{
- Request: r,
- PathParams: pathParams,
- Route: route,
- }
-
- if options != nil {
- requestValidationInput.Options = &options.Options
- }
-
- if err := openapi3filter.ValidateRequest(r.Context(), requestValidationInput); err != nil {
- me := openapi3.MultiError{}
- if errors.As(err, &me) {
- errFunc := getMultiErrorHandlerFromOptions(options)
- return errFunc(me)
- }
-
- switch e := err.(type) {
- case *openapi3filter.RequestError:
- // We've got a bad request
- // Split up the verbose error by lines and return the first one
- // openapi errors seem to be multi-line with a decent message on the first
- errorLines := strings.Split(e.Error(), "\n")
- return http.StatusBadRequest, fmt.Errorf(errorLines[0])
- case *openapi3filter.SecurityRequirementsError:
- return http.StatusUnauthorized, err
- default:
- // This should never happen today, but if our upstream code changes,
- // we don't want to crash the server, so handle the unexpected error.
- return http.StatusInternalServerError, fmt.Errorf("error validating route: %s", err.Error())
- }
- }
-
- return http.StatusOK, nil
-}
-
-// attempt to get the MultiErrorHandler from the options. If it is not set,
-// return a default handler
-// Deprecated: This has been replaced by github.com/oapi-codegen/nethttp-middleware#getMultiErrorHandlerFromOptions
-func getMultiErrorHandlerFromOptions(options *Options) MultiErrorHandler {
- if options == nil {
- return defaultMultiErrorHandler
- }
-
- if options.MultiErrorHandler == nil {
- return defaultMultiErrorHandler
- }
-
- return options.MultiErrorHandler
-}
-
-// defaultMultiErrorHandler returns a StatusBadRequest (400) and a list
-// of all the errors. This method is called if there are no other
-// methods defined on the options.
-// Deprecated: This has been replaced by github.com/oapi-codegen/nethttp-middleware#defaultMultiErrorHandler
-func defaultMultiErrorHandler(me openapi3.MultiError) (int, error) {
- return http.StatusBadRequest, me
-}
diff --git a/pkg/chi-middleware/oapi_validate_test.go b/pkg/chi-middleware/oapi_validate_test.go
deleted file mode 100644
index 44816dc513..0000000000
--- a/pkg/chi-middleware/oapi_validate_test.go
+++ /dev/null
@@ -1,405 +0,0 @@
-package middleware
-
-import (
- "context"
- _ "embed"
- "errors"
- "io"
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/deepmap/oapi-codegen/pkg/testutil"
- "github.com/getkin/kin-openapi/openapi3"
- "github.com/getkin/kin-openapi/openapi3filter"
- "github.com/go-chi/chi/v5"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-//go:embed test_spec.yaml
-var testSchema []byte
-
-func doGet(t *testing.T, mux *chi.Mux, rawURL string) *httptest.ResponseRecorder {
- u, err := url.Parse(rawURL)
- if err != nil {
- t.Fatalf("Invalid url: %s", rawURL)
- }
-
- response := testutil.NewRequest().Get(u.RequestURI()).WithHost(u.Host).WithAcceptJson().GoWithHTTPHandler(t, mux)
- return response.Recorder
-}
-
-func doPost(t *testing.T, mux *chi.Mux, rawURL string, jsonBody interface{}) *httptest.ResponseRecorder {
- u, err := url.Parse(rawURL)
- if err != nil {
- t.Fatalf("Invalid url: %s", rawURL)
- }
-
- response := testutil.NewRequest().Post(u.RequestURI()).WithHost(u.Host).WithJsonBody(jsonBody).GoWithHTTPHandler(t, mux)
- return response.Recorder
-}
-
-func TestOapiRequestValidator(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- r := chi.NewRouter()
-
- // register middleware
- r.Use(OapiRequestValidator(swagger))
-
- // basic cases
- testRequestValidatorBasicFunctions(t, r)
-}
-
-func TestOapiRequestValidatorWithOptionsMultiError(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- r := chi.NewRouter()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- Options: openapi3filter.Options{
- ExcludeRequestBody: false,
- ExcludeResponseBody: false,
- IncludeResponseStatus: true,
- MultiError: true,
- },
- }
-
- // register middleware
- r.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- r.Get("/multiparamresource", func(w http.ResponseWriter, r *http.Request) {
- called = true
- })
-
- // Let's send a good request, it should pass
- {
- rec := doGet(t, r, "http://deepmap.ai/multiparamresource?id=50&id2=50")
- assert.Equal(t, http.StatusOK, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Let's send a request with a missing parameter, it should return
- // a bad status
- {
- rec := doGet(t, r, "http://deepmap.ai/multiparamresource?id=50")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 2 missing parameters, it should return
- // a bad status
- {
- rec := doGet(t, r, "http://deepmap.ai/multiparamresource")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "value is required but missing")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 1 missing parameter, and another outside
- // or the parameters. It should return a bad status
- {
- rec := doGet(t, r, "http://deepmap.ai/multiparamresource?id=500")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "number must be at most 100")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a parameters that do not meet spec. It should
- // return a bad status
- {
- rec := doGet(t, r, "http://deepmap.ai/multiparamresource?id=abc&id2=1")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "number must be at least 10")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-}
-
-func TestOapiRequestValidatorWithOptionsMultiErrorAndCustomHandler(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- r := chi.NewRouter()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- Options: openapi3filter.Options{
- ExcludeRequestBody: false,
- ExcludeResponseBody: false,
- IncludeResponseStatus: true,
- MultiError: true,
- },
- MultiErrorHandler: func(me openapi3.MultiError) (int, error) {
- return http.StatusTeapot, me
- },
- }
-
- // register middleware
- r.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- r.Get("/multiparamresource", func(w http.ResponseWriter, r *http.Request) {
- called = true
- })
-
- // Let's send a good request, it should pass
- {
- rec := doGet(t, r, "http://deepmap.ai/multiparamresource?id=50&id2=50")
- assert.Equal(t, http.StatusOK, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Let's send a request with a missing parameter, it should return
- // a bad status
- {
- rec := doGet(t, r, "http://deepmap.ai/multiparamresource?id=50")
- assert.Equal(t, http.StatusTeapot, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 2 missing parameters, it should return
- // a bad status
- {
- rec := doGet(t, r, "http://deepmap.ai/multiparamresource")
- assert.Equal(t, http.StatusTeapot, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "value is required but missing")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 1 missing parameter, and another outside
- // or the parameters. It should return a bad status
- {
- rec := doGet(t, r, "http://deepmap.ai/multiparamresource?id=500")
- assert.Equal(t, http.StatusTeapot, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "number must be at most 100")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a parameters that do not meet spec. It should
- // return a bad status
- {
- rec := doGet(t, r, "http://deepmap.ai/multiparamresource?id=abc&id2=1")
- assert.Equal(t, http.StatusTeapot, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "number must be at least 10")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-}
-
-func TestOapiRequestValidatorWithOptions(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- r := chi.NewRouter()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- ErrorHandler: func(w http.ResponseWriter, message string, statusCode int) {
- http.Error(w, "test: "+message, statusCode)
- },
- Options: openapi3filter.Options{
- AuthenticationFunc: func(c context.Context, input *openapi3filter.AuthenticationInput) error {
-
- for _, s := range input.Scopes {
- if s == "someScope" {
- return nil
- }
- }
- return errors.New("unauthorized")
- },
- },
- }
-
- // register middleware
- r.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- // basic cases
- testRequestValidatorBasicFunctions(t, r)
-
- called := false
-
- r.Get("/protected_resource", func(w http.ResponseWriter, r *http.Request) {
- called = true
- w.WriteHeader(http.StatusNoContent)
- })
-
- // Call a protected function to which we have access
- {
- rec := doGet(t, r, "http://deepmap.ai/protected_resource")
- assert.Equal(t, http.StatusNoContent, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- r.Get("/protected_resource2", func(w http.ResponseWriter, r *http.Request) {
- called = true
- w.WriteHeader(http.StatusNoContent)
- })
- // Call a protected function to which we dont have access
- {
- rec := doGet(t, r, "http://deepmap.ai/protected_resource2")
- assert.Equal(t, http.StatusUnauthorized, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- r.Get("/protected_resource_401", func(w http.ResponseWriter, r *http.Request) {
- called = true
- w.WriteHeader(http.StatusNoContent)
- })
- // Call a protected function without credentials
- {
- rec := doGet(t, r, "http://deepmap.ai/protected_resource_401")
- assert.Equal(t, http.StatusUnauthorized, rec.Code)
- assert.Equal(t, "test: security requirements failed: unauthorized\n", rec.Body.String())
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
-}
-
-func testRequestValidatorBasicFunctions(t *testing.T, r *chi.Mux) {
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- r.Get("/resource", func(w http.ResponseWriter, r *http.Request) {
- called = true
- })
-
- // Let's send the request to the wrong server, this should return 404
- {
- rec := doGet(t, r, "http://not.deepmap.ai/resource")
- assert.Equal(t, http.StatusNotFound, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- }
-
- // Let's send a good request, it should pass
- {
- rec := doGet(t, r, "http://deepmap.ai/resource")
- assert.Equal(t, http.StatusOK, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Send an out-of-spec parameter
- {
- rec := doGet(t, r, "http://deepmap.ai/resource?id=500")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Send a bad parameter type
- {
- rec := doGet(t, r, "http://deepmap.ai/resource?id=foo")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Add a handler for the POST message
- r.Post("/resource", func(w http.ResponseWriter, r *http.Request) {
- called = true
- w.WriteHeader(http.StatusNoContent)
- })
-
- called = false
- // Send a good request body
- {
- body := struct {
- Name string `json:"name"`
- }{
- Name: "Marcin",
- }
- rec := doPost(t, r, "http://deepmap.ai/resource", body)
- assert.Equal(t, http.StatusNoContent, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Send a malformed body
- {
- body := struct {
- Name int `json:"name"`
- }{
- Name: 7,
- }
- rec := doPost(t, r, "http://deepmap.ai/resource", body)
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
-}
diff --git a/pkg/chi-middleware/test_spec.yaml b/pkg/chi-middleware/test_spec.yaml
deleted file mode 100644
index 6e0a2415d2..0000000000
--- a/pkg/chi-middleware/test_spec.yaml
+++ /dev/null
@@ -1,103 +0,0 @@
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: TestServer
-servers:
- - url: http://deepmap.ai/
-paths:
- /resource:
- get:
- operationId: getResource
- parameters:
- - name: id
- in: query
- schema:
- type: integer
- minimum: 10
- maximum: 100
- responses:
- '200':
- description: success
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- id:
- type: integer
- post:
- operationId: createResource
- responses:
- '204':
- description: No content
- requestBody:
- required: true
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- /protected_resource:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - someScope
- responses:
- '204':
- description: no content
- /protected_resource2:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - otherScope
- responses:
- '204':
- description: no content
- /protected_resource_401:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - unauthorized
- responses:
- '401':
- description: no content
- /multiparamresource:
- get:
- operationId: getResource
- parameters:
- - name: id
- in: query
- required: true
- schema:
- type: integer
- minimum: 10
- maximum: 100
- - name: id2
- required: true
- in: query
- schema:
- type: integer
- minimum: 10
- maximum: 100
- responses:
- '200':
- description: success
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- id:
- type: integer
-components:
- securitySchemes:
- BearerAuth:
- type: http
- scheme: bearer
- bearerFormat: JWT
diff --git a/pkg/codegen/codegen.go b/pkg/codegen/codegen.go
index e292cfe5a1..22317bda16 100644
--- a/pkg/codegen/codegen.go
+++ b/pkg/codegen/codegen.go
@@ -19,20 +19,26 @@ import (
"bytes"
"context"
"embed"
+ "errors"
"fmt"
+ "go/scanner"
"io"
"io/fs"
+ "maps"
"net/http"
"os"
+ "regexp"
"runtime/debug"
+ "slices"
"sort"
"strings"
"text/template"
"time"
- "github.com/deepmap/oapi-codegen/pkg/util"
"github.com/getkin/kin-openapi/openapi3"
"golang.org/x/tools/imports"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/util"
)
// Embed the templates directory
@@ -46,6 +52,20 @@ var globalState struct {
options Configuration
spec *openapi3.T
importMapping importMap
+ // initialismsMap stores initialisms as "lower(initialism) -> initialism" map.
+ // List of initialisms was taken from https://staticcheck.io/docs/configuration/options/#initialisms.
+ initialismsMap map[string]string
+ // typeMapping is the merged type mapping (defaults + user overrides).
+ typeMapping TypeMapping
+ // resolvedNames maps schema path strings (e.g. "components/schemas/Pet")
+ // to their resolved Go type names, assigned by the multi-pass name resolver.
+ resolvedNames map[string]string
+ // resolvedClientWrapperNames maps operationID to the resolved Go type name
+ // for client response wrapper types (e.g., "createChatCompletion" -> "CreateChatCompletionResponseWrapper").
+ resolvedClientWrapperNames map[string]string
+ // streamingContentTypeRegexes are the compiled regexes (defaults + user)
+ // used by ResponseContentDefinition.IsStreamingContentType.
+ streamingContentTypeRegexes []*regexp.Regexp
}
// goImport represents a go package to be imported in the generated code
@@ -65,10 +85,18 @@ func (gi goImport) String() string {
// importMap maps external OpenAPI specifications files/urls to external go packages
type importMap map[string]goImport
+// importMappingCurrentPackage allows an Import Mapping to map to the current package, rather than an external package.
+// This allows users to split their OpenAPI specification across multiple files, but keep them in the same package, which can reduce a bit of the overhead for users.
+// We use `-` to indicate that this is a bit of a special case
+const importMappingCurrentPackage = "-"
+
// GoImports returns a slice of go import statements
func (im importMap) GoImports() []string {
goImports := make([]string, 0, len(im))
for _, v := range im {
+ if v.Path == importMappingCurrentPackage {
+ continue
+ }
goImports = append(goImports, v.String())
}
return goImports
@@ -76,25 +104,41 @@ func (im importMap) GoImports() []string {
func constructImportMapping(importMapping map[string]string) importMap {
var (
- pathToName = map[string]string{}
- result = importMap{}
+ pathToImport = importMap{}
+ result = importMap{}
)
{
- var packagePaths []string
- for _, packageName := range importMapping {
- packagePaths = append(packagePaths, packageName)
- }
- sort.Strings(packagePaths)
+ packagePaths := slices.Collect(maps.Values(importMapping))
+ slices.Sort(packagePaths)
for _, packagePath := range packagePaths {
- if _, ok := pathToName[packagePath]; !ok {
- pathToName[packagePath] = fmt.Sprintf("externalRef%d", len(pathToName))
+ if _, ok := pathToImport[packagePath]; !ok && packagePath != importMappingCurrentPackage {
+ split := strings.Split(packagePath, " ")
+ if len(split) == 2 {
+ // if we have 2 parts, we assume both the package name and path are provided, and we use them as is
+ pathToImport[packagePath] = goImport{
+ Name: split[0],
+ Path: split[1],
+ }
+ } else {
+ // otherwise, we auto-generate a package name based on the order of the imports, to ensure deterministic output
+ pathToImport[packagePath] = goImport{
+ Name: fmt.Sprintf("externalRef%d", len(pathToImport)),
+ Path: packagePath,
+ }
+ }
}
}
}
for specPath, packagePath := range importMapping {
- result[specPath] = goImport{Name: pathToName[packagePath], Path: packagePath}
+ if packagePath == importMappingCurrentPackage {
+ result[specPath] = goImport{
+ Path: importMappingCurrentPackage,
+ }
+ } else {
+ result[specPath] = pathToImport[packagePath]
+ }
}
return result
}
@@ -107,8 +151,14 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
globalState.options = opts
globalState.spec = spec
globalState.importMapping = constructImportMapping(opts.ImportMapping)
+ if opts.OutputOptions.TypeMapping != nil {
+ globalState.typeMapping = DefaultTypeMapping.Merge(*opts.OutputOptions.TypeMapping)
+ } else {
+ globalState.typeMapping = DefaultTypeMapping
+ }
filterOperationsByTag(spec, opts)
+ filterOperationsByOperationID(spec, opts)
if !opts.OutputOptions.SkipPrune {
pruneUnusedComponents(spec)
}
@@ -122,12 +172,55 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
globalState.options.OutputOptions.ClientTypeName = defaultClientTypeName
}
+ nameNormalizerFunction := NameNormalizerFunction(opts.OutputOptions.NameNormalizer)
+ nameNormalizer = NameNormalizers[nameNormalizerFunction]
+ if nameNormalizer == nil {
+ return "", fmt.Errorf(`the name-normalizer option %v could not be found among options %q`,
+ opts.OutputOptions.NameNormalizer, NameNormalizers.Options())
+ }
+
+ if nameNormalizerFunction != NameNormalizerFunctionToCamelCaseWithInitialisms && len(opts.OutputOptions.AdditionalInitialisms) > 0 {
+ return "", fmt.Errorf("you have specified `additional-initialisms`, but the `name-normalizer` is not set to `ToCamelCaseWithInitialisms`. Please specify `name-normalizer: ToCamelCaseWithInitialisms` or remove the `additional-initialisms` configuration")
+ }
+
+ globalState.initialismsMap = makeInitialismsMap(opts.OutputOptions.AdditionalInitialisms)
+
+ // Compile streaming-content-type patterns (defaults merged with user-supplied).
+ // Validate() already caught syntax errors, but surface any regression here too.
+ streamingRegexes, err := compileStreamingContentTypes(opts.OutputOptions.StreamingContentTypes)
+ if err != nil {
+ return "", err
+ }
+ globalState.streamingContentTypeRegexes = streamingRegexes
+
+ // Multi-pass name resolution: gather all schemas, then resolve names globally.
+ // Only enabled when resolve-type-name-collisions is set.
+ if opts.OutputOptions.ResolveTypeNameCollisions {
+ gathered := GatherSchemas(spec, opts)
+ globalState.resolvedNames = ResolveNames(gathered)
+ // Build a separate operationID -> wrapper name lookup for genResponseTypeName.
+ // Keys must use the normalized operationID (via nameNormalizer) because
+ // OperationDefinition.OperationId is normalized before templates run.
+ globalState.resolvedClientWrapperNames = make(map[string]string)
+ for _, gs := range gathered {
+ if gs.Context == ContextClientResponseWrapper && gs.OperationID != "" {
+ if name, ok := globalState.resolvedNames[gs.Path.String()]; ok {
+ normalizedOpID := nameNormalizer(gs.OperationID)
+ globalState.resolvedClientWrapperNames[normalizedOpID] = name
+ }
+ }
+ }
+ } else {
+ globalState.resolvedNames = nil
+ globalState.resolvedClientWrapperNames = nil
+ }
+
// This creates the golang templates text package
TemplateFunctions["opts"] = func() Configuration { return globalState.options }
t := template.New("oapi-codegen").Funcs(TemplateFunctions)
// This parses all of our own template files into the template object
// above
- err := LoadTemplates(templates, t)
+ err = LoadTemplates(templates, t)
if err != nil {
return "", fmt.Errorf("error parsing oapi-codegen templates: %w", err)
}
@@ -147,7 +240,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
}
}
- ops, err := OperationDefinitions(spec, opts.OutputOptions.InitialismOverrides)
+ ops, err := OperationDefinitions(spec)
if err != nil {
return "", fmt.Errorf("error creating operation definitions: %w", err)
}
@@ -173,7 +266,36 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
if err != nil {
return "", fmt.Errorf("error getting type definition imports: %w", err)
}
- MergeImports(xGoTypeImports, imprts)
+ maps.Copy(xGoTypeImports, imprts)
+ }
+
+ var serverURLsDefinitions string
+ if opts.Generate.ServerURLs {
+ // Server-URL enum-typed variables are routed through the same
+ // typedef.tmpl + constants.tmpl pipelines as any other
+ // enum-bearing schema, so they get matching `type X string`,
+ // `const ( … )` block, and `Valid()` method. We do this here
+ // (rather than in GenerateTypeDefinitions) so the types are
+ // emitted even when `generate.models` is disabled.
+ serverURLEnumTypes, err := BuildServerURLTypeDefinitions(spec)
+ if err != nil {
+ return "", fmt.Errorf("error generating Go types for server URL variables: %w", err)
+ }
+ serverURLEnumTypeDecls, err := GenerateTypes(t, serverURLEnumTypes)
+ if err != nil {
+ return "", fmt.Errorf("error generating type declarations for server URL variables: %w", err)
+ }
+ serverURLEnumConstants, err := GenerateEnums(t, serverURLEnumTypes)
+ if err != nil {
+ return "", fmt.Errorf("error generating enums for server URL variables: %w", err)
+ }
+
+ serverURLsBody, err := GenerateServerURLs(t, spec)
+ if err != nil {
+ return "", fmt.Errorf("error generating Server URLs: %w", err)
+ }
+
+ serverURLsDefinitions = serverURLEnumTypeDecls + serverURLEnumConstants + serverURLsBody
}
var irisServerOut string
@@ -192,6 +314,14 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
}
}
+ var echo5ServerOut string
+ if opts.Generate.Echo5Server {
+ echo5ServerOut, err = GenerateEcho5Server(t, ops)
+ if err != nil {
+ return "", fmt.Errorf("error generating Go handlers for Paths: %w", err)
+ }
+ }
+
var chiServerOut string
if opts.Generate.ChiServer {
chiServerOut, err = GenerateChiServer(t, ops)
@@ -224,11 +354,19 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
}
}
+ var stdHTTPServerOut string
+ if opts.Generate.StdHTTPServer {
+ stdHTTPServerOut, err = GenerateStdHTTPServer(t, ops)
+ if err != nil {
+ return "", fmt.Errorf("error generating Go handlers for Paths: %w", err)
+ }
+ }
+
var strictServerOut string
if opts.Generate.Strict {
var responses []ResponseDefinition
if spec.Components != nil {
- responses, err = GenerateResponseDefinitions("", spec.Components.Responses)
+ responses, err = GenerateResponseDefinitions("", spec.Components.Responses, "")
if err != nil {
return "", fmt.Errorf("error generation response definitions for schema: %w", err)
}
@@ -292,6 +430,11 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
return "", fmt.Errorf("error writing constants: %w", err)
}
+ _, err = w.WriteString(serverURLsDefinitions)
+ if err != nil {
+ return "", fmt.Errorf("error writing Server URLs: %w", err)
+ }
+
_, err = w.WriteString(typeDefinitions)
if err != nil {
return "", fmt.Errorf("error writing type definitions: %w", err)
@@ -323,6 +466,13 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
}
}
+ if opts.Generate.Echo5Server {
+ _, err = w.WriteString(echo5ServerOut)
+ if err != nil {
+ return "", fmt.Errorf("error writing server path handlers: %w", err)
+ }
+ }
+
if opts.Generate.ChiServer {
_, err = w.WriteString(chiServerOut)
if err != nil {
@@ -351,6 +501,13 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
}
}
+ if opts.Generate.StdHTTPServer {
+ _, err = w.WriteString(stdHTTPServerOut)
+ if err != nil {
+ return "", fmt.Errorf("error writing server path handlers: %w", err)
+ }
+ }
+
if opts.Generate.Strict {
_, err = w.WriteString(strictServerOut)
if err != nil {
@@ -381,7 +538,15 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
outBytes, err := imports.Process(opts.PackageName+".go", []byte(goCode), nil)
if err != nil {
- return "", fmt.Errorf("error formatting Go code %s: %w", goCode, err)
+ errLine := -1
+ var scanErr scanner.ErrorList
+ if errors.As(err, &scanErr) && scanErr.Len() > 0 {
+ errLine = scanErr[0].Pos.Line
+ }
+ if errLine > 0 {
+ return goCode, fmt.Errorf("error formatting Go code at line %d: %w", errLine, err)
+ }
+ return goCode, fmt.Errorf("error formatting Go code: %w", err)
}
return string(outBytes), nil
}
@@ -411,15 +576,36 @@ func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []Op
return "", fmt.Errorf("error generating Go types for component request bodies: %w", err)
}
allTypes = append(allTypes, bodyTypes...)
- }
- // Go through all operations, and add their types to allTypes, so that we can
- // scan all of them for enums. Operation definitions are handled differently
- // from the rest, so let's keep track of enumTypes separately, which will contain
- // all types needed to be scanned for enums, which includes those within operations.
- enumTypes := allTypes
+ securitySchemeTypes, err := GenerateTypesForSecuritySchemes(t, swagger.Components.SecuritySchemes)
+ if err != nil {
+ return "", fmt.Errorf("error generating Go types for component security schemes: %w", err)
+ }
+ allTypes = append(allTypes, securitySchemeTypes...)
+ }
+
+ // allTypes stays components-only — it's the slice passed to
+ // GenerateTypes (typedef.tmpl) for top-level type declarations.
+ // Op-derived types are declared by their per-context templates
+ // (param-types.tmpl, request-bodies.tmpl, client-with-responses.tmpl).
+ //
+ // boilerplateTypes is the wider universe for the method-emitting
+ // passes (enum scanning, additionalProperties marshalers, union
+ // accessors). Inline union/additionalProperties types living
+ // inside operations (params, request bodies, response schemas
+ // and any nested AdditionalTypeDefinitions) historically never
+ // reached these passes, so accessor methods were silently
+ // missing. Folding them in here is what fixes that.
+ boilerplateTypes := slices.Clone(allTypes)
for _, op := range ops {
- enumTypes = append(enumTypes, op.TypeDefinitions...)
+ boilerplateTypes = append(boilerplateTypes, op.TypeDefinitions...)
+ respDefs, err := op.GetResponseTypeDefinitions()
+ if err != nil {
+ return "", fmt.Errorf("error collecting response type definitions for %s: %w", op.OperationId, err)
+ }
+ for _, rd := range respDefs {
+ boilerplateTypes = append(boilerplateTypes, rd.AdditionalTypeDefinitions...)
+ }
}
operationsOut, err := GenerateTypesForOperations(t, ops)
@@ -427,7 +613,7 @@ func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []Op
return "", fmt.Errorf("error generating Go types for component request bodies: %w", err)
}
- enumsOut, err := GenerateEnums(t, enumTypes)
+ enumsOut, err := GenerateEnums(t, boilerplateTypes)
if err != nil {
return "", fmt.Errorf("error generating code for type enums: %w", err)
}
@@ -437,17 +623,17 @@ func GenerateTypeDefinitions(t *template.Template, swagger *openapi3.T, ops []Op
return "", fmt.Errorf("error generating code for type definitions: %w", err)
}
- allOfBoilerplate, err := GenerateAdditionalPropertyBoilerplate(t, allTypes)
+ allOfBoilerplate, err := GenerateAdditionalPropertyBoilerplate(t, boilerplateTypes)
if err != nil {
return "", fmt.Errorf("error generating allOf boilerplate: %w", err)
}
- unionBoilerplate, err := GenerateUnionBoilerplate(t, allTypes)
+ unionBoilerplate, err := GenerateUnionBoilerplate(t, boilerplateTypes)
if err != nil {
return "", fmt.Errorf("error generating union boilerplate: %w", err)
}
- unionAndAdditionalBoilerplate, err := GenerateUnionAndAdditionalProopertiesBoilerplate(t, allTypes)
+ unionAndAdditionalBoilerplate, err := GenerateUnionAndAdditionalProopertiesBoilerplate(t, boilerplateTypes)
if err != nil {
return "", fmt.Errorf("error generating boilerplate for union types with additionalProperties: %w", err)
}
@@ -470,11 +656,7 @@ func GenerateConstants(t *template.Template, ops []OperationDefinition) (string,
}
}
- var providerNames []string
- for providerName := range providerNameMap {
- providerNames = append(providerNames, providerName)
- }
-
+ providerNames := slices.Collect(maps.Keys(providerNameMap))
sort.Strings(providerNames)
constants.SecuritySchemeProviderNames = append(constants.SecuritySchemeProviderNames, providerNames...)
@@ -507,13 +689,17 @@ func GenerateTypesForSchemas(t *template.Template, schemas map[string]*openapi3.
return nil, fmt.Errorf("error making name for components/schemas/%s: %w", schemaName, err)
}
+ if resolved := resolvedNameForComponent("schemas", schemaName); resolved != "" {
+ goTypeName = resolved
+ }
+
types = append(types, TypeDefinition{
JsonName: schemaName,
TypeName: goTypeName,
Schema: goSchema,
})
- types = append(types, goSchema.GetAdditionalTypeDefs()...)
+ types = append(types, goSchema.AdditionalTypes...)
}
return types, nil
}
@@ -522,7 +708,7 @@ func GenerateTypesForSchemas(t *template.Template, schemas map[string]*openapi3.
// components/parameters section of the Swagger spec.
func GenerateTypesForParameters(t *template.Template, params map[string]*openapi3.ParameterRef) ([]TypeDefinition, error) {
var types []TypeDefinition
- for _, paramName := range SortedParameterKeys(params) {
+ for _, paramName := range SortedMapKeys(params) {
paramOrRef := params[paramName]
goType, err := paramToGoType(paramOrRef.Value, nil)
@@ -535,6 +721,10 @@ func GenerateTypesForParameters(t *template.Template, params map[string]*openapi
return nil, fmt.Errorf("error making name for components/parameters/%s: %w", paramName, err)
}
+ if resolved := resolvedNameForComponent("parameters", paramName); resolved != "" {
+ goTypeName = resolved
+ }
+
typeDef := TypeDefinition{
JsonName: paramName,
Schema: goType,
@@ -557,10 +747,10 @@ func GenerateTypesForParameters(t *template.Template, params map[string]*openapi
// GenerateTypesForResponses generates type definitions for any custom types defined in the
// components/responses section of the Swagger spec.
-func GenerateTypesForResponses(t *template.Template, responses openapi3.Responses) ([]TypeDefinition, error) {
+func GenerateTypesForResponses(t *template.Template, responses openapi3.ResponseBodies) ([]TypeDefinition, error) {
var types []TypeDefinition
- for _, responseName := range SortedResponsesKeys(responses) {
+ for _, responseName := range SortedMapKeys(responses) {
responseOrRef := responses[responseName]
// We have to generate the response object. We're only going to
@@ -575,14 +765,29 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response
}
}
- sortedContentKeys := SortedContentKeys(response.Content)
- for _, mediaType := range sortedContentKeys {
+ SortedMapKeys := SortedMapKeys(response.Content)
+ for _, mediaType := range SortedMapKeys {
response := response.Content[mediaType]
if !util.IsMediaTypeJson(mediaType) {
continue
}
- goType, err := GenerateGoSchema(response.Schema, []string{responseName})
+ // When a response has multiple JSON content types, include the
+ // content type in the schema path so that inline types (e.g.,
+ // oneOf union members) get unique names per content type.
+ // See the matching logic in GetResponseTypeDefinitions.
+ //
+ // We only add the content type segment when collision resolution
+ // is enabled (resolve-type-name-collisions) and jsonCount > 1,
+ // to avoid changing type names for existing users. Ideally the
+ // media type would always be part of the path for consistency.
+ // TODO: revisit this at the next major version change —
+ // always include the media type in the schema path.
+ schemaPath := []string{responseName}
+ if jsonCount > 1 && globalState.options.OutputOptions.ResolveTypeNameCollisions {
+ schemaPath = append(schemaPath, mediaTypeToCamelCase(mediaType))
+ }
+ goType, err := GenerateGoSchema(response.Schema, schemaPath)
if err != nil {
return nil, fmt.Errorf("error generating Go type for schema in response %s: %w", responseName, err)
}
@@ -592,6 +797,10 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response
return nil, fmt.Errorf("error making name for components/responses/%s: %w", responseName, err)
}
+ if resolved := resolvedNameForComponent("responses", responseName, mediaType); resolved != "" {
+ goTypeName = resolved
+ }
+
typeDef := TypeDefinition{
JsonName: responseName,
Schema: goType,
@@ -612,6 +821,7 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response
}
types = append(types, typeDef)
+ types = append(types, goType.AdditionalTypes...)
}
}
return types, nil
@@ -622,13 +832,14 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response
func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*openapi3.RequestBodyRef) ([]TypeDefinition, error) {
var types []TypeDefinition
- for _, requestBodyName := range SortedRequestBodyKeys(bodies) {
+ for _, requestBodyName := range SortedMapKeys(bodies) {
requestBodyRef := bodies[requestBodyName]
// As for responses, we will only generate Go code for JSON bodies,
// the other body formats are up to the user.
response := requestBodyRef.Value
- for mediaType, body := range response.Content {
+ for _, mediaType := range SortedMapKeys(response.Content) {
+ body := response.Content[mediaType]
if !util.IsMediaTypeJson(mediaType) {
continue
}
@@ -643,6 +854,10 @@ func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*open
return nil, fmt.Errorf("error making name for components/schemas/%s: %w", requestBodyName, err)
}
+ if resolved := resolvedNameForComponent("requestBodies", requestBodyName, mediaType); resolved != "" {
+ goTypeName = resolved
+ }
+
typeDef := TypeDefinition{
JsonName: requestBodyName,
Schema: goType,
@@ -658,8 +873,32 @@ func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*open
typeDef.TypeName = SchemaNameToTypeName(refType)
}
types = append(types, typeDef)
+ types = append(types, goType.AdditionalTypes...)
+ }
+ }
+ return types, nil
+}
+
+// GenerateTypesForSecuritySchemes generates type definitions for any custom types defined in the
+// components/securitySchemes section of the Swagger spec.
+func GenerateTypesForSecuritySchemes(t *template.Template, schemes map[string]*openapi3.SecuritySchemeRef) ([]TypeDefinition, error) {
+ var types []TypeDefinition
+
+ for _, schemeName := range SortedSecuritySchemeKeys(schemes) {
+ // Generate a type to be used as a key in context.WithValue
+ goTypeName := LowercaseFirstCharacter(SchemaNameToTypeName(schemeName)) + "ContextKey"
+ goType := Schema{
+ GoType: "string",
+ Description: fmt.Sprintf("is the context key for %s security scheme", schemeName),
}
+
+ types = append(types, TypeDefinition{
+ JsonName: schemeName,
+ TypeName: goTypeName,
+ Schema: goType,
+ })
}
+
return types, nil
}
@@ -672,12 +911,11 @@ func GenerateTypes(t *template.Template, types []TypeDefinition) (string, error)
for _, typ := range types {
if prevType, found := m[typ.TypeName]; found {
// If type names collide, we need to see if they refer to the same
- // exact type definition, in which case, we can de-dupe. If they don't
- // match, we error out.
+ // exact type definition, in which case, we can de-dupe. If they
+ // don't match, we error out.
if TypeDefinitionsEquivalent(prevType, typ) {
continue
}
- // We want to create an error when we try to define the same type twice.
return "", fmt.Errorf("duplicate typename '%s' detected, can't auto-rename, "+
"please use x-go-name to specify your own name for one of them", typ.TypeName)
}
@@ -696,6 +934,63 @@ func GenerateTypes(t *template.Template, types []TypeDefinition) (string, error)
return GenerateTemplates([]string{"typedef.tmpl"}, t, context)
}
+// resolvedNameForComponent looks up the resolved Go type name for a component
+// identified by its section (e.g., "schemas", "parameters") and name.
+// For content-bearing sections (responses, requestBodies), an optional
+// contentType can be provided to match the exact media type entry.
+// Returns empty string if no resolved name is available.
+func resolvedNameForComponent(section, name string, contentType ...string) string {
+ if len(globalState.resolvedNames) == 0 {
+ return ""
+ }
+
+ // Direct key match for schemas, parameters, headers
+ key := "components/" + section + "/" + name
+ if resolved, ok := globalState.resolvedNames[key]; ok {
+ return resolved
+ }
+
+ // For responses and requestBodies, the path includes content type info.
+ // If a specific content type was provided, do an exact match.
+ if len(contentType) > 0 && contentType[0] != "" {
+ exactKey := key + "/content/" + contentType[0]
+ if resolved, ok := globalState.resolvedNames[exactKey]; ok {
+ return resolved
+ }
+ }
+
+ // Fall back to prefix match for callers that don't specify content type.
+ // Sort matching keys so the result is deterministic across runs.
+ prefix := key + "/"
+ var matches []string
+ for k := range globalState.resolvedNames {
+ if strings.HasPrefix(k, prefix) {
+ matches = append(matches, k)
+ }
+ }
+ if len(matches) > 0 {
+ if len(matches) > 1 {
+ slices.Sort(matches)
+ }
+ return globalState.resolvedNames[matches[0]]
+ }
+
+ return ""
+}
+
+// resolvedNameForRefPath looks up the resolved Go type name for a $ref path
+// like "#/components/responses/Foo", optionally scoped to a specific content type.
+func resolvedNameForRefPath(refPath, contentType string) string {
+ if len(globalState.resolvedNames) == 0 || !strings.HasPrefix(refPath, "#/") {
+ return ""
+ }
+ parts := strings.Split(refPath, "/")
+ if len(parts) != 4 || parts[1] != "components" {
+ return ""
+ }
+ return resolvedNameForComponent(parts[2], parts[3], contentType)
+}
+
func GenerateEnums(t *template.Template, types []TypeDefinition) (string, error) {
enums := []EnumDefinition{}
@@ -719,7 +1014,7 @@ func GenerateEnums(t *template.Template, types []TypeDefinition) (string, error)
Schema: tp.Schema,
TypeName: tp.TypeName,
ValueWrapper: wrapper,
- PrefixTypeName: globalState.options.Compatibility.AlwaysPrefixEnumValues,
+ PrefixTypeName: globalState.options.Compatibility.AlwaysPrefixEnumValues || tp.ForceEnumPrefix,
})
}
}
@@ -769,7 +1064,10 @@ func GenerateEnums(t *template.Template, types []TypeDefinition) (string, error)
// Now see if enums conflict with any non-enum typenames
- return GenerateTemplates([]string{"constants.tmpl"}, t, Constants{EnumDefinitions: enums})
+ return GenerateTemplates([]string{"constants.tmpl"}, t, Constants{
+ EnumDefinitions: enums,
+ SkipEnumValidate: globalState.options.OutputOptions.SkipEnumValidate,
+ })
}
// GenerateImports generates our import statements and package definition.
@@ -798,12 +1096,14 @@ func GenerateImports(t *template.Template, externalImports []string, packageName
ModuleName string
Version string
AdditionalImports []AdditionalImport
+ RouterImports []AdditionalImport
}{
ExternalImports: externalImports,
PackageName: packageName,
ModuleName: modulePath,
Version: moduleVersion,
AdditionalImports: globalState.options.AdditionalImports,
+ RouterImports: globalState.options.Generate.RouterImports(),
}
return GenerateTemplates([]string{"imports.tmpl"}, t, context)
@@ -839,7 +1139,12 @@ func GenerateAdditionalPropertyBoilerplate(t *template.Template, typeDefs []Type
func GenerateUnionBoilerplate(t *template.Template, typeDefs []TypeDefinition) (string, error) {
var filteredTypes []TypeDefinition
+ seen := map[string]bool{}
for _, t := range typeDefs {
+ if seen[t.TypeName] {
+ continue
+ }
+ seen[t.TypeName] = true
if len(t.Schema.UnionElements) != 0 {
filteredTypes = append(filteredTypes, t)
}
@@ -860,7 +1165,12 @@ func GenerateUnionBoilerplate(t *template.Template, typeDefs []TypeDefinition) (
func GenerateUnionAndAdditionalProopertiesBoilerplate(t *template.Template, typeDefs []TypeDefinition) (string, error) {
var filteredTypes []TypeDefinition
+ seen := map[string]bool{}
for _, t := range typeDefs {
+ if seen[t.TypeName] {
+ continue
+ }
+ seen[t.TypeName] = true
if len(t.Schema.UnionElements) != 0 && t.Schema.HasAdditionalProperties {
filteredTypes = append(filteredTypes, t)
}
@@ -923,7 +1233,9 @@ func GetUserTemplateText(inputData string) (template string, err error) {
return "", fmt.Errorf("failed to execute GET request data from %s: %w", inputData, err)
}
if resp != nil {
- defer resp.Body.Close()
+ defer func() {
+ _ = resp.Body.Close()
+ }()
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return "", fmt.Errorf("got non %d status code on GET %s", resp.StatusCode, inputData)
@@ -970,14 +1282,14 @@ func OperationSchemaImports(s *Schema) (map[string]goImport, error) {
if err != nil {
return nil, err
}
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
}
imprts, err := GoSchemaImports(&openapi3.SchemaRef{Value: s.OAPISchema})
if err != nil {
return nil, err
}
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
return res, nil
}
@@ -990,7 +1302,7 @@ func OperationImports(ops []OperationDefinition) (map[string]goImport, error) {
if err != nil {
return nil, err
}
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
}
}
@@ -999,7 +1311,7 @@ func OperationImports(ops []OperationDefinition) (map[string]goImport, error) {
if err != nil {
return nil, err
}
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
}
for _, b := range op.Responses {
@@ -1008,7 +1320,7 @@ func OperationImports(ops []OperationDefinition) (map[string]goImport, error) {
if err != nil {
return nil, err
}
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
}
}
@@ -1043,7 +1355,7 @@ func GetTypeDefinitionsImports(swagger *openapi3.T, excludeSchemas []string) (ma
}
for _, imprts := range []map[string]goImport{schemaImports, reqBodiesImports, responsesImports, parametersImports} {
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
}
return res, nil
}
@@ -1051,34 +1363,36 @@ func GetTypeDefinitionsImports(swagger *openapi3.T, excludeSchemas []string) (ma
func GoSchemaImports(schemas ...*openapi3.SchemaRef) (map[string]goImport, error) {
res := map[string]goImport{}
for _, sref := range schemas {
- if sref == nil || sref.Value == nil || IsGoTypeReference(sref.Ref) {
+ if sref == nil {
return nil, nil
}
+
if gi, err := ParseGoImportExtension(sref); err != nil {
return nil, err
- } else {
- if gi != nil {
- res[gi.String()] = *gi
- }
+ } else if gi != nil {
+ res[gi.String()] = *gi
+ }
+
+ if sref.Value == nil || IsGoTypeReference(sref.Ref) {
+ continue
}
schemaVal := sref.Value
t := schemaVal.Type
- switch t {
- case "", "object":
+ if t.Slice() == nil || t.Is("object") {
for _, v := range schemaVal.Properties {
imprts, err := GoSchemaImports(v)
if err != nil {
return nil, err
}
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
}
- case "array":
+ } else if t.Is("array") {
imprts, err := GoSchemaImports(schemaVal.Items)
if err != nil {
return nil, err
}
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
}
}
return res, nil
@@ -1099,7 +1413,7 @@ func GetSchemaImports(schemas map[string]*openapi3.SchemaRef, excludeSchemas []s
if err != nil {
return nil, err
}
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
}
return res, nil
}
@@ -1117,7 +1431,7 @@ func GetRequestBodiesImports(bodies map[string]*openapi3.RequestBodyRef) (map[st
if err != nil {
return nil, err
}
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
}
}
return res, nil
@@ -1136,7 +1450,7 @@ func GetResponsesImports(responses map[string]*openapi3.ResponseRef) (map[string
if err != nil {
return nil, err
}
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
}
}
return res, nil
@@ -1152,7 +1466,7 @@ func GetParametersImports(params map[string]*openapi3.ParameterRef) (map[string]
if err != nil {
return nil, err
}
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
}
return res, nil
}
diff --git a/pkg/codegen/codegen_test.go b/pkg/codegen/codegen_test.go
index 0cc7c6668d..037c9e1886 100644
--- a/pkg/codegen/codegen_test.go
+++ b/pkg/codegen/codegen_test.go
@@ -8,24 +8,16 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
- "golang.org/x/lint"
- "github.com/deepmap/oapi-codegen/pkg/util"
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/util"
)
const (
- remoteRefFile = `https://raw.githubusercontent.com/deepmap/oapi-codegen/master/examples/petstore-expanded` +
+ remoteRefFile = `https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/master/examples/petstore-expanded` +
`/petstore-expanded.yaml`
- remoteRefImport = `github.com/deepmap/oapi-codegen/examples/petstore-expanded`
+ remoteRefImport = `github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded`
)
-func checkLint(t *testing.T, filename string, code []byte) {
- linter := new(lint.Linter)
- problems, err := linter.Lint(filename, code)
- assert.NoError(t, err)
- assert.Len(t, problems, 0)
-}
-
func TestExampleOpenAPICodeGeneration(t *testing.T) {
// Input vars for code generation:
@@ -85,15 +77,19 @@ type GetTestByNameResponse struct {
assert.Contains(t, code, "Top *int `form:\"$top,omitempty\" json:\"$top,omitempty\"`")
assert.Contains(t, code, "func (c *Client) GetTestByName(ctx context.Context, name string, params *GetTestByNameParams, reqEditors ...RequestEditorFn) (*http.Response, error) {")
assert.Contains(t, code, "func (c *ClientWithResponses) GetTestByNameWithResponse(ctx context.Context, name string, params *GetTestByNameParams, reqEditors ...RequestEditorFn) (*GetTestByNameResponse, error) {")
- assert.Contains(t, code, "DeadSince *time.Time `json:\"dead_since,omitempty\" tag1:\"value1\" tag2:\"value2\"`")
+ assert.Contains(t, code, "FavouriteBirds *[]*string `json:\"favourite_birds,omitempty\"`")
+ assert.Contains(t, code, "DetestedBirds *[]string `json:\"detested_birds,omitempty\"`")
+ assert.Contains(t, code, "SlicedBirds []string `json:\"sliced_birds\"`")
+ assert.Contains(t, code, "ForgettableBirds *map[string]*string `json:\"forgettable_birds,omitempty\"`")
+ assert.Contains(t, code, "MemorableBirds *map[string]string `json:\"memorable_birds,omitempty\"`")
+ assert.Contains(t, code, "VeryMemorableBirds map[string]string `json:\"very_memorable_birds\"`")
+ assert.Contains(t, code, "DeadSince *time.Time `json:\"dead_since,omitempty\" tag1:\"value1\" tag2:\"value2\"`")
+ assert.Contains(t, code, "VeryDeadSince time.Time `json:\"very_dead_since\"`")
assert.Contains(t, code, "type EnumTestNumerics int")
assert.Contains(t, code, "N2 EnumTestNumerics = 2")
assert.Contains(t, code, "type EnumTestEnumNames int")
assert.Contains(t, code, "Two EnumTestEnumNames = 2")
assert.Contains(t, code, "Double EnumTestEnumVarnames = 2")
-
- // Make sure the generated code is valid:
- checkLint(t, "test.gen.go", []byte(code))
}
func TestExtPropGoTypeSkipOptionalPointer(t *testing.T) {
@@ -121,8 +117,8 @@ func TestExtPropGoTypeSkipOptionalPointer(t *testing.T) {
assert.NoError(t, err)
// Check that optional pointer fields are skipped if requested
- assert.Contains(t, code, "NullableFieldSkipFalse *string `json:\"nullableFieldSkipFalse\"`")
- assert.Contains(t, code, "NullableFieldSkipTrue string `json:\"nullableFieldSkipTrue\"`")
+ assert.Contains(t, code, "NullableFieldSkipFalse *string `json:\"nullableFieldSkipFalse,omitempty\"`")
+ assert.Contains(t, code, "NullableFieldSkipTrue string `json:\"nullableFieldSkipTrue,omitempty\"`")
assert.Contains(t, code, "OptionalField *string `json:\"optionalField,omitempty\"`")
assert.Contains(t, code, "OptionalFieldSkipFalse *string `json:\"optionalFieldSkipFalse,omitempty\"`")
assert.Contains(t, code, "OptionalFieldSkipTrue string `json:\"optionalFieldSkipTrue,omitempty\"`")
@@ -175,10 +171,41 @@ func TestGoTypeImport(t *testing.T) {
for _, imp := range imports {
assert.Contains(t, code, imp)
}
+}
- // Make sure the generated code is valid:
- checkLint(t, "test.gen.go", []byte(code))
+func TestGoAllofTypeOverride(t *testing.T) {
+ packageName := "api"
+ opts := Configuration{
+ PackageName: packageName,
+ Generate: GenerateOptions{
+ EchoServer: true,
+ Models: true,
+ EmbeddedSpec: true,
+ },
+ }
+ spec := "test_specs/x-go-type-pet-allof.yaml"
+ swagger, err := util.LoadSwagger(spec)
+ require.NoError(t, err)
+
+ // Run our code generation:
+ code, err := Generate(swagger, opts)
+ assert.NoError(t, err)
+ assert.NotEmpty(t, code)
+ // Check that we have valid (formattable) code:
+ _, err = format.Source([]byte(code))
+ assert.NoError(t, err)
+
+ for _, expected := range []string{
+ "type Cat = cat.Cat",
+ "type Dog = dog.Dog",
+ "type Pet = pet.Pet",
+ "github.com/somepetproject/pkg/cat",
+ "github.com/somepetproject/pkg/dog",
+ "github.com/somepetproject/pkg/pet",
+ } {
+ assert.Contains(t, code, expected)
+ }
}
func TestRemoteExternalReference(t *testing.T) {
@@ -213,7 +240,7 @@ func TestRemoteExternalReference(t *testing.T) {
assert.Contains(t, code, "package api")
// Check import
- assert.Contains(t, code, `externalRef0 "github.com/deepmap/oapi-codegen/examples/petstore-expanded"`)
+ assert.Contains(t, code, `externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded"`)
// Check generated oneOf structure:
assert.Contains(t, code, `
@@ -240,10 +267,66 @@ func (t *ExampleSchema_Item) FromExternalRef0NewPet(v externalRef0.NewPet) error
// FromExternalRef0NewPet overwrites any union data inside the ExampleSchema_Item as the provided externalRef0.NewPet
func (t *ExampleSchema_Item) FromExternalRef0NewPet(v externalRef0.NewPet) error {
`)
+}
+
+func TestDuplicatePathParameter(t *testing.T) {
+ // Regression test for https://github.com/oapi-codegen/oapi-codegen/issues/1574
+ // Some real-world specs (e.g. Keycloak) have paths where the same parameter
+ // appears more than once: /clients/{client-uuid}/.../clients/{client-uuid}
+ spec := `
+openapi: "3.0.0"
+info:
+ version: 1.0.0
+ title: Duplicate path param test
+paths:
+ /admin/realms/{realm}/clients/{client-uuid}/roles/{role-name}/composites/clients/{client-uuid}:
+ get:
+ operationId: getCompositeRoles
+ parameters:
+ - name: realm
+ in: path
+ required: true
+ schema:
+ type: string
+ - name: client-uuid
+ in: path
+ required: true
+ schema:
+ type: string
+ - name: role-name
+ in: path
+ required: true
+ schema:
+ type: string
+ responses:
+ '200':
+ description: Success
+`
+ loader := openapi3.NewLoader()
+ swagger, err := loader.LoadFromData([]byte(spec))
+ require.NoError(t, err)
+
+ opts := Configuration{
+ PackageName: "api",
+ Generate: GenerateOptions{
+ EchoServer: true,
+ Client: true,
+ Models: true,
+ },
+ }
+
+ code, err := Generate(swagger, opts)
+ require.NoError(t, err)
+ assert.NotEmpty(t, code)
- // Make sure the generated code is valid:
- checkLint(t, "test.gen.go", []byte(code))
+ // Verify the generated code is valid Go.
+ _, err = format.Source([]byte(code))
+ require.NoError(t, err)
+ // The path params should appear exactly once in the function signature.
+ assert.Contains(t, code, "realm string")
+ assert.Contains(t, code, "clientUuid string")
+ assert.Contains(t, code, "roleName string")
}
//go:embed test_spec.yaml
diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go
index 9533f166e2..dbcb0a6874 100644
--- a/pkg/codegen/configuration.go
+++ b/pkg/codegen/configuration.go
@@ -2,9 +2,20 @@ package codegen
import (
"errors"
+ "fmt"
"reflect"
+ "regexp"
)
+// defaultStreamingContentTypes are the regex patterns matched against
+// response Content-Type to decide when the strict-server should emit a
+// flush-per-chunk streaming path. User-supplied patterns are merged on top.
+var defaultStreamingContentTypes = []string{
+ "text/event-stream",
+ "application/jsonl",
+ "application/x-ndjson",
+}
+
type AdditionalImport struct {
Alias string `yaml:"alias,omitempty"`
Package string `yaml:"package"`
@@ -12,29 +23,186 @@ type AdditionalImport struct {
// Configuration defines code generation customizations
type Configuration struct {
- PackageName string `yaml:"package"` // PackageName to generate
- Generate GenerateOptions `yaml:"generate,omitempty"`
- Compatibility CompatibilityOptions `yaml:"compatibility,omitempty"`
- OutputOptions OutputOptions `yaml:"output-options,omitempty"`
- ImportMapping map[string]string `yaml:"import-mapping,omitempty"` // ImportMapping specifies the golang package path for each external reference
- AdditionalImports []AdditionalImport `yaml:"additional-imports,omitempty"`
+ // PackageName to generate the code under
+ PackageName string `yaml:"package"`
+ // Generate specifies which supported output formats to generate
+ Generate GenerateOptions `yaml:"generate,omitempty"`
+ // CompatibilityOptions specifies backward compatibility settings for the code generator
+ Compatibility CompatibilityOptions `yaml:"compatibility,omitempty"`
+ // OutputOptions are used to modify the output code in some way.
+ OutputOptions OutputOptions `yaml:"output-options,omitempty"`
+ // ImportMapping specifies the golang package path for each external reference
+ ImportMapping map[string]string `yaml:"import-mapping,omitempty"`
+ // AdditionalImports defines any additional Go imports to add to the generated code
+ AdditionalImports []AdditionalImport `yaml:"additional-imports,omitempty"`
// NoVCSVersionOverride allows overriding the version of the application for cases where no Version Control System (VCS) is available when building, for instance when using a Nix derivation.
// See documentation for how to use it in examples/no-vcs-version-override/README.md
NoVCSVersionOverride *string `yaml:"-"`
}
+// Validate checks whether Configuration represent a valid configuration
+func (o Configuration) Validate() error {
+ if o.PackageName == "" {
+ return errors.New("package name must be specified")
+ }
+
+ // Only one server type should be specified at a time.
+ nServers := 0
+ if o.Generate.IrisServer {
+ nServers++
+ }
+ if o.Generate.ChiServer {
+ nServers++
+ }
+ if o.Generate.FiberServer {
+ nServers++
+ }
+ if o.Generate.EchoServer {
+ nServers++
+ }
+ if o.Generate.Echo5Server {
+ nServers++
+ }
+ if o.Generate.GorillaServer {
+ nServers++
+ }
+ if o.Generate.StdHTTPServer {
+ nServers++
+ }
+ if o.Generate.GinServer {
+ nServers++
+ }
+ if nServers > 1 {
+ return errors.New("only one server type is supported at a time")
+ }
+
+ var errs []error
+ if problems := o.Generate.Validate(); problems != nil {
+ for k, v := range problems {
+ errs = append(errs, fmt.Errorf("`generate` configuration for %v was incorrect: %v", k, v))
+ }
+ }
+
+ if problems := o.Compatibility.Validate(); problems != nil {
+ for k, v := range problems {
+ errs = append(errs, fmt.Errorf("`compatibility-options` configuration for %v was incorrect: %v", k, v))
+ }
+ }
+
+ if problems := o.OutputOptions.Validate(); problems != nil {
+ for k, v := range problems {
+ errs = append(errs, fmt.Errorf("`output-options` configuration for %v was incorrect: %v", k, v))
+ }
+ }
+
+ err := errors.Join(errs...)
+ if err != nil {
+ return fmt.Errorf("failed to validate configuration: %w", err)
+ }
+
+ return nil
+}
+
+// UpdateDefaults sets reasonable default values for unset fields in Configuration
+func (o Configuration) UpdateDefaults() Configuration {
+ if reflect.ValueOf(o.Generate).IsZero() {
+ o.Generate = GenerateOptions{
+ EchoServer: true,
+ Models: true,
+ EmbeddedSpec: true,
+ }
+ }
+ return o
+}
+
// GenerateOptions specifies which supported output formats to generate.
type GenerateOptions struct {
- IrisServer bool `yaml:"iris-server,omitempty"` // IrisServer specifies whether to generate iris server boilerplate
- ChiServer bool `yaml:"chi-server,omitempty"` // ChiServer specifies whether to generate chi server boilerplate
- FiberServer bool `yaml:"fiber-server,omitempty"` // FiberServer specifies whether to generate fiber server boilerplate
- EchoServer bool `yaml:"echo-server,omitempty"` // EchoServer specifies whether to generate echo server boilerplate
- GinServer bool `yaml:"gin-server,omitempty"` // GinServer specifies whether to generate gin server boilerplate
- GorillaServer bool `yaml:"gorilla-server,omitempty"` // GorillaServer specifies whether to generate Gorilla server boilerplate
- Strict bool `yaml:"strict-server,omitempty"` // Strict specifies whether to generate strict server wrapper
- Client bool `yaml:"client,omitempty"` // Client specifies whether to generate client boilerplate
- Models bool `yaml:"models,omitempty"` // Models specifies whether to generate type definitions
- EmbeddedSpec bool `yaml:"embedded-spec,omitempty"` // Whether to embed the swagger spec in the generated code
+ // IrisServer specifies whether to generate iris server boilerplate
+ IrisServer bool `yaml:"iris-server,omitempty"`
+ // ChiServer specifies whether to generate chi server boilerplate
+ ChiServer bool `yaml:"chi-server,omitempty"`
+ // FiberServer specifies whether to generate fiber server boilerplate
+ FiberServer bool `yaml:"fiber-server,omitempty"`
+ // EchoServer specifies whether to generate echo server boilerplate
+ EchoServer bool `yaml:"echo-server,omitempty"`
+ // Echo5Server specifies whether to generate echo v5 server boilerplate
+ Echo5Server bool `yaml:"echo5-server,omitempty"`
+ // GinServer specifies whether to generate gin server boilerplate
+ GinServer bool `yaml:"gin-server,omitempty"`
+ // GorillaServer specifies whether to generate Gorilla server boilerplate
+ GorillaServer bool `yaml:"gorilla-server,omitempty"`
+ // StdHTTPServer specifies whether to generate stdlib http server boilerplate
+ StdHTTPServer bool `yaml:"std-http-server,omitempty"`
+ // Strict specifies whether to generate strict server wrapper
+ Strict bool `yaml:"strict-server,omitempty"`
+ // Client specifies whether to generate client boilerplate
+ Client bool `yaml:"client,omitempty"`
+ // Models specifies whether to generate type definitions
+ Models bool `yaml:"models,omitempty"`
+ // EmbeddedSpec indicates whether to embed the swagger spec in the generated code
+ EmbeddedSpec bool `yaml:"embedded-spec,omitempty"`
+ // ServerURLs generates types for the `Server` definitions' URLs, instead of needing to provide your own values
+ ServerURLs bool `yaml:"server-urls,omitempty"`
+}
+
+// RouterImports returns the framework-specific and strict middleware imports
+// needed based on which server type is selected.
+func (g GenerateOptions) RouterImports() []AdditionalImport {
+ var imports []AdditionalImport
+
+ switch {
+ case g.EchoServer:
+ imports = append(imports, AdditionalImport{Package: "github.com/labstack/echo/v4"})
+ case g.Echo5Server:
+ imports = append(imports, AdditionalImport{Package: "github.com/labstack/echo/v5"})
+ case g.ChiServer:
+ imports = append(imports, AdditionalImport{Package: "github.com/go-chi/chi/v5"})
+ case g.GinServer:
+ imports = append(imports, AdditionalImport{Package: "github.com/gin-gonic/gin"})
+ case g.GorillaServer:
+ imports = append(imports, AdditionalImport{Package: "github.com/gorilla/mux"})
+ case g.FiberServer:
+ imports = append(imports, AdditionalImport{Package: "github.com/gofiber/fiber/v2"})
+ case g.IrisServer:
+ imports = append(imports, AdditionalImport{Package: "github.com/kataras/iris/v12"})
+ imports = append(imports, AdditionalImport{Package: "github.com/kataras/iris/v12/core/router"})
+ case g.StdHTTPServer:
+ }
+
+ return imports
+}
+
+func (oo GenerateOptions) Validate() map[string]string {
+ return nil
+}
+
+func (oo GenerateOptions) Warnings() map[string]string {
+ warnings := make(map[string]string)
+
+ if oo.StdHTTPServer {
+ if warning := oo.warningForStdHTTP(); warning != "" {
+ warnings["std-http-server"] = warning
+ }
+ }
+
+ return warnings
+}
+
+func (oo GenerateOptions) warningForStdHTTP() string {
+ pathToGoMod, mod, err := findAndParseGoModuleForDepth(".", maximumDepthToSearchForGoMod)
+ if err != nil {
+ return fmt.Sprintf("Encountered an error while trying to find a `go.mod` or a `tools.mod` in this directory, or %d levels above it: %v", maximumDepthToSearchForGoMod, err)
+ }
+
+ if mod == nil {
+ return fmt.Sprintf("Failed to find a `go.mod` or a `tools.mod` in this directory, or %d levels above it, so unable to validate that you're using Go 1.22+. If you start seeing API interactions resulting in a `404 page not found`, the Go directive (implying source compatibility for this module) needs to be bumped. See also: https://www.jvt.me/posts/2024/03/04/go-net-http-why-404/", maximumDepthToSearchForGoMod)
+ }
+
+ if !hasMinimalMinorGoDirective(minimumGoVersionForGenerateStdHTTPServer, mod) {
+ return fmt.Sprintf("Found a `go.mod` or a `tools.mod` at path %v, but it only had a version of %v, whereas the minimum required is 1.%d. It's very likely API interactions will result in a `404 page not found`. The Go directive (implying source compatibility for this module) needs to be bumped. See also: https://www.jvt.me/posts/2024/03/04/go-net-http-why-404/", pathToGoMod, mod.Go.Version, minimumGoVersionForGenerateStdHTTPServer)
+ }
+
+ return ""
}
// CompatibilityOptions specifies backward compatibility settings for the
@@ -45,26 +213,39 @@ type CompatibilityOptions struct {
// `allOf` merges at the schema definition level, not at the resulting model
// level. So, new behavior merges OpenAPI specs but generates different code
// than we have in the past. Set OldMergeSchemas to true for the old behavior.
- // Please see https://github.com/deepmap/oapi-codegen/issues/531
+ // Please see https://github.com/oapi-codegen/oapi-codegen/issues/531
OldMergeSchemas bool `yaml:"old-merge-schemas,omitempty"`
+ // In the past, when a schema combined `allOf` with sibling fields at the
+ // same level (`properties`, `required`, `additionalProperties`,
+ // `description`), those siblings were silently discarded and the schema
+ // was emitted as a Go type alias to its sole `allOf` target. New behavior
+ // merges the parent's siblings with the `allOf` members so the generated
+ // type carries every field declared in the spec. This is a more accurate
+ // translation of OpenAPI semantics, but it changes the shape of generated
+ // types: a schema that previously produced `type X = Y` may now produce
+ // a distinct struct embedding Y with extra fields, which is not
+ // interchangeable with Y in downstream Go code. Set OldAllOfSiblingMerging
+ // to true to restore the prior behavior.
+ // Please see https://github.com/oapi-codegen/oapi-codegen/issues/697
+ OldAllOfSiblingMerging bool `yaml:"old-allof-sibling-merging,omitempty"`
// Enum values can generate conflicting typenames, so we've updated the
// code for enum generation to avoid these conflicts, but it will result
// in some enum types being renamed in existing code. Set OldEnumConflicts to true
// to revert to old behavior. Please see:
- // Please see https://github.com/deepmap/oapi-codegen/issues/549
+ // Please see https://github.com/oapi-codegen/oapi-codegen/issues/549
OldEnumConflicts bool `yaml:"old-enum-conflicts,omitempty"`
// It was a mistake to generate a go type definition for every $ref in
// the OpenAPI schema. New behavior uses type aliases where possible, but
// this can generate code which breaks existing builds. Set OldAliasing to true
// for old behavior.
- // Please see https://github.com/deepmap/oapi-codegen/issues/549
+ // Please see https://github.com/oapi-codegen/oapi-codegen/issues/549
OldAliasing bool `yaml:"old-aliasing,omitempty"`
// When an object contains no members, and only an additionalProperties specification,
- // it is flattened to a map. Set
+ // it is flattened to a map
DisableFlattenAdditionalProperties bool `yaml:"disable-flatten-additional-properties,omitempty"`
// When an object property is both required and readOnly the go model is generated
// as a pointer. Set DisableRequiredReadOnlyAsPointer to true to mark them as non pointer.
- // Please see https://github.com/deepmap/oapi-codegen/issues/604
+ // Please see https://github.com/oapi-codegen/oapi-codegen/issues/604
DisableRequiredReadOnlyAsPointer bool `yaml:"disable-required-readonly-as-pointer,omitempty"`
// When set to true, always prefix enum values with their type name instead of only
// when typenames would be conflicting.
@@ -72,71 +253,188 @@ type CompatibilityOptions struct {
// Our generated code for Chi has historically inverted the order in which Chi middleware is
// applied such that the last invoked middleware ends up executing first in the Chi chain
// This resolves the behavior such that middlewares are chained in the order they are invoked.
- // Please see https://github.com/deepmap/oapi-codegen/issues/786
+ // Please see https://github.com/oapi-codegen/oapi-codegen/issues/786
ApplyChiMiddlewareFirstToLast bool `yaml:"apply-chi-middleware-first-to-last,omitempty"`
// Our generated code for gorilla/mux has historically inverted the order in which gorilla/mux middleware is
// applied such that the last invoked middleware ends up executing first in the middlewares chain
// This resolves the behavior such that middlewares are chained in the order they are invoked.
- // Please see https://github.com/deepmap/oapi-codegen/issues/841
+ // Please see https://github.com/oapi-codegen/oapi-codegen/issues/841
ApplyGorillaMiddlewareFirstToLast bool `yaml:"apply-gorilla-middleware-first-to-last,omitempty"`
// CircularReferenceLimit allows controlling the limit for circular reference checking.
// In some OpenAPI specifications, we have a higher number of circular
// references than is allowed out-of-the-box, but can be tuned to allow
// traversing them.
+ // Deprecated: In kin-openapi v0.126.0 (https://github.com/getkin/kin-openapi/tree/v0.126.0?tab=readme-ov-file#v01260) the Circular Reference Counter functionality was removed, instead resolving all references with backtracking, to avoid needing to provide a limit to reference counts.
CircularReferenceLimit int `yaml:"circular-reference-limit"`
+ // AllowUnexportedStructFieldNames makes it possible to output structs that have fields that are unexported.
+ //
+ // This is expected to be used in conjunction with `x-go-name` and `x-oapi-codegen-only-honour-go-name` to override the resulting output field name, and `x-oapi-codegen-extra-tags` to not produce JSON tags for `encoding/json`, such as:
+ //
+ // ```yaml
+ // id:
+ // type: string
+ // x-go-name: accountIdentifier
+ // x-oapi-codegen-extra-tags:
+ // json: "-"
+ // x-oapi-codegen-only-honour-go-name: true
+ // ```
+ //
+ // NOTE that this can be confusing to users of your OpenAPI specification, who may see a field present and therefore be expecting to see/use it in the request/response, without understanding the nuance of how `oapi-codegen` generates the code.
+ AllowUnexportedStructFieldNames bool `yaml:"allow-unexported-struct-field-names"`
+
+ // PreserveOriginalOperationIdCasingInEmbeddedSpec ensures that the `operationId` from the source spec is kept intact in case when embedding it into the Embedded Spec output.
+ // When `oapi-codegen` parses the original OpenAPI specification, it will apply the configured `output-options.name-normalizer` to each operation's `operationId` before that is used to generate code from.
+ // However, this is also applied to the copy of the `operationId`s in the `embedded-spec` generation, which means that the embedded OpenAPI specification is then out-of-sync with the input specificiation.
+ // To ensure that the `operationId` in the embedded spec is preserved as-is from the input specification, set this.
+ // NOTE that this will not impact generated code.
+ // NOTE that if you're using `include-operation-ids` or `exclude-operation-ids` you may want to ensure that the `operationId`s used are correct.
+ PreserveOriginalOperationIdCasingInEmbeddedSpec bool `yaml:"preserve-original-operation-id-casing-in-embedded-spec"`
+
+ // HeadersImplicitlyRequired treats all response headers as required, ignoring
+ // the `required` property from the header definition. Prior to v2.6.0,
+ // oapi-codegen generated all response headers as direct values (implicitly
+ // required). The OpenAPI specification defaults headers to optional
+ // (required: false), so the corrected behavior generates optional headers as
+ // pointers. Set this to true to restore the old behavior where all headers
+ // are treated as required.
+ // Please see https://github.com/oapi-codegen/oapi-codegen/issues/2267
+ HeadersImplicitlyRequired bool `yaml:"headers-implicitly-required,omitempty"`
+}
+
+func (co CompatibilityOptions) Validate() map[string]string {
+ return nil
}
// OutputOptions are used to modify the output code in some way.
type OutputOptions struct {
- SkipFmt bool `yaml:"skip-fmt,omitempty"` // Whether to skip go imports on the generated code
- SkipPrune bool `yaml:"skip-prune,omitempty"` // Whether to skip pruning unused components on the generated code
- IncludeTags []string `yaml:"include-tags,omitempty"` // Only include operations that have one of these tags. Ignored when empty.
- ExcludeTags []string `yaml:"exclude-tags,omitempty"` // Exclude operations that have one of these tags. Ignored when empty.
- UserTemplates map[string]string `yaml:"user-templates,omitempty"` // Override built-in templates from user-provided files
+ // Whether to skip go imports on the generated code
+ SkipFmt bool `yaml:"skip-fmt,omitempty"`
+ // Whether to skip pruning unused components on the generated code
+ SkipPrune bool `yaml:"skip-prune,omitempty"`
+ // SkipEnumValidate disables the generation of the `Valid()` method on
+ // enum types. By default each generated enum type includes a `Valid()
+ // bool` method which returns true when the value matches one of the
+ // defined constants; set this to true to suppress that method when it
+ // conflicts with user-defined methods of the same name.
+ SkipEnumValidate bool `yaml:"skip-enum-validate,omitempty"`
+ // Only include operations that have one of these tags. Ignored when empty.
+ IncludeTags []string `yaml:"include-tags,omitempty"`
+ // Exclude operations that have one of these tags. Ignored when empty.
+ ExcludeTags []string `yaml:"exclude-tags,omitempty"`
+ // Only include operations that have one of these operation-ids. Ignored when empty.
+ IncludeOperationIDs []string `yaml:"include-operation-ids,omitempty"`
+ // Exclude operations that have one of these operation-ids. Ignored when empty.
+ ExcludeOperationIDs []string `yaml:"exclude-operation-ids,omitempty"`
+ // Override built-in templates from user-provided files
+ UserTemplates map[string]string `yaml:"user-templates,omitempty"`
+
+ // Exclude from generation schemas with given names. Ignored when empty.
+ ExcludeSchemas []string `yaml:"exclude-schemas,omitempty"`
+ // The suffix used for responses types
+ ResponseTypeSuffix string `yaml:"response-type-suffix,omitempty"`
+ // Override the default generated client type with the value
+ ClientTypeName string `yaml:"client-type-name,omitempty"`
+ // AdditionalInitialisms is a list of additional initialisms to use when generating names.
+ // NOTE that this has no effect unless the `name-normalizer` is set to `ToCamelCaseWithInitialisms`
+ AdditionalInitialisms []string `yaml:"additional-initialisms,omitempty"`
+ // StreamingContentTypes are regex patterns matched against response
+ // Content-Type to decide when to generate a flush-per-chunk streaming
+ // response path. User-provided patterns are merged with the defaults
+ // (text/event-stream, application/jsonl, application/x-ndjson); invalid
+ // regexes fail Validate().
+ StreamingContentTypes []string `yaml:"streaming-content-types,omitempty"`
+ // Whether to generate nullable type for nullable fields
+ NullableType bool `yaml:"nullable-type,omitempty"`
- ExcludeSchemas []string `yaml:"exclude-schemas,omitempty"` // Exclude from generation schemas with given names. Ignored when empty.
- ResponseTypeSuffix string `yaml:"response-type-suffix,omitempty"` // The suffix used for responses types
- ClientTypeName string `yaml:"client-type-name,omitempty"` // Override the default generated client type with the value
- InitialismOverrides bool `yaml:"initialism-overrides,omitempty"` // Whether to use the initialism overrides
+ // DisableTypeAliasesForType allows defining which OpenAPI `type`s will explicitly not use type aliases
+ // Currently supports:
+ // "array"
+ DisableTypeAliasesForType []string `yaml:"disable-type-aliases-for-type"`
+
+ // SkipResponseBodyGetters decides whether to generate getter methods for response bodies.
+ SkipResponseBodyGetters bool `yaml:"skip-response-body-getters,omitempty"`
+
+ // NameNormalizer is the method used to normalize Go names and types, for instance converting the text `MyApi` to `MyAPI`. Corresponds with the constants defined for `codegen.NameNormalizerFunction`
+ NameNormalizer string `yaml:"name-normalizer,omitempty"`
+
+ // Overlay defines configuration for the OpenAPI Overlay (https://github.com/OAI/Overlay-Specification) to manipulate the OpenAPI specification before generation. This allows modifying the specification without needing to apply changes directly to it, making it easier to keep it up-to-date.
+ Overlay OutputOptionsOverlay `yaml:"overlay"`
+
+ // EnableYamlTags adds YAML tags to generated structs, in addition to default JSON ones
+ EnableYamlTags bool `yaml:"yaml-tags,omitempty"`
+
+ // ClientResponseBytesFunction decides whether to enable the generation of a `Bytes()` method on response objects for `ClientWithResponses`
+ ClientResponseBytesFunction bool `yaml:"client-response-bytes-function,omitempty"`
+
+ // SkipClientResponseContentType disables the generation of a `ContentType()` method on response objects for `ClientWithResponses`, which is otherwise generated by default.
+ SkipClientResponseContentType bool `yaml:"skip-client-response-content-type,omitempty"`
+
+ // PreferSkipOptionalPointer allows defining at a global level whether to omit the pointer for a type to indicate that the field/type is optional.
+ // This is the same as adding `x-go-type-skip-optional-pointer` to each field (manually, or using an OpenAPI Overlay)
+ PreferSkipOptionalPointer bool `yaml:"prefer-skip-optional-pointer,omitempty"`
+
+ // PreferSkipOptionalPointerWithOmitzero allows generating the `omitzero` JSON tag types that would have had an optional pointer.
+ // This is the same as adding `x-omitzero` to each field (manually, or using an OpenAPI Overlay).
+ // A field can set `x-omitzero: false` to disable the `omitzero` JSON tag.
+ // NOTE that this must be used alongside `prefer-skip-optional-pointer`, otherwise makes no difference.
+ PreferSkipOptionalPointerWithOmitzero bool `yaml:"prefer-skip-optional-pointer-with-omitzero,omitempty"`
+
+ // PreferSkipOptionalPointerOnContainerTypes allows disabling the generation of an "optional pointer" for an optional field that is a container type (such as a slice or a map), which ends up requiring an additional, unnecessary, `... != nil` check
+ PreferSkipOptionalPointerOnContainerTypes bool `yaml:"prefer-skip-optional-pointer-on-container-types,omitempty"`
+
+ // ResolveTypeNameCollisions, when set to true, automatically renames
+ // types that collide across different OpenAPI component sections
+ // (schemas, parameters, requestBodies, responses, headers) by appending
+ // a suffix based on the component section (e.g., "Parameter", "Response",
+ // "RequestBody"). It also detects collisions between component types and
+ // client response wrapper types (e.g., issue #1474). Without this, the
+ // codegen will error on duplicate type names, requiring manual resolution
+ // via x-go-name.
+ ResolveTypeNameCollisions bool `yaml:"resolve-type-name-collisions,omitempty"`
+
+ // TypeMapping allows customizing OpenAPI type/format to Go type mappings.
+ // User-specified mappings are merged on top of the defaults.
+ TypeMapping *TypeMapping `yaml:"type-mapping,omitempty"`
}
-// UpdateDefaults sets reasonable default values for unset fields in Configuration
-func (o Configuration) UpdateDefaults() Configuration {
- if reflect.ValueOf(o.Generate).IsZero() {
- o.Generate = GenerateOptions{
- EchoServer: true,
- Models: true,
- EmbeddedSpec: true,
+func (oo OutputOptions) Validate() map[string]string {
+ if NameNormalizerFunction(oo.NameNormalizer) != NameNormalizerFunctionToCamelCaseWithInitialisms && len(oo.AdditionalInitialisms) > 0 {
+ return map[string]string{
+ "additional-initialisms": "You have specified `additional-initialisms`, but the `name-normalizer` is not set to `ToCamelCaseWithInitialisms`. Please specify `name-normalizer: ToCamelCaseWithInitialisms` or remove the `additional-initialisms` configuration",
}
}
- return o
-}
-// Validate checks whether Configuration represent a valid configuration
-func (o Configuration) Validate() error {
- if o.PackageName == "" {
- return errors.New("package name must be specified")
+ if _, err := compileStreamingContentTypes(oo.StreamingContentTypes); err != nil {
+ return map[string]string{
+ "streaming-content-types": err.Error(),
+ }
}
- // Only one server type should be specified at a time.
- nServers := 0
- if o.Generate.IrisServer {
- nServers++
- }
- if o.Generate.ChiServer {
- nServers++
- }
- if o.Generate.FiberServer {
- nServers++
- }
- if o.Generate.EchoServer {
- nServers++
- }
- if o.Generate.GinServer {
- nServers++
- }
- if nServers > 1 {
- return errors.New("only one server type is supported at a time")
- }
return nil
}
+
+// compileStreamingContentTypes returns the merged default + user-provided
+// patterns compiled into regexes. The first compile error is returned
+// including the offending pattern.
+func compileStreamingContentTypes(user []string) ([]*regexp.Regexp, error) {
+ all := make([]string, 0, len(defaultStreamingContentTypes)+len(user))
+ all = append(all, defaultStreamingContentTypes...)
+ all = append(all, user...)
+ out := make([]*regexp.Regexp, 0, len(all))
+ for _, p := range all {
+ re, err := regexp.Compile(p)
+ if err != nil {
+ return nil, fmt.Errorf("invalid streaming-content-type pattern %q: %w", p, err)
+ }
+ out = append(out, re)
+ }
+ return out, nil
+}
+
+type OutputOptionsOverlay struct {
+ Path string `yaml:"path"`
+
+ // Strict defines whether the Overlay should be applied in a strict way, highlighting any actions that will not take any effect. This can, however, lead to more work when testing new actions in an Overlay, so can be turned off with this setting.
+ // Defaults to true.
+ Strict *bool `yaml:"strict,omitempty"`
+}
diff --git a/pkg/codegen/extension.go b/pkg/codegen/extension.go
index 29c9727a48..dbf6611f4d 100644
--- a/pkg/codegen/extension.go
+++ b/pkg/codegen/extension.go
@@ -5,7 +5,10 @@ import (
)
const (
- // extPropGoType overrides the generated type definition.
+ // extPropGoType overrides the generated type definition. When
+ // resolve-type-name-collisions is enabled, the collision resolver
+ // controls the final Go type name; this extension controls what
+ // that name aliases or refers to.
extPropGoType = "x-go-type"
// extPropGoTypeSkipOptionalPointer specifies that optional fields should
// be the type itself instead of a pointer to the type.
@@ -14,17 +17,25 @@ const (
extPropGoImport = "x-go-type-import"
// extGoName is used to override a field name
extGoName = "x-go-name"
- // extGoTypeName is used to override a generated typename for something.
+ // extGoTypeName overrides a generated typename. When
+ // resolve-type-name-collisions is enabled, the collision resolver
+ // controls the top-level Go type name; this extension controls
+ // the name of the underlying type definition that gets aliased.
extGoTypeName = "x-go-type-name"
extPropGoJsonIgnore = "x-go-json-ignore"
extPropOmitEmpty = "x-omitempty"
+ extPropOmitZero = "x-omitzero"
extPropExtraTags = "x-oapi-codegen-extra-tags"
extEnumVarNames = "x-enum-varnames"
extEnumNames = "x-enumNames"
extDeprecationReason = "x-deprecated-reason"
+ extOrder = "x-order"
+ // extOapiCodegenOnlyHonourGoName is to be used to explicitly enforce the generation of a field as the `x-go-name` extension has describe it.
+ // This is intended to be used alongside the `allow-unexported-struct-field-names` Compatibility option
+ extOapiCodegenOnlyHonourGoName = "x-oapi-codegen-only-honour-go-name"
)
-func extString(extPropValue interface{}) (string, error) {
+func extString(extPropValue any) (string, error) {
str, ok := extPropValue.(string)
if !ok {
return "", fmt.Errorf("failed to convert type: %T", extPropValue)
@@ -32,11 +43,11 @@ func extString(extPropValue interface{}) (string, error) {
return str, nil
}
-func extTypeName(extPropValue interface{}) (string, error) {
+func extTypeName(extPropValue any) (string, error) {
return extString(extPropValue)
}
-func extParsePropGoTypeSkipOptionalPointer(extPropValue interface{}) (bool, error) {
+func extParsePropGoTypeSkipOptionalPointer(extPropValue any) (bool, error) {
goTypeSkipOptionalPointer, ok := extPropValue.(bool)
if !ok {
return false, fmt.Errorf("failed to convert type: %T", extPropValue)
@@ -44,11 +55,11 @@ func extParsePropGoTypeSkipOptionalPointer(extPropValue interface{}) (bool, erro
return goTypeSkipOptionalPointer, nil
}
-func extParseGoFieldName(extPropValue interface{}) (string, error) {
+func extParseGoFieldName(extPropValue any) (string, error) {
return extString(extPropValue)
}
-func extParseOmitEmpty(extPropValue interface{}) (bool, error) {
+func extParseOmitEmpty(extPropValue any) (bool, error) {
omitEmpty, ok := extPropValue.(bool)
if !ok {
return false, fmt.Errorf("failed to convert type: %T", extPropValue)
@@ -56,8 +67,16 @@ func extParseOmitEmpty(extPropValue interface{}) (bool, error) {
return omitEmpty, nil
}
-func extExtraTags(extPropValue interface{}) (map[string]string, error) {
- tagsI, ok := extPropValue.(map[string]interface{})
+func extParseOmitZero(extPropValue any) (bool, error) {
+ omitZero, ok := extPropValue.(bool)
+ if !ok {
+ return false, fmt.Errorf("failed to convert type: %T", extPropValue)
+ }
+ return omitZero, nil
+}
+
+func extExtraTags(extPropValue any) (map[string]string, error) {
+ tagsI, ok := extPropValue.(map[string]any)
if !ok {
return nil, fmt.Errorf("failed to convert type: %T", extPropValue)
}
@@ -72,7 +91,7 @@ func extExtraTags(extPropValue interface{}) (map[string]string, error) {
return tags, nil
}
-func extParseGoJsonIgnore(extPropValue interface{}) (bool, error) {
+func extParseGoJsonIgnore(extPropValue any) (bool, error) {
goJsonIgnore, ok := extPropValue.(bool)
if !ok {
return false, fmt.Errorf("failed to convert type: %T", extPropValue)
@@ -80,8 +99,8 @@ func extParseGoJsonIgnore(extPropValue interface{}) (bool, error) {
return goJsonIgnore, nil
}
-func extParseEnumVarNames(extPropValue interface{}) ([]string, error) {
- namesI, ok := extPropValue.([]interface{})
+func extParseEnumVarNames(extPropValue any) ([]string, error) {
+ namesI, ok := extPropValue.([]any)
if !ok {
return nil, fmt.Errorf("failed to convert type: %T", extPropValue)
}
@@ -96,6 +115,14 @@ func extParseEnumVarNames(extPropValue interface{}) ([]string, error) {
return names, nil
}
-func extParseDeprecationReason(extPropValue interface{}) (string, error) {
+func extParseDeprecationReason(extPropValue any) (string, error) {
return extString(extPropValue)
}
+
+func extParseOapiCodegenOnlyHonourGoName(extPropValue any) (bool, error) {
+ onlyHonourGoName, ok := extPropValue.(bool)
+ if !ok {
+ return false, fmt.Errorf("failed to convert type: %T", extPropValue)
+ }
+ return onlyHonourGoName, nil
+}
diff --git a/pkg/codegen/extension_test.go b/pkg/codegen/extension_test.go
index 7a5f363bd7..0223ee9404 100644
--- a/pkg/codegen/extension_test.go
+++ b/pkg/codegen/extension_test.go
@@ -39,7 +39,7 @@ func Test_extTypeName(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// kin-openapi no longer returns these as RawMessage
- var extPropValue interface{}
+ var extPropValue any
if tt.args.extPropValue != nil {
err := json.Unmarshal(tt.args.extPropValue, &extPropValue)
assert.NoError(t, err)
@@ -93,7 +93,7 @@ func Test_extParsePropGoTypeSkipOptionalPointer(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// kin-openapi no longer returns these as RawMessage
- var extPropValue interface{}
+ var extPropValue any
if tt.args.extPropValue != nil {
err := json.Unmarshal(tt.args.extPropValue, &extPropValue)
assert.NoError(t, err)
diff --git a/pkg/codegen/externalref.go b/pkg/codegen/externalref.go
new file mode 100644
index 0000000000..829885a5b3
--- /dev/null
+++ b/pkg/codegen/externalref.go
@@ -0,0 +1,107 @@
+package codegen
+
+import (
+ "fmt"
+ "strings"
+)
+
+// ensureExternalRefsInRequestBodyDefinitions ensures that when an externalRef (`$ref` that points to a file that isn't the current spec) is encountered, we make sure we update our underlying `RefType` to make sure that we point to that type.
+// This only happens if we have a non-empty `ref` passed in, and that `ref` isn't pointing to something in our file
+// NOTE that the pointer here allows us to pass in a reference and edit in-place
+func ensureExternalRefsInRequestBodyDefinitions(defs *[]RequestBodyDefinition, ref string) {
+ if ref == "" {
+ return
+ }
+
+ for i, rbd := range *defs {
+ ensureExternalRefsInSchema(&rbd.Schema, ref)
+
+ // make sure we then update it in-place
+ (*defs)[i] = rbd
+ }
+}
+
+// ensureExternalRefsInResponseDefinitions ensures that when an externalRef (`$ref` that points to a file that isn't the current spec) is encountered, we make sure we update our underlying `RefType` to make sure that we point to that type.
+// This only happens if we have a non-empty `ref` passed in, and that `ref` isn't pointing to something in our file
+// NOTE that the pointer here allows us to pass in a reference and edit in-place
+func ensureExternalRefsInResponseDefinitions(defs *[]ResponseDefinition, ref string) {
+ if ref == "" {
+ return
+ }
+
+ for i, rd := range *defs {
+ for j, rcd := range rd.Contents {
+ ensureExternalRefsInSchema(&rcd.Schema, ref)
+
+ // make sure we then update it in-place
+ rd.Contents[j] = rcd
+ }
+
+ // make sure we then update it in-place
+ (*defs)[i] = rd
+ }
+}
+
+// ensureExternalRefsInParameterDefinitions ensures that when an externalRef (`$ref` that points to a file that isn't the current spec) is encountered, we make sure we update our underlying `RefType` to make sure that we point to that type.
+// This only happens if we have a non-empty `ref` passed in, and that `ref` isn't pointing to something in our file
+// NOTE that the pointer here allows us to pass in a reference and edit in-place
+func ensureExternalRefsInParameterDefinitions(defs *[]ParameterDefinition, ref string) {
+ if ref == "" {
+ return
+ }
+
+ for i, pd := range *defs {
+ ensureExternalRefsInSchema(&pd.Schema, ref)
+
+ // make sure we then update it in-place
+ (*defs)[i] = pd
+ }
+}
+
+// externalPackageFor returns the imported Go package name for a `$ref` that
+// targets a file outside the current spec. Returns an empty string when the
+// ref is empty, points within the current spec, or has no import-mapping.
+func externalPackageFor(ref string) string {
+ if ref == "" {
+ return ""
+ }
+ parts := strings.SplitN(ref, "#", 2)
+ if pack, ok := globalState.importMapping[parts[0]]; ok {
+ return pack.Name
+ }
+ return ""
+}
+
+// ensureExternalRefsInSchema ensures that when an externalRef (`$ref` that points to a file that isn't the current spec) is encountered, we make sure we update our underlying `RefType` to make sure that we point to that type.
+//
+// This only happens if we have a non-empty `ref` passed in, and that `ref` isn't pointing to something in our file
+//
+// NOTE that the pointer here allows us to pass in a reference and edit in-place
+func ensureExternalRefsInSchema(schema *Schema, ref string) {
+ if ref == "" {
+ return
+ }
+
+ parts := strings.SplitN(ref, "#", 2)
+ pack, ok := globalState.importMapping[parts[0]]
+ if !ok {
+ return
+ }
+
+ // if this is already defined as the start of a struct, we shouldn't inject **??**
+ if !strings.HasPrefix(schema.GoType, "struct {") {
+ schema.RefType = fmt.Sprintf("%s.%s", pack.Name, schema.GoType)
+ }
+
+ // Qualify union branch types. Each UnionElement was resolved as a
+ // local reference during generateUnion (e.g. "Bionicle"); when the
+ // enclosing schema came from an externally-ref'd file the branches
+ // actually live in the imported package, so the As/From/Merge
+ // methods generated by union.tmpl must use ".Bionicle" instead.
+ for i, elem := range schema.UnionElements {
+ s := string(elem)
+ if !strings.Contains(s, ".") {
+ schema.UnionElements[i] = UnionElement(fmt.Sprintf("%s.%s", pack.Name, s))
+ }
+ }
+}
diff --git a/pkg/codegen/filter.go b/pkg/codegen/filter.go
index 01a3639575..435968a379 100644
--- a/pkg/codegen/filter.go
+++ b/pkg/codegen/filter.go
@@ -2,21 +2,29 @@ package codegen
import "github.com/getkin/kin-openapi/openapi3"
+func sliceToMap(items []string) map[string]bool {
+ m := make(map[string]bool, len(items))
+ for _, item := range items {
+ m[item] = true
+ }
+ return m
+}
+
func filterOperationsByTag(swagger *openapi3.T, opts Configuration) {
if len(opts.OutputOptions.ExcludeTags) > 0 {
- excludeOperationsWithTags(swagger.Paths, opts.OutputOptions.ExcludeTags)
+ operationsWithTags(swagger.Paths, sliceToMap(opts.OutputOptions.ExcludeTags), true)
}
if len(opts.OutputOptions.IncludeTags) > 0 {
- includeOperationsWithTags(swagger.Paths, opts.OutputOptions.IncludeTags, false)
+ operationsWithTags(swagger.Paths, sliceToMap(opts.OutputOptions.IncludeTags), false)
}
}
-func excludeOperationsWithTags(paths openapi3.Paths, tags []string) {
- includeOperationsWithTags(paths, tags, true)
-}
+func operationsWithTags(paths *openapi3.Paths, tags map[string]bool, exclude bool) {
+ if paths == nil {
+ return
+ }
-func includeOperationsWithTags(paths openapi3.Paths, tags []string, exclude bool) {
- for _, pathItem := range paths {
+ for _, pathItem := range paths.Map() {
ops := pathItem.Operations()
names := make([]string, 0, len(ops))
for name, op := range ops {
@@ -31,16 +39,50 @@ func includeOperationsWithTags(paths openapi3.Paths, tags []string, exclude bool
}
// operationHasTag returns true if the operation is tagged with any of tags
-func operationHasTag(op *openapi3.Operation, tags []string) bool {
+func operationHasTag(op *openapi3.Operation, tags map[string]bool) bool {
if op == nil {
return false
}
for _, hasTag := range op.Tags {
- for _, wantTag := range tags {
- if hasTag == wantTag {
- return true
- }
+ if tags[hasTag] {
+ return true
}
}
return false
}
+
+func filterOperationsByOperationID(swagger *openapi3.T, opts Configuration) {
+ if len(opts.OutputOptions.ExcludeOperationIDs) > 0 {
+ operationsWithOperationIDs(swagger.Paths, sliceToMap(opts.OutputOptions.ExcludeOperationIDs), true)
+ }
+ if len(opts.OutputOptions.IncludeOperationIDs) > 0 {
+ operationsWithOperationIDs(swagger.Paths, sliceToMap(opts.OutputOptions.IncludeOperationIDs), false)
+ }
+}
+
+func operationsWithOperationIDs(paths *openapi3.Paths, operationIDs map[string]bool, exclude bool) {
+ if paths == nil {
+ return
+ }
+
+ for _, pathItem := range paths.Map() {
+ ops := pathItem.Operations()
+ names := make([]string, 0, len(ops))
+ for name, op := range ops {
+ if operationHasOperationID(op, operationIDs) == exclude {
+ names = append(names, name)
+ }
+ }
+ for _, name := range names {
+ pathItem.SetOperation(name, nil)
+ }
+ }
+}
+
+// operationHasOperationID returns true if the operation has operation id is included in operation ids
+func operationHasOperationID(op *openapi3.Operation, operationIDs map[string]bool) bool {
+ if op == nil {
+ return false
+ }
+ return operationIDs[op.OperationID]
+}
diff --git a/pkg/codegen/filter_test.go b/pkg/codegen/filter_test.go
index 774d016a84..09dcf5c5a3 100644
--- a/pkg/codegen/filter_test.go
+++ b/pkg/codegen/filter_test.go
@@ -67,3 +67,64 @@ func TestFilterOperationsByTag(t *testing.T) {
assert.NotContains(t, code, `"/cat"`)
})
}
+
+func TestFilterOperationsByOperationID(t *testing.T) {
+ packageName := "testswagger"
+ t.Run("include operation ids", func(t *testing.T) {
+ opts := Configuration{
+ PackageName: packageName,
+ Generate: GenerateOptions{
+ EchoServer: true,
+ Client: true,
+ Models: true,
+ EmbeddedSpec: true,
+ },
+ OutputOptions: OutputOptions{
+ IncludeOperationIDs: []string{"getCatStatus"},
+ },
+ }
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+
+ // Get a spec from the test definition in this file:
+ swagger, err := loader.LoadFromData([]byte(testOpenAPIDefinition))
+ assert.NoError(t, err)
+
+ // Run our code generation:
+ code, err := Generate(swagger, opts)
+ assert.NoError(t, err)
+ assert.NotEmpty(t, code)
+ assert.NotContains(t, code, `"/test/:name"`)
+ assert.Contains(t, code, `"/cat"`)
+ })
+
+ t.Run("exclude operation ids", func(t *testing.T) {
+ opts := Configuration{
+ PackageName: packageName,
+ Generate: GenerateOptions{
+ EchoServer: true,
+ Client: true,
+ Models: true,
+ EmbeddedSpec: true,
+ },
+ OutputOptions: OutputOptions{
+ ExcludeOperationIDs: []string{"getCatStatus"},
+ },
+ }
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
+
+ // Get a spec from the test definition in this file:
+ swagger, err := loader.LoadFromData([]byte(testOpenAPIDefinition))
+ assert.NoError(t, err)
+
+ // Run our code generation:
+ code, err := Generate(swagger, opts)
+ assert.NoError(t, err)
+ assert.NotEmpty(t, code)
+ assert.Contains(t, code, `"/test/:name"`)
+ assert.NotContains(t, code, `"/cat"`)
+ })
+}
diff --git a/pkg/codegen/gather.go b/pkg/codegen/gather.go
new file mode 100644
index 0000000000..0daf2ccf74
--- /dev/null
+++ b/pkg/codegen/gather.go
@@ -0,0 +1,338 @@
+package codegen
+
+import (
+ "cmp"
+ "fmt"
+ "slices"
+ "strings"
+
+ "github.com/getkin/kin-openapi/openapi3"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/util"
+)
+
+var _ fmt.Stringer = (*SchemaPath)(nil)
+
+// SchemaPath represents the document location of a schema, e.g.
+// ["components", "schemas", "Pet", "properties", "name"].
+type SchemaPath []string
+
+// String returns the path joined with "/".
+func (sp SchemaPath) String() string {
+ return strings.Join(sp, "/")
+}
+
+var _ fmt.Stringer = (*SchemaContext)(nil)
+
+// SchemaContext identifies where in the OpenAPI document a schema was found.
+type SchemaContext int
+
+const (
+ ContextComponentSchema SchemaContext = iota
+ ContextComponentParameter
+ ContextComponentRequestBody
+ ContextComponentResponse
+ ContextComponentHeader
+ ContextOperationParameter
+ ContextOperationRequestBody
+ ContextOperationResponse
+ ContextClientResponseWrapper
+)
+
+// String returns a human-readable name for the context.
+func (sc SchemaContext) String() string {
+ switch sc {
+ case ContextComponentSchema:
+ return "Schema"
+ case ContextComponentParameter:
+ return "Parameter"
+ case ContextComponentRequestBody:
+ return "RequestBody"
+ case ContextComponentResponse:
+ return "Response"
+ case ContextComponentHeader:
+ return "Header"
+ case ContextOperationParameter:
+ return "OperationParameter"
+ case ContextOperationRequestBody:
+ return "OperationRequestBody"
+ case ContextOperationResponse:
+ return "OperationResponse"
+ case ContextClientResponseWrapper:
+ return "ClientResponseWrapper"
+ default:
+ return "Unknown"
+ }
+}
+
+// Suffix returns the suffix to use for collision resolution.
+func (sc SchemaContext) Suffix() string {
+ switch sc {
+ case ContextComponentSchema:
+ return "Schema"
+ case ContextComponentParameter, ContextOperationParameter:
+ return "Parameter"
+ case ContextComponentRequestBody, ContextOperationRequestBody:
+ return "RequestBody"
+ case ContextComponentResponse, ContextOperationResponse:
+ return "Response"
+ case ContextComponentHeader:
+ return "Header"
+ case ContextClientResponseWrapper:
+ return "Response"
+ default:
+ return ""
+ }
+}
+
+// GatheredSchema represents a schema discovered during the gather pass,
+// along with its document location and context metadata.
+type GatheredSchema struct {
+ Path SchemaPath
+ Context SchemaContext
+ Ref string // $ref string if this is a reference
+ Schema *openapi3.Schema // The resolved schema value
+ OperationID string // Enclosing operation's ID, if any
+ ContentType string // Media type, if from request/response body
+ StatusCode string // HTTP status code, if from a response
+ ParamIndex int // Parameter index within an operation
+ ComponentName string // The component name (e.g., "Bar" for components/schemas/Bar)
+ GoNameOverride string // x-go-name override from the component or its parent container
+}
+
+// IsComponentSchema returns true if this schema came from components/schemas.
+func (gs *GatheredSchema) IsComponentSchema() bool {
+ return gs.Context == ContextComponentSchema
+}
+
+// GatherSchemas walks the entire OpenAPI spec and collects all schemas that
+// will need Go type names. This is the first pass of the multi-pass resolution.
+func GatherSchemas(spec *openapi3.T, opts Configuration) []*GatheredSchema {
+ var schemas []*GatheredSchema
+
+ if spec.Components != nil {
+ schemas = slices.Concat(
+ gatherComponentSchemas(spec.Components),
+ gatherComponentParameters(spec.Components),
+ gatherComponentResponses(spec.Components),
+ gatherComponentRequestBodies(spec.Components),
+ gatherComponentHeaders(spec.Components),
+ )
+ }
+
+ // Gather client response wrapper types for operations that will generate
+ // client code. These synthetic entries exist so wrapper types like
+ // `CreateChatCompletionResponse` participate in collision detection.
+ if opts.Generate.Client {
+ schemas = append(schemas, gatherClientResponseWrappers(spec)...)
+ }
+
+ return schemas
+}
+
+func gatherComponentSchemas(components *openapi3.Components) []*GatheredSchema {
+ var result []*GatheredSchema
+ for _, name := range SortedSchemaKeys(components.Schemas) {
+ schemaRef := components.Schemas[name]
+ if schemaRef == nil || schemaRef.Value == nil {
+ continue
+ }
+ var goNameOverride string
+ if schemaRef.Ref == "" {
+ goNameOverride = extractGoNameOverride(schemaRef.Value.Extensions)
+ }
+ result = append(result, &GatheredSchema{
+ Path: SchemaPath{"components", "schemas", name},
+ Context: ContextComponentSchema,
+ Ref: schemaRef.Ref,
+ Schema: schemaRef.Value,
+ ComponentName: name,
+ GoNameOverride: goNameOverride,
+ })
+ }
+ return result
+}
+
+func gatherComponentParameters(components *openapi3.Components) []*GatheredSchema {
+ var result []*GatheredSchema
+ for _, name := range SortedMapKeys(components.Parameters) {
+ paramRef := components.Parameters[name]
+ if paramRef == nil || paramRef.Value == nil {
+ continue
+ }
+ param := paramRef.Value
+ if param.Schema != nil && param.Schema.Value != nil {
+ var goNameOverride string
+ if paramRef.Ref == "" {
+ goNameOverride = extractGoNameOverride(param.Extensions)
+ }
+ result = append(result, &GatheredSchema{
+ Path: SchemaPath{"components", "parameters", name},
+ Context: ContextComponentParameter,
+ Ref: paramRef.Ref,
+ Schema: param.Schema.Value,
+ ComponentName: name,
+ GoNameOverride: goNameOverride,
+ })
+ }
+ }
+ return result
+}
+
+func gatherComponentResponses(components *openapi3.Components) []*GatheredSchema {
+ var result []*GatheredSchema
+ for _, name := range SortedMapKeys(components.Responses) {
+ responseRef := components.Responses[name]
+ if responseRef == nil || responseRef.Value == nil {
+ continue
+ }
+ response := responseRef.Value
+ var goNameOverride string
+ if responseRef.Ref == "" {
+ goNameOverride = extractGoNameOverride(response.Extensions)
+ }
+ for _, mediaType := range SortedMapKeys(response.Content) {
+ if !util.IsMediaTypeJson(mediaType) {
+ continue
+ }
+ mt := response.Content[mediaType]
+ if mt.Schema != nil && mt.Schema.Value != nil {
+ result = append(result, &GatheredSchema{
+ Path: SchemaPath{"components", "responses", name, "content", mediaType},
+ Context: ContextComponentResponse,
+ Ref: responseRef.Ref,
+ Schema: mt.Schema.Value,
+ ContentType: mediaType,
+ ComponentName: name,
+ GoNameOverride: goNameOverride,
+ })
+ }
+ }
+ }
+ return result
+}
+
+func gatherComponentRequestBodies(components *openapi3.Components) []*GatheredSchema {
+ var result []*GatheredSchema
+ for _, name := range SortedMapKeys(components.RequestBodies) {
+ bodyRef := components.RequestBodies[name]
+ if bodyRef == nil || bodyRef.Value == nil {
+ continue
+ }
+ body := bodyRef.Value
+ var goNameOverride string
+ if bodyRef.Ref == "" {
+ goNameOverride = extractGoNameOverride(body.Extensions)
+ }
+ for _, mediaType := range SortedMapKeys(body.Content) {
+ if !util.IsMediaTypeJson(mediaType) {
+ continue
+ }
+ mt := body.Content[mediaType]
+ if mt.Schema != nil && mt.Schema.Value != nil {
+ result = append(result, &GatheredSchema{
+ Path: SchemaPath{"components", "requestBodies", name, "content", mediaType},
+ Context: ContextComponentRequestBody,
+ Ref: bodyRef.Ref,
+ Schema: mt.Schema.Value,
+ ContentType: mediaType,
+ ComponentName: name,
+ GoNameOverride: goNameOverride,
+ })
+ }
+ }
+ }
+ return result
+}
+
+func gatherComponentHeaders(components *openapi3.Components) []*GatheredSchema {
+ var result []*GatheredSchema
+ for _, name := range SortedMapKeys(components.Headers) {
+ headerRef := components.Headers[name]
+ if headerRef == nil || headerRef.Value == nil {
+ continue
+ }
+ header := headerRef.Value
+ if header.Schema != nil && header.Schema.Value != nil {
+ var goNameOverride string
+ if headerRef.Ref == "" {
+ goNameOverride = extractGoNameOverride(header.Extensions)
+ }
+ result = append(result, &GatheredSchema{
+ Path: SchemaPath{"components", "headers", name},
+ Context: ContextComponentHeader,
+ Ref: headerRef.Ref,
+ Schema: header.Schema.Value,
+ ComponentName: name,
+ GoNameOverride: goNameOverride,
+ })
+ }
+ }
+ return result
+}
+
+// gatherClientResponseWrappers creates synthetic schema entries for each
+// operation that would generate a client response wrapper type like
+// `Response`. These don't correspond to a real schema in the
+// spec but they need names that don't collide with real types.
+func gatherClientResponseWrappers(spec *openapi3.T) []*GatheredSchema {
+ if spec.Paths == nil {
+ return nil
+ }
+
+ // Collect all operations sorted for determinism
+ type opEntry struct {
+ path string
+ method string
+ op *openapi3.Operation
+ }
+ var ops []opEntry
+
+ pathKeys := SortedMapKeys(spec.Paths.Map())
+ for _, path := range pathKeys {
+ pathItem := spec.Paths.Find(path)
+ if pathItem == nil {
+ continue
+ }
+ for method, op := range pathItem.Operations() {
+ if op != nil && op.OperationID != "" {
+ ops = append(ops, opEntry{path: path, method: method, op: op})
+ }
+ }
+ }
+
+ // Sort by operationID for determinism
+ slices.SortFunc(ops, func(a, b opEntry) int {
+ return cmp.Compare(a.op.OperationID, b.op.OperationID)
+ })
+
+ result := make([]*GatheredSchema, 0, len(ops))
+ for _, entry := range ops {
+ result = append(result, &GatheredSchema{
+ Path: SchemaPath{"paths", entry.path, entry.method, "x-client-response-wrapper"},
+ Context: ContextClientResponseWrapper,
+ OperationID: entry.op.OperationID,
+ })
+ }
+
+ return result
+}
+
+// FormatPath returns a human-readable representation of the path for debugging.
+func (gs *GatheredSchema) FormatPath() string {
+ return fmt.Sprintf("#/%s", strings.Join(gs.Path, "/"))
+}
+
+// extractGoNameOverride reads the x-go-name extension from extensions and
+// returns its value, or "" if not present or invalid.
+func extractGoNameOverride(extensions map[string]any) string {
+ ext, ok := extensions[extGoName]
+ if !ok {
+ return ""
+ }
+ name, err := extTypeName(ext)
+ if err != nil {
+ return ""
+ }
+ return name
+}
diff --git a/pkg/codegen/gather_test.go b/pkg/codegen/gather_test.go
new file mode 100644
index 0000000000..24e63b000b
--- /dev/null
+++ b/pkg/codegen/gather_test.go
@@ -0,0 +1,356 @@
+package codegen
+
+import (
+ "testing"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestGatherSchemas_ComponentSchemas(t *testing.T) {
+ spec := &openapi3.T{
+ Components: &openapi3.Components{
+ Schemas: openapi3.Schemas{
+ "Pet": &openapi3.SchemaRef{
+ Value: &openapi3.Schema{Type: &openapi3.Types{"object"}},
+ },
+ "Owner": &openapi3.SchemaRef{
+ Value: &openapi3.Schema{Type: &openapi3.Types{"object"}},
+ },
+ },
+ },
+ }
+
+ opts := Configuration{}
+ schemas := GatherSchemas(spec, opts)
+
+ require.Len(t, schemas, 2)
+
+ // Sorted order: Owner, Pet
+ assert.Equal(t, SchemaPath{"components", "schemas", "Owner"}, schemas[0].Path)
+ assert.Equal(t, ContextComponentSchema, schemas[0].Context)
+ assert.Equal(t, "Owner", schemas[0].ComponentName)
+
+ assert.Equal(t, SchemaPath{"components", "schemas", "Pet"}, schemas[1].Path)
+ assert.Equal(t, ContextComponentSchema, schemas[1].Context)
+ assert.Equal(t, "Pet", schemas[1].ComponentName)
+}
+
+func TestGatherSchemas_ComponentParameters(t *testing.T) {
+ spec := &openapi3.T{
+ Components: &openapi3.Components{
+ Parameters: openapi3.ParametersMap{
+ "Limit": &openapi3.ParameterRef{
+ Value: &openapi3.Parameter{
+ Name: "limit",
+ In: "query",
+ Schema: &openapi3.SchemaRef{
+ Value: &openapi3.Schema{Type: &openapi3.Types{"integer"}},
+ },
+ },
+ },
+ },
+ },
+ }
+
+ opts := Configuration{}
+ schemas := GatherSchemas(spec, opts)
+
+ require.Len(t, schemas, 1)
+ assert.Equal(t, SchemaPath{"components", "parameters", "Limit"}, schemas[0].Path)
+ assert.Equal(t, ContextComponentParameter, schemas[0].Context)
+ assert.Equal(t, "Limit", schemas[0].ComponentName)
+}
+
+func TestGatherSchemas_ComponentResponses(t *testing.T) {
+ spec := &openapi3.T{
+ Components: &openapi3.Components{
+ Responses: openapi3.ResponseBodies{
+ "Error": &openapi3.ResponseRef{
+ Value: &openapi3.Response{
+ Content: openapi3.Content{
+ "application/json": &openapi3.MediaType{
+ Schema: &openapi3.SchemaRef{
+ Value: &openapi3.Schema{Type: &openapi3.Types{"object"}},
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+
+ opts := Configuration{}
+ schemas := GatherSchemas(spec, opts)
+
+ require.Len(t, schemas, 1)
+ assert.Equal(t, SchemaPath{"components", "responses", "Error", "content", "application/json"}, schemas[0].Path)
+ assert.Equal(t, ContextComponentResponse, schemas[0].Context)
+ assert.Equal(t, "Error", schemas[0].ComponentName)
+ assert.Equal(t, "application/json", schemas[0].ContentType)
+}
+
+func TestGatherSchemas_ComponentRequestBodies(t *testing.T) {
+ spec := &openapi3.T{
+ Components: &openapi3.Components{
+ RequestBodies: openapi3.RequestBodies{
+ "CreatePet": &openapi3.RequestBodyRef{
+ Value: &openapi3.RequestBody{
+ Content: openapi3.Content{
+ "application/json": &openapi3.MediaType{
+ Schema: &openapi3.SchemaRef{
+ Value: &openapi3.Schema{Type: &openapi3.Types{"object"}},
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+
+ opts := Configuration{}
+ schemas := GatherSchemas(spec, opts)
+
+ require.Len(t, schemas, 1)
+ assert.Equal(t, SchemaPath{"components", "requestBodies", "CreatePet", "content", "application/json"}, schemas[0].Path)
+ assert.Equal(t, ContextComponentRequestBody, schemas[0].Context)
+ assert.Equal(t, "CreatePet", schemas[0].ComponentName)
+}
+
+func TestGatherSchemas_ComponentHeaders(t *testing.T) {
+ spec := &openapi3.T{
+ Components: &openapi3.Components{
+ Headers: openapi3.Headers{
+ "X-Rate-Limit": &openapi3.HeaderRef{
+ Value: &openapi3.Header{
+ Parameter: openapi3.Parameter{
+ Schema: &openapi3.SchemaRef{
+ Value: &openapi3.Schema{Type: &openapi3.Types{"integer"}},
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+
+ opts := Configuration{}
+ schemas := GatherSchemas(spec, opts)
+
+ require.Len(t, schemas, 1)
+ assert.Equal(t, SchemaPath{"components", "headers", "X-Rate-Limit"}, schemas[0].Path)
+ assert.Equal(t, ContextComponentHeader, schemas[0].Context)
+}
+
+func TestGatherSchemas_ClientResponseWrappers(t *testing.T) {
+ paths := openapi3.NewPaths()
+ paths.Set("/pets", &openapi3.PathItem{
+ Get: &openapi3.Operation{
+ OperationID: "listPets",
+ },
+ Post: &openapi3.Operation{
+ OperationID: "createPet",
+ },
+ })
+
+ spec := &openapi3.T{
+ Paths: paths,
+ }
+
+ // Without client generation, no wrappers
+ opts := Configuration{Generate: GenerateOptions{Client: false}}
+ schemas := GatherSchemas(spec, opts)
+ assert.Len(t, schemas, 0)
+
+ // With client generation, wrappers are gathered
+ opts = Configuration{Generate: GenerateOptions{Client: true}}
+ schemas = GatherSchemas(spec, opts)
+ assert.Len(t, schemas, 2)
+
+ // Check they're sorted by operationID
+ assert.Equal(t, ContextClientResponseWrapper, schemas[0].Context)
+ assert.Equal(t, "createPet", schemas[0].OperationID)
+ assert.Equal(t, ContextClientResponseWrapper, schemas[1].Context)
+ assert.Equal(t, "listPets", schemas[1].OperationID)
+}
+
+func TestGatherSchemas_GoNameOverride_Schema(t *testing.T) {
+ spec := &openapi3.T{
+ Components: &openapi3.Components{
+ Schemas: openapi3.Schemas{
+ "Renamer": &openapi3.SchemaRef{
+ Value: &openapi3.Schema{
+ Type: &openapi3.Types{"object"},
+ Extensions: map[string]any{"x-go-name": "SpecialName"},
+ },
+ },
+ },
+ },
+ }
+
+ opts := Configuration{}
+ schemas := GatherSchemas(spec, opts)
+
+ require.Len(t, schemas, 1)
+ assert.Equal(t, "SpecialName", schemas[0].GoNameOverride)
+}
+
+func TestGatherSchemas_GoNameOverride_Response(t *testing.T) {
+ spec := &openapi3.T{
+ Components: &openapi3.Components{
+ Responses: openapi3.ResponseBodies{
+ "Outcome": &openapi3.ResponseRef{
+ Value: &openapi3.Response{
+ Extensions: map[string]any{"x-go-name": "OutcomeResult"},
+ Content: openapi3.Content{
+ "application/json": &openapi3.MediaType{
+ Schema: &openapi3.SchemaRef{
+ Value: &openapi3.Schema{Type: &openapi3.Types{"object"}},
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+
+ opts := Configuration{}
+ schemas := GatherSchemas(spec, opts)
+
+ require.Len(t, schemas, 1)
+ assert.Equal(t, "OutcomeResult", schemas[0].GoNameOverride)
+}
+
+func TestGatherSchemas_GoNameOverride_RequestBody(t *testing.T) {
+ spec := &openapi3.T{
+ Components: &openapi3.Components{
+ RequestBodies: openapi3.RequestBodies{
+ "Payload": &openapi3.RequestBodyRef{
+ Value: &openapi3.RequestBody{
+ Extensions: map[string]any{"x-go-name": "PayloadBody"},
+ Content: openapi3.Content{
+ "application/json": &openapi3.MediaType{
+ Schema: &openapi3.SchemaRef{
+ Value: &openapi3.Schema{Type: &openapi3.Types{"object"}},
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+
+ opts := Configuration{}
+ schemas := GatherSchemas(spec, opts)
+
+ require.Len(t, schemas, 1)
+ assert.Equal(t, "PayloadBody", schemas[0].GoNameOverride)
+}
+
+func TestGatherSchemas_GoNameOverride_SkippedForRef(t *testing.T) {
+ spec := &openapi3.T{
+ Components: &openapi3.Components{
+ Schemas: openapi3.Schemas{
+ "AliasedPet": &openapi3.SchemaRef{
+ Ref: "#/components/schemas/Pet",
+ Value: &openapi3.Schema{
+ Type: &openapi3.Types{"object"},
+ Extensions: map[string]any{"x-go-name": "ShouldBeIgnored"},
+ },
+ },
+ },
+ },
+ }
+
+ opts := Configuration{}
+ schemas := GatherSchemas(spec, opts)
+
+ require.Len(t, schemas, 1)
+ assert.Equal(t, "", schemas[0].GoNameOverride)
+}
+
+func TestGatherSchemas_AllSections(t *testing.T) {
+ // Spec with "Bar" in schemas, parameters, responses, requestBodies, headers
+ // This is the issue #200 scenario (cross-section collision)
+ paths := openapi3.NewPaths()
+ spec := &openapi3.T{
+ Paths: paths,
+ Components: &openapi3.Components{
+ Schemas: openapi3.Schemas{
+ "Bar": &openapi3.SchemaRef{
+ Value: &openapi3.Schema{Type: &openapi3.Types{"object"}},
+ },
+ },
+ Parameters: openapi3.ParametersMap{
+ "Bar": &openapi3.ParameterRef{
+ Value: &openapi3.Parameter{
+ Name: "Bar",
+ In: "query",
+ Schema: &openapi3.SchemaRef{
+ Value: &openapi3.Schema{Type: &openapi3.Types{"string"}},
+ },
+ },
+ },
+ },
+ Responses: openapi3.ResponseBodies{
+ "Bar": &openapi3.ResponseRef{
+ Value: &openapi3.Response{
+ Content: openapi3.Content{
+ "application/json": &openapi3.MediaType{
+ Schema: &openapi3.SchemaRef{
+ Value: &openapi3.Schema{Type: &openapi3.Types{"object"}},
+ },
+ },
+ },
+ },
+ },
+ },
+ RequestBodies: openapi3.RequestBodies{
+ "Bar": &openapi3.RequestBodyRef{
+ Value: &openapi3.RequestBody{
+ Content: openapi3.Content{
+ "application/json": &openapi3.MediaType{
+ Schema: &openapi3.SchemaRef{
+ Value: &openapi3.Schema{Type: &openapi3.Types{"object"}},
+ },
+ },
+ },
+ },
+ },
+ },
+ Headers: openapi3.Headers{
+ "Bar": &openapi3.HeaderRef{
+ Value: &openapi3.Header{
+ Parameter: openapi3.Parameter{
+ Schema: &openapi3.SchemaRef{
+ Value: &openapi3.Schema{Type: &openapi3.Types{"boolean"}},
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+
+ opts := Configuration{}
+ schemas := GatherSchemas(spec, opts)
+
+ // Should have 5 entries: schema, parameter, response, requestBody, header
+ assert.Len(t, schemas, 5)
+
+ // Verify contexts are all different
+ contexts := make(map[SchemaContext]bool)
+ for _, s := range schemas {
+ contexts[s.Context] = true
+ }
+ assert.True(t, contexts[ContextComponentSchema])
+ assert.True(t, contexts[ContextComponentParameter])
+ assert.True(t, contexts[ContextComponentResponse])
+ assert.True(t, contexts[ContextComponentRequestBody])
+ assert.True(t, contexts[ContextComponentHeader])
+}
diff --git a/pkg/codegen/inline.go b/pkg/codegen/inline.go
index 459255c05f..c07e1fe659 100644
--- a/pkg/codegen/inline.go
+++ b/pkg/codegen/inline.go
@@ -15,7 +15,7 @@ package codegen
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"fmt"
@@ -35,20 +35,21 @@ func GenerateInlinedSpec(t *template.Template, importMapping importMap, swagger
return "", fmt.Errorf("error marshaling swagger: %w", err)
}
- // gzip
+ // flate
var buf bytes.Buffer
- zw, err := gzip.NewWriterLevel(&buf, gzip.BestCompression)
+ zw, err := flate.NewWriter(&buf, flate.BestCompression)
if err != nil {
- return "", fmt.Errorf("error creating gzip compressor: %w", err)
+ return "", fmt.Errorf("new flate writer: %w", err)
}
- _, err = zw.Write(encoded)
- if err != nil {
- return "", fmt.Errorf("error gzipping swagger file: %w", err)
+
+ if _, err := zw.Write(encoded); err != nil {
+ return "", fmt.Errorf("write flate: %w", err)
}
- err = zw.Close()
- if err != nil {
- return "", fmt.Errorf("error gzipping swagger file: %w", err)
+
+ if err := zw.Close(); err != nil {
+ return "", fmt.Errorf("close flate writer: %w", err)
}
+
str := base64.StdEncoding.EncodeToString(buf.Bytes())
var parts []string
diff --git a/pkg/codegen/merge_schemas.go b/pkg/codegen/merge_schemas.go
index 419d52bd94..3becb5e412 100644
--- a/pkg/codegen/merge_schemas.go
+++ b/pkg/codegen/merge_schemas.go
@@ -3,6 +3,8 @@ package codegen
import (
"errors"
"fmt"
+ "maps"
+ "reflect"
"strings"
"github.com/getkin/kin-openapi/openapi3"
@@ -26,30 +28,138 @@ func mergeSchemas(allOf []*openapi3.SchemaRef, path []string) (Schema, error) {
return GenerateGoSchema(allOf[0], path)
}
+ // Distinguish two uses of allOf:
+ //
+ // 1. Decorator idiom — at least one INLINE member (Ref == "") is
+ // "extension-only" (carries no structural content). This is a
+ // workaround for OpenAPI 3.0's $ref-sibling restriction: users
+ // wrap a $ref in allOf to attach extensions like
+ // x-go-type-skip-optional-pointer (see issue #1957). Here
+ // extensions are meant to flow through to the result.
+ //
+ // 2. Real composition — every member either contributes structural
+ // content or is a $ref contributing the referenced schema. The
+ // result is a NEW distinct type, and extensions like x-go-type on
+ // a source schema do NOT transfer (see issue #2335: Client has
+ // x-go-type=OverlayClient, but allOf[Client, {properties:{id}}]
+ // is ClientWithId — a different shape, not OverlayClient).
+ //
+ // A $ref member is excluded from the decorator check because it is by
+ // construction delivering the referenced schema, not "decorating"
+ // siblings — even if the referenced schema happens to carry only
+ // extensions, that's a property of the target, not an intent on this
+ // composition.
+ decoratorIdiom := false
+ for _, m := range allOf {
+ if m.Ref == "" && isExtensionOnlySchema(m.Value) {
+ decoratorIdiom = true
+ break
+ }
+ }
+
schema, err := valueWithPropagatedRef(allOf[0])
if err != nil {
return Schema{}, err
}
+ // Seed allOf[0]'s ref so that if s1's own AllOf contains a back-reference
+ // to itself, the cycle is detected during recursive merging.
+ seenTopLevel := make(map[string]bool)
+ if allOf[0].Ref != "" {
+ seenTopLevel[allOf[0].Ref] = true
+ }
+
for i := 1; i < n; i++ {
var err error
oneOfSchema, err := valueWithPropagatedRef(allOf[i])
if err != nil {
return Schema{}, err
}
- schema, err = mergeOpenapiSchemas(schema, oneOfSchema, true)
+
+ seenSchemaRef := make(map[string]bool)
+ for k := range seenTopLevel {
+ seenSchemaRef[k] = true
+ }
+ if allOf[i].Ref != "" {
+ seenSchemaRef[allOf[i].Ref] = true
+ seenTopLevel[allOf[i].Ref] = true
+ }
+ schema, err = mergeOpenapiSchemas(schema, oneOfSchema, true, seenSchemaRef)
if err != nil {
return Schema{}, fmt.Errorf("error merging schemas for AllOf: %w", err)
}
}
+
+ if !decoratorIdiom {
+ // Drop only the type-identity directives. Other extensions
+ // (user-defined x-* metadata, etc.) are preserved — we only
+ // have concrete evidence that the identity-bound ones cause
+ // incorrect aliasing across composition.
+ //
+ // Clone before mutating: the current merge path always
+ // reallocates schema.Extensions in mergeOpenapiSchemas before
+ // we reach here, so the delete is safe today — but the
+ // defensive copy keeps this correct if that invariant changes
+ // (e.g. an allocation-skipping optimization). Cost is a small
+ // map copy on a single code path.
+ ext := maps.Clone(schema.Extensions)
+ delete(ext, extPropGoType)
+ delete(ext, extGoTypeName)
+ delete(ext, extPropGoImport)
+ schema.Extensions = ext
+ }
+
return GenerateGoSchema(openapi3.NewSchemaRef("", &schema), path)
}
-// valueWithPropagatedRef returns a copy of ref schema with its Properties refs
-// updated if ref itself is external. Otherwise, return ref.Value as-is.
+// isExtensionOnlySchema reports whether a schema carries only extensions,
+// with no structural or constraint-bearing content. Used to detect the
+// "$ref + sibling extension" idiom: allOf wrappers whose purpose is
+// attaching extensions to a $ref (since OpenAPI 3.0 disallows sibling
+// keys next to $ref).
+//
+// Implementation: zero out every field that doesn't affect the generated
+// Go type, then compare to the zero Schema. Anything left over — a Type,
+// Properties, Pattern, MinLength, etc. — disqualifies the schema from
+// being treated as a pure decorator. This formulation defaults to safe
+// behavior if kin-openapi gains new structural fields: they'd be non-zero
+// by default and correctly disqualify.
+func isExtensionOnlySchema(s *openapi3.Schema) bool {
+ if s == nil || len(s.Extensions) == 0 {
+ return false
+ }
+ tmp := *s
+ tmp.Extensions = nil
+ // Source-tracking metadata from kin-openapi; always non-nil for
+ // schemas parsed from a file.
+ tmp.Origin = nil
+ // Purely documentary / metadata fields. These don't affect the
+ // generated Go type, so a schema carrying only these plus extensions
+ // still behaves as a decorator.
+ tmp.Title = ""
+ tmp.Description = ""
+ tmp.Default = nil
+ tmp.Example = nil
+ tmp.ExternalDocs = nil
+ tmp.Deprecated = false
+ tmp.ReadOnly = false
+ tmp.WriteOnly = false
+ tmp.AllowEmptyValue = false
+ tmp.XML = nil
+ return reflect.DeepEqual(tmp, openapi3.Schema{})
+}
+
+// valueWithPropagatedRef returns a copy of ref's schema with its Properties
+// refs rewritten when ref itself is external, and with extensions placed
+// next to the $ref folded in (ref-side wins over value-side). This is what
+// allows allOf members to carry per-use sibling directives without
+// mutating the referenced schema.
func valueWithPropagatedRef(ref *openapi3.SchemaRef) (openapi3.Schema, error) {
+ schema := *ref.Value
+ schema.Extensions = combinedSchemaExtensions(ref)
+
if len(ref.Ref) == 0 || ref.Ref[0] == '#' {
- return *ref.Value, nil
+ return schema, nil
}
pathParts := strings.Split(ref.Ref, "#")
@@ -58,23 +168,79 @@ func valueWithPropagatedRef(ref *openapi3.SchemaRef) (openapi3.Schema, error) {
}
remoteComponent := pathParts[0]
- // remote ref
- schema := *ref.Value
+ propagateRemoteRefs(remoteComponent, &schema)
+
+ return schema, nil
+}
+
+// propagateRemoteRefs rewrites local "#/..." refs within a schema to be
+// qualified with the remote component path. This is needed so that when an
+// external schema is flattened via allOf, nested type references (array items,
+// additionalProperties, sub-object properties) retain their external
+// qualification. See https://github.com/oapi-codegen/oapi-codegen/issues/2288
+func propagateRemoteRefs(remoteComponent string, schema *openapi3.Schema) {
for _, value := range schema.Properties {
if len(value.Ref) > 0 && value.Ref[0] == '#' {
- // local reference, should propagate remote
value.Ref = remoteComponent + value.Ref
+ } else if value.Value != nil {
+ propagateRemoteRefs(remoteComponent, value.Value)
}
}
- return schema, nil
+ if schema.Items != nil {
+ if len(schema.Items.Ref) > 0 && schema.Items.Ref[0] == '#' {
+ schema.Items.Ref = remoteComponent + schema.Items.Ref
+ } else if schema.Items.Value != nil {
+ propagateRemoteRefs(remoteComponent, schema.Items.Value)
+ }
+ }
+
+ if schema.AdditionalProperties.Schema != nil {
+ ap := schema.AdditionalProperties.Schema
+ if len(ap.Ref) > 0 && ap.Ref[0] == '#' {
+ ap.Ref = remoteComponent + ap.Ref
+ } else if ap.Value != nil {
+ propagateRemoteRefs(remoteComponent, ap.Value)
+ }
+ }
+
+ for _, list := range [][]*openapi3.SchemaRef{schema.AllOf, schema.AnyOf, schema.OneOf} {
+ for _, ref := range list {
+ if len(ref.Ref) > 0 && ref.Ref[0] == '#' {
+ ref.Ref = remoteComponent + ref.Ref
+ } else if ref.Value != nil {
+ propagateRemoteRefs(remoteComponent, ref.Value)
+ }
+ }
+ }
+
+ if schema.Not != nil {
+ if len(schema.Not.Ref) > 0 && schema.Not.Ref[0] == '#' {
+ schema.Not.Ref = remoteComponent + schema.Not.Ref
+ } else if schema.Not.Value != nil {
+ propagateRemoteRefs(remoteComponent, schema.Not.Value)
+ }
+ }
}
-func mergeAllOf(allOf []*openapi3.SchemaRef) (openapi3.Schema, error) {
+func mergeAllOf(allOf []*openapi3.SchemaRef, seenSchemaRef map[string]bool) (openapi3.Schema, error) {
var schema openapi3.Schema
for _, schemaRef := range allOf {
var err error
- schema, err = mergeOpenapiSchemas(schema, *schemaRef.Value, true)
+ if schemaRef.Ref != "" && seenSchemaRef[schemaRef.Ref] {
+ continue
+ }
+ if schemaRef.Ref != "" {
+ seenSchemaRef[schemaRef.Ref] = true
+ }
+ // Use valueWithPropagatedRef so sibling extensions on a $ref
+ // member of a transitively-flattened allOf reach the merged
+ // schema, matching mergeSchemas' top-level handling.
+ member, err := valueWithPropagatedRef(schemaRef)
+ if err != nil {
+ return openapi3.Schema{}, err
+ }
+ schema, err = mergeOpenapiSchemas(schema, member, true, seenSchemaRef)
if err != nil {
return openapi3.Schema{}, fmt.Errorf("error merging schemas for AllOf: %w", err)
}
@@ -84,22 +250,13 @@ func mergeAllOf(allOf []*openapi3.SchemaRef) (openapi3.Schema, error) {
// mergeOpenapiSchemas merges two openAPI schemas and returns the schema
// all of whose fields are composed.
-func mergeOpenapiSchemas(s1, s2 openapi3.Schema, allOf bool) (openapi3.Schema, error) {
+func mergeOpenapiSchemas(s1, s2 openapi3.Schema, allOf bool, seenSchemaRef map[string]bool) (openapi3.Schema, error) {
var result openapi3.Schema
- if s1.Extensions != nil || s2.Extensions != nil {
- result.Extensions = make(map[string]interface{})
- if s1.Extensions != nil {
- for k, v := range s1.Extensions {
- result.Extensions[k] = v
- }
- }
- if s2.Extensions != nil {
- for k, v := range s2.Extensions {
- // TODO: Check for collisions
- result.Extensions[k] = v
- }
- }
- }
+
+ result.Extensions = make(map[string]any, len(s1.Extensions)+len(s2.Extensions))
+ maps.Copy(result.Extensions, s1.Extensions)
+ // TODO: Check for collisions
+ maps.Copy(result.Extensions, s2.Extensions)
result.OneOf = append(s1.OneOf, s2.OneOf...)
@@ -108,7 +265,7 @@ func mergeOpenapiSchemas(s1, s2 openapi3.Schema, allOf bool) (openapi3.Schema, e
var err error
if s1.AllOf != nil {
var merged openapi3.Schema
- merged, err = mergeAllOf(s1.AllOf)
+ merged, err = mergeAllOf(s1.AllOf, seenSchemaRef)
if err != nil {
return openapi3.Schema{}, fmt.Errorf("error transitive merging AllOf on schema 1")
}
@@ -116,7 +273,7 @@ func mergeOpenapiSchemas(s1, s2 openapi3.Schema, allOf bool) (openapi3.Schema, e
}
if s2.AllOf != nil {
var merged openapi3.Schema
- merged, err = mergeAllOf(s2.AllOf)
+ merged, err = mergeAllOf(s2.AllOf, seenSchemaRef)
if err != nil {
return openapi3.Schema{}, fmt.Errorf("error transitive merging AllOf on schema 2")
}
@@ -125,8 +282,8 @@ func mergeOpenapiSchemas(s1, s2 openapi3.Schema, allOf bool) (openapi3.Schema, e
result.AllOf = append(s1.AllOf, s2.AllOf...)
- if s1.Type != "" && s2.Type != "" && s1.Type != s2.Type {
- return openapi3.Schema{}, errors.New("can not merge incompatible types")
+ if s1.Type.Slice() != nil && s2.Type.Slice() != nil && !equalTypes(s1.Type, s2.Type) {
+ return openapi3.Schema{}, fmt.Errorf("can not merge incompatible types: %v, %v", s1.Type.Slice(), s2.Type.Slice())
}
result.Type = s1.Type
@@ -200,14 +357,10 @@ func mergeOpenapiSchemas(s1, s2 openapi3.Schema, allOf bool) (openapi3.Schema, e
result.Required = append(s1.Required, s2.Required...)
// We merge all properties
- result.Properties = make(map[string]*openapi3.SchemaRef)
- for k, v := range s1.Properties {
- result.Properties[k] = v
- }
- for k, v := range s2.Properties {
- // TODO: detect conflicts
- result.Properties[k] = v
- }
+ result.Properties = make(map[string]*openapi3.SchemaRef, len(s1.Properties)+len(s2.Properties))
+ maps.Copy(result.Properties, s1.Properties)
+ // TODO: detect conflicts
+ maps.Copy(result.Properties, s2.Properties)
if isAdditionalPropertiesExplicitFalse(&s1) || isAdditionalPropertiesExplicitFalse(&s2) {
result.WithoutAdditionalProperties()
@@ -232,5 +385,34 @@ func mergeOpenapiSchemas(s1, s2 openapi3.Schema, allOf bool) (openapi3.Schema, e
return openapi3.Schema{}, errors.New("merging two schemas with discriminators is not supported")
}
+ // For allOf merges, propagate a discriminator if only one schema has it.
+ // Merging two different discriminators is not supported.
+ if s1.Discriminator != nil && s2.Discriminator != nil {
+ return openapi3.Schema{}, errors.New("merging two schemas with discriminators is not supported")
+ }
+ if s1.Discriminator != nil {
+ result.Discriminator = s1.Discriminator
+ } else if s2.Discriminator != nil {
+ result.Discriminator = s2.Discriminator
+ }
+
return result, nil
}
+
+func equalTypes(t1 *openapi3.Types, t2 *openapi3.Types) bool {
+ s1 := t1.Slice()
+ s2 := t2.Slice()
+
+ if len(s1) != len(s2) {
+ return false
+ }
+
+ // NOTE that ideally we'd use `slices.Equal` but as we're currently supporting Go 1.20+, we can't use it (yet https://github.com/oapi-codegen/oapi-codegen/issues/1634)
+ for i := range s1 {
+ if s1[i] != s2[i] {
+ return false
+ }
+ }
+
+ return true
+}
diff --git a/pkg/codegen/merge_schemas_test.go b/pkg/codegen/merge_schemas_test.go
new file mode 100644
index 0000000000..61fcbef125
--- /dev/null
+++ b/pkg/codegen/merge_schemas_test.go
@@ -0,0 +1,68 @@
+package codegen
+
+import (
+ "testing"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestMergeOpenapiSchemas_DiscriminatorPropagation(t *testing.T) {
+ disc := &openapi3.Discriminator{
+ PropertyName: "type",
+ }
+
+ t.Run("allOf with single discriminator on s1 propagates it", func(t *testing.T) {
+ s1 := openapi3.Schema{Discriminator: disc}
+ s2 := openapi3.Schema{}
+
+ result, err := mergeOpenapiSchemas(s1, s2, true, make(map[string]bool))
+ require.NoError(t, err)
+ assert.Equal(t, disc, result.Discriminator)
+ })
+
+ t.Run("allOf with single discriminator on s2 propagates it", func(t *testing.T) {
+ s1 := openapi3.Schema{}
+ s2 := openapi3.Schema{Discriminator: disc}
+
+ result, err := mergeOpenapiSchemas(s1, s2, true, make(map[string]bool))
+ require.NoError(t, err)
+ assert.Equal(t, disc, result.Discriminator)
+ })
+
+ t.Run("allOf with discriminators on both schemas errors", func(t *testing.T) {
+ disc2 := &openapi3.Discriminator{PropertyName: "kind"}
+ s1 := openapi3.Schema{Discriminator: disc}
+ s2 := openapi3.Schema{Discriminator: disc2}
+
+ _, err := mergeOpenapiSchemas(s1, s2, true, make(map[string]bool))
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "discriminators")
+ })
+
+ t.Run("allOf with no discriminators succeeds with nil discriminator", func(t *testing.T) {
+ s1 := openapi3.Schema{}
+ s2 := openapi3.Schema{}
+
+ result, err := mergeOpenapiSchemas(s1, s2, true, make(map[string]bool))
+ require.NoError(t, err)
+ assert.Nil(t, result.Discriminator)
+ })
+
+ t.Run("non-allOf with discriminator on s1 errors", func(t *testing.T) {
+ s1 := openapi3.Schema{Discriminator: disc}
+ s2 := openapi3.Schema{}
+
+ _, err := mergeOpenapiSchemas(s1, s2, false, make(map[string]bool))
+ require.Error(t, err)
+ })
+
+ t.Run("non-allOf with discriminator on s2 errors", func(t *testing.T) {
+ s1 := openapi3.Schema{}
+ s2 := openapi3.Schema{Discriminator: disc}
+
+ _, err := mergeOpenapiSchemas(s1, s2, false, make(map[string]bool))
+ require.Error(t, err)
+ })
+}
diff --git a/pkg/codegen/merge_schemas_v1.go b/pkg/codegen/merge_schemas_v1.go
index af83582381..b82eb3e622 100644
--- a/pkg/codegen/merge_schemas_v1.go
+++ b/pkg/codegen/merge_schemas_v1.go
@@ -3,6 +3,7 @@ package codegen
import (
"errors"
"fmt"
+ "slices"
"strings"
"github.com/getkin/kin-openapi/openapi3"
@@ -100,7 +101,7 @@ func GenStructFromAllOf(allOf []*openapi3.SchemaRef, path []string) (string, err
}
additionalPropertiesPart := fmt.Sprintf("AdditionalProperties map[string]%s `json:\"-\"`", addPropsType)
- if !StringInArray(additionalPropertiesPart, objectParts) {
+ if !slices.Contains(objectParts, additionalPropertiesPart) {
objectParts = append(objectParts, additionalPropertiesPart)
}
}
diff --git a/pkg/codegen/minimum_go_version.go b/pkg/codegen/minimum_go_version.go
new file mode 100644
index 0000000000..4f4f70fe7b
--- /dev/null
+++ b/pkg/codegen/minimum_go_version.go
@@ -0,0 +1,91 @@
+package codegen
+
+import (
+ "fmt"
+ "os"
+ "path/filepath"
+ "strconv"
+ "strings"
+
+ "golang.org/x/mod/modfile"
+)
+
+const maximumDepthToSearchForGoMod = 5
+
+// minimumGoVersionForGenerateStdHTTPServer indicates the Go 1.x minor version that the module the std-http-server is being generated into needs.
+// If the version is lower, a warning should be logged.
+const minimumGoVersionForGenerateStdHTTPServer = 22
+
+func findAndParseGoModuleForDepth(dir string, maxDepth int) (string, *modfile.File, error) {
+ absDir, err := filepath.Abs(dir)
+ if err != nil {
+ return "", nil, fmt.Errorf("failed to determine absolute path for %v: %w", dir, err)
+ }
+ currentDir := absDir
+
+ for i := 0; i <= maxDepth; i++ {
+ goModPath := filepath.Join(currentDir, "go.mod")
+ if _, err := os.Stat(goModPath); err == nil {
+ goModContent, err := os.ReadFile(goModPath)
+ if err != nil {
+ return "", nil, fmt.Errorf("failed to read `go.mod`: %w", err)
+ }
+
+ mod, err := modfile.ParseLax("go.mod", goModContent, nil)
+ if err != nil {
+ return "", nil, fmt.Errorf("failed to parse `go.mod`: %w", err)
+ }
+
+ return goModPath, mod, nil
+ }
+
+ goModPath = filepath.Join(currentDir, "tools.mod")
+ if _, err := os.Stat(goModPath); err == nil {
+ goModContent, err := os.ReadFile(goModPath)
+ if err != nil {
+ return "", nil, fmt.Errorf("failed to read `tools.mod`: %w", err)
+ }
+
+ parsedModFile, err := modfile.ParseLax("tools.mod", goModContent, nil)
+ if err != nil {
+ return "", nil, fmt.Errorf("failed to parse `tools.mod`: %w", err)
+ }
+
+ return goModPath, parsedModFile, nil
+ }
+
+ parentDir := filepath.Dir(currentDir)
+ // NOTE that this may not work particularly well on Windows
+ if parentDir == "/" {
+ break
+ }
+
+ currentDir = parentDir
+ }
+
+ return "", nil, fmt.Errorf("no `go.mod` or `tools.mod` file found within %d levels upwards from %s", maxDepth, absDir)
+}
+
+// hasMinimalMinorGoDirective indicates that the Go module (`mod`) has a minor version greater than or equal to the `expected`'s
+// This only applies to the `go` directive:
+//
+// go 1.23
+// go 1.22.1
+func hasMinimalMinorGoDirective(expected int, mod *modfile.File) bool {
+ parts := strings.Split(mod.Go.Version, ".")
+
+ if len(parts) < 2 {
+ return false
+ }
+
+ actual, err := strconv.Atoi(parts[1])
+ if err != nil {
+ return false
+ }
+
+ if actual < expected {
+ return false
+ }
+
+ return true
+}
diff --git a/pkg/codegen/operations.go b/pkg/codegen/operations.go
index c66fa31d57..736a8ea1b5 100644
--- a/pkg/codegen/operations.go
+++ b/pkg/codegen/operations.go
@@ -16,15 +16,18 @@ package codegen
import (
"bufio"
"bytes"
+ "cmp"
"fmt"
- "sort"
+ "maps"
+ "slices"
"strconv"
"strings"
"text/template"
"unicode"
- "github.com/deepmap/oapi-codegen/pkg/util"
"github.com/getkin/kin-openapi/openapi3"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/util"
)
type ParameterDefinition struct {
@@ -43,15 +46,70 @@ func (pd ParameterDefinition) TypeDef() string {
return typeDecl
}
+// RequiresNilCheck indicates whether the generated property should have a nil check performed on it before other checks.
+// This should be used in templates when performing `nil` checks, but NOT when i.e. determining if there should be an optional pointer given to the type - in that case, use `HasOptionalPointer`
+func (pd ParameterDefinition) RequiresNilCheck() bool {
+ return pd.ZeroValueIsNil() || pd.HasOptionalPointer()
+}
+
+// ZeroValueIsNil is a helper function to determine if the given Go type used
+// for this property has `nil` as its Go zero value. Slices (OpenAPI `array`)
+// and maps (OpenAPI `object` with only `additionalProperties`, rendered as
+// `map[K]V`) both satisfy this — templates use it to decide whether to emit a
+// nil-check before reading the field.
+func (pd ParameterDefinition) ZeroValueIsNil() bool {
+ if pd.Schema.OAPISchema == nil {
+ return false
+ }
+
+ if pd.Schema.OAPISchema.Type.Is("array") {
+ return true
+ }
+
+ return strings.HasPrefix(pd.Schema.GoType, "map[")
+}
+
// JsonTag generates the JSON annotation to map GoType to json type name. If Parameter
// Foo is marshaled to json as "foo", this will create the annotation
// 'json:"foo"'
+// It also includes any additional struct tags from x-oapi-codegen-extra-tags
+// at the parameter or schema level (parameter-level takes precedence).
func (pd *ParameterDefinition) JsonTag() string {
+ fieldTags := make(map[string]string)
+
if pd.Required {
- return fmt.Sprintf("`json:\"%s\"`", pd.ParamName)
+ fieldTags["json"] = pd.ParamName
} else {
- return fmt.Sprintf("`json:\"%s,omitempty\"`", pd.ParamName)
+ fieldTags["json"] = pd.ParamName + ",omitempty"
+ }
+
+ // Merge x-oapi-codegen-extra-tags from schema level first, then parameter level
+ // so that parameter-level takes precedence.
+ if pd.Spec != nil && pd.Spec.Schema != nil && pd.Spec.Schema.Value != nil {
+ if extension, ok := pd.Spec.Schema.Value.Extensions[extPropExtraTags]; ok {
+ if tags, err := extExtraTags(extension); err == nil {
+ for k, v := range tags {
+ fieldTags[k] = v
+ }
+ }
+ }
}
+ if pd.Spec != nil {
+ if extension, ok := pd.Spec.Extensions[extPropExtraTags]; ok {
+ if tags, err := extExtraTags(extension); err == nil {
+ for k, v := range tags {
+ fieldTags[k] = v
+ }
+ }
+ }
+ }
+
+ keys := SortedMapKeys(fieldTags)
+ tags := make([]string, len(keys))
+ for i, k := range keys {
+ tags[i] = fmt.Sprintf(`%s:"%s"`, k, fieldTags[k])
+ }
+ return "`" + strings.Join(tags, " ") + "`"
}
func (pd *ParameterDefinition) IsJson() bool {
@@ -113,8 +171,36 @@ func (pd *ParameterDefinition) Explode() bool {
return *pd.Spec.Explode
}
+// SchemaType returns the first OpenAPI type string for this parameter's schema (e.g. "string", "integer"),
+// or empty string if unavailable.
+func (pd *ParameterDefinition) SchemaType() string {
+ if pd.Spec.Schema != nil && pd.Spec.Schema.Value != nil && pd.Spec.Schema.Value.Type != nil {
+ if s := pd.Spec.Schema.Value.Type.Slice(); len(s) > 0 {
+ return s[0]
+ }
+ }
+ return ""
+}
+
+// SchemaFormat returns the OpenAPI format string for this parameter's schema (e.g. "byte", "date-time"),
+// or empty string if unavailable.
+func (pd *ParameterDefinition) SchemaFormat() string {
+ if pd.Spec.Schema != nil && pd.Spec.Schema.Value != nil {
+ return pd.Spec.Schema.Value.Format
+ }
+ return ""
+}
+
+// SanitizedParamName returns the parameter name sanitized to be a valid Go
+// identifier. This is needed for routers like net/http's ServeMux where path
+// wildcards (e.g. {name}) must be valid Go identifiers. For the original
+// OpenAPI parameter name (e.g. for error messages or JSON tags), use ParamName.
+func (pd ParameterDefinition) SanitizedParamName() string {
+ return SanitizeGoIdentifier(pd.ParamName)
+}
+
func (pd ParameterDefinition) GoVariableName() string {
- name := LowercaseFirstCharacter(pd.GoName())
+ name := LowercaseFirstCharacters(pd.GoName())
if IsGoKeyword(name) {
name = "p" + UppercaseFirstCharacter(name)
}
@@ -126,18 +212,25 @@ func (pd ParameterDefinition) GoVariableName() string {
func (pd ParameterDefinition) GoName() string {
goName := pd.ParamName
- if _, ok := pd.Spec.Extensions[extGoName]; ok {
- if extGoFieldName, err := extParseGoFieldName(pd.Spec.Extensions[extGoName]); err == nil {
+ if extension, ok := pd.Spec.Extensions[extGoName]; ok {
+ if extGoFieldName, err := extParseGoFieldName(extension); err == nil {
goName = extGoFieldName
}
}
return SchemaNameToTypeName(goName)
}
+// Deprecated: Use HasOptionalPointer, as it is clearer what the intent is.
func (pd ParameterDefinition) IndirectOptional() bool {
return !pd.Required && !pd.Schema.SkipOptionalPointer
}
+// HasOptionalPointer indicates whether the generated property has an optional pointer associated with it.
+// This takes into account the `x-go-type-skip-optional-pointer` extension, allowing a parameter definition to control whether the pointer should be skipped.
+func (pd ParameterDefinition) HasOptionalPointer() bool {
+ return !pd.Required && !pd.Schema.SkipOptionalPointer
+}
+
type ParameterDefinitions []ParameterDefinition
func (p ParameterDefinitions) FindByName(name string) *ParameterDefinition {
@@ -153,7 +246,7 @@ func (p ParameterDefinitions) FindByName(name string) *ParameterDefinition {
// descriptors into a flat list. This makes it a lot easier to traverse the
// data in the template engine.
func DescribeParameters(params openapi3.Parameters, path []string) ([]ParameterDefinition, error) {
- outParams := make([]ParameterDefinition, 0)
+ outParams := make([]ParameterDefinition, 0, len(params))
for _, paramOrRef := range params {
param := paramOrRef.Value
@@ -171,6 +264,17 @@ func DescribeParameters(params openapi3.Parameters, path []string) ([]ParameterD
Schema: goType,
}
+ // A parameter-level `x-go-type-skip-optional-pointer` overrides the
+ // schema-level setting. `GenStructFromSchema` applies the same override
+ // when rendering the params struct; without mirroring it here, the
+ // client/server templates disagree with the struct definition and emit
+ // a dereference (`*params.Field`) on a field declared without a pointer.
+ if extension, ok := param.Extensions[extPropGoTypeSkipOptionalPointer]; ok {
+ if skipOptionalPointer, err := extParsePropGoTypeSkipOptionalPointer(extension); err == nil {
+ pd.Schema.SkipOptionalPointer = skipOptionalPointer
+ }
+ }
+
// If this is a reference to a predefined type, simply use the reference
// name as the type. $ref: "#/components/schemas/custom_type" becomes
// "CustomType".
@@ -196,7 +300,7 @@ func DescribeSecurityDefinition(securityRequirements openapi3.SecurityRequiremen
outDefs := make([]SecurityDefinition, 0)
for _, sr := range securityRequirements {
- for _, k := range SortedSecurityRequirementKeys(sr) {
+ for _, k := range SortedMapKeys(sr) {
v := sr[k]
outDefs = append(outDefs, SecurityDefinition{ProviderName: k, Scopes: v})
}
@@ -205,9 +309,27 @@ func DescribeSecurityDefinition(securityRequirements openapi3.SecurityRequiremen
return outDefs
}
+// filterOutUndefinedSecuritySchemes drops any SecurityDefinition whose ProviderName
+// is not present in defined. A `security` requirement that references an
+// unknown scheme would otherwise produce a constant declaration and middleware
+// references against a context-key type that is never emitted (the type is
+// only generated for entries in components/securitySchemes).
+func filterOutUndefinedSecuritySchemes(defs []SecurityDefinition, defined map[string]struct{}) []SecurityDefinition {
+ out := make([]SecurityDefinition, 0, len(defs))
+ for _, d := range defs {
+ if _, ok := defined[d.ProviderName]; ok {
+ out = append(out, d)
+ }
+ }
+ return out
+}
+
// OperationDefinition describes an Operation
type OperationDefinition struct {
- OperationId string // The operation_id description from Swagger, used to generate function names
+ // OperationId is the `operationId` field from the OpenAPI Specification, after going through a `nameNormalizer`, and will be used to generate function names
+ OperationId string
+ // SpecOperationId is the raw `operationId` value as it appears in the OpenAPI spec, before normalization to a Go identifier. Empty when the spec didn't supply one (in which case the codegen-generated ID is the only available identifier and is exposed via OperationId).
+ SpecOperationId string
PathParams []ParameterDefinition // Parameters in the path, eg, /path/:param
HeaderParams []ParameterDefinition // Parameters in HTTP headers
@@ -222,6 +344,30 @@ type OperationDefinition struct {
Method string // GET, POST, DELETE, etc.
Path string // The Swagger path for the operation, like /resource/{id}
Spec *openapi3.Operation
+ IsAlias bool // True when this path is a $ref alias of another path item
+ AliasTarget string // When IsAlias is true, this is the OperationId of the canonical operation (for route registration to reference the correct wrapper)
+ PathItemRef string // The path item's $ref (if any); used to qualify externally-loaded schemas referenced from this operation's responses
+}
+
+// HandlerName returns the OperationId to use when referencing the server-side
+// wrapper function. For alias operations this is the canonical operation's ID,
+// since the alias doesn't generate its own wrapper.
+func (o *OperationDefinition) HandlerName() string {
+ if o.IsAlias {
+ return o.AliasTarget
+ }
+ return o.OperationId
+}
+
+// MiddlewareKey returns the identifier to use as the key in per-operation
+// middleware maps. The raw spec OperationId is preferred so map keys mirror
+// the OpenAPI spec verbatim; falls back to the normalized OperationId when
+// the spec didn't supply one.
+func (o *OperationDefinition) MiddlewareKey() string {
+ if o.SpecOperationId != "" {
+ return o.SpecOperationId
+ }
+ return o.OperationId
}
// Params returns the list of all parameters except Path parameters. Path parameters
@@ -274,69 +420,106 @@ func (o *OperationDefinition) SummaryAsComment() string {
func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefinition, error) {
var tds []ResponseTypeDefinition
- responses := o.Spec.Responses
- sortedResponsesKeys := SortedResponsesKeys(responses)
+ if o.Spec == nil || o.Spec.Responses == nil {
+ return tds, nil
+ }
+
+ sortedResponsesKeys := SortedMapKeys(o.Spec.Responses.Map())
for _, responseName := range sortedResponsesKeys {
- responseRef := responses[responseName]
+ responseRef := o.Spec.Responses.Value(responseName)
// We can only generate a type if we have a value:
if responseRef.Value != nil {
- jsonCount := 0
+ supportedCount := 0
for mediaType := range responseRef.Value.Content {
- if util.IsMediaTypeJson(mediaType) {
- jsonCount++
+ if isMediaTypeSupported(mediaType) {
+ supportedCount++
}
}
- sortedContentKeys := SortedContentKeys(responseRef.Value.Content)
+ sortedContentKeys := SortedMapKeys(responseRef.Value.Content)
for _, contentTypeName := range sortedContentKeys {
contentType := responseRef.Value.Content[contentTypeName]
// We can only generate a type if we have a schema:
if contentType.Schema != nil {
- responseSchema, err := GenerateGoSchema(contentType.Schema, []string{responseName})
- if err != nil {
- return nil, fmt.Errorf("Unable to determine Go type for %s.%s: %w", o.OperationId, contentTypeName, err)
- }
-
- var typeName string
+ var typeName, tag string
switch {
// HAL+JSON:
- case StringInArray(contentTypeName, contentTypesHalJSON):
- typeName = fmt.Sprintf("HALJSON%s", ToCamelCase(responseName))
- case "application/json" == contentTypeName:
+ case slices.Contains(contentTypesHalJSON, contentTypeName):
+ typeName = fmt.Sprintf("HALJSON%s", nameNormalizer(responseName))
+ tag = "HALJSON"
+ case contentTypeName == "application/json":
// if it's the standard application/json
- typeName = fmt.Sprintf("JSON%s", ToCamelCase(responseName))
+ typeName = fmt.Sprintf("JSON%s", nameNormalizer(responseName))
+ tag = "JSON"
// Vendored JSON
- case StringInArray(contentTypeName, contentTypesJSON) || util.IsMediaTypeJson(contentTypeName):
- baseTypeName := fmt.Sprintf("%s%s", ToCamelCase(contentTypeName), ToCamelCase(responseName))
+ case slices.Contains(contentTypesJSON, contentTypeName) || util.IsMediaTypeJson(contentTypeName):
+ baseTypeName := fmt.Sprintf("%s%s", nameNormalizer(contentTypeName), nameNormalizer(responseName))
typeName = strings.ReplaceAll(baseTypeName, "Json", "JSON")
+ tag = strings.ReplaceAll(nameNormalizer(contentTypeName), "Json", "JSON")
// YAML:
- case StringInArray(contentTypeName, contentTypesYAML):
- typeName = fmt.Sprintf("YAML%s", ToCamelCase(responseName))
+ case slices.Contains(contentTypesYAML, contentTypeName):
+ typeName = fmt.Sprintf("YAML%s", nameNormalizer(responseName))
+ tag = "YAML"
// XML:
- case StringInArray(contentTypeName, contentTypesXML):
- typeName = fmt.Sprintf("XML%s", ToCamelCase(responseName))
+ case slices.Contains(contentTypesXML, contentTypeName):
+ typeName = fmt.Sprintf("XML%s", nameNormalizer(responseName))
+ tag = "XML"
default:
continue
}
+ // Use the same body-type name as the server-side
+ // GenerateResponseDefinitions ("Body" suffixed so it
+ // doesn't collide with the strict envelope's struct
+ // wrapper) as the schema-path root. The canonical
+ // declaration happens server-side; here we just point
+ // RefType at the same name so the JSON field
+ // renders as a pointer to it.
+ responseBodyTypeName := o.OperationId + responseName + tag + "ResponseBody"
+ schemaPath := []string{responseBodyTypeName}
+ responseSchema, err := GenerateGoSchema(contentType.Schema, schemaPath)
+ if err != nil {
+ return nil, fmt.Errorf("unable to determine Go type for %s.%s: %w", o.OperationId, contentTypeName, err)
+ }
+
+ // Hoist inline response-root schemas that need
+ // method-emitting boilerplate (UnionElements /
+ // AdditionalProperties). For external path items,
+ // qualify with the imported package — see the
+ // equivalent block in GenerateResponseDefinitions for
+ // rationale.
+ if !IsGoTypeReference(responseRef.Ref) && responseSchema.RefType == "" &&
+ (len(responseSchema.UnionElements) != 0 || responseSchema.HasAdditionalProperties) {
+ if externalPkg := externalPackageFor(o.PathItemRef); externalPkg != "" {
+ responseSchema.RefType = fmt.Sprintf("%s.%s", externalPkg, responseBodyTypeName)
+ } else {
+ responseSchema.RefType = responseBodyTypeName
+ }
+ }
+
td := ResponseTypeDefinition{
TypeDefinition: TypeDefinition{
TypeName: typeName,
Schema: responseSchema,
},
- ResponseName: responseName,
- ContentTypeName: contentTypeName,
+ ResponseName: responseName,
+ ContentTypeName: contentTypeName,
+ AdditionalTypeDefinitions: responseSchema.GetAdditionalTypeDefs(),
}
if IsGoTypeReference(responseRef.Ref) {
refType, err := RefPathToGoType(responseRef.Ref)
if err != nil {
return nil, fmt.Errorf("error dereferencing response Ref: %w", err)
}
- if jsonCount > 1 && util.IsMediaTypeJson(contentTypeName) {
- refType += mediaTypeToCamelCase(contentTypeName)
+ if supportedCount > 1 {
+ if resolved := resolvedNameForRefPath(responseRef.Ref, contentTypeName); resolved != "" {
+ refType = resolved + mediaTypeToCamelCase(contentTypeName)
+ } else {
+ refType += mediaTypeToCamelCase(contentTypeName)
+ }
}
td.Schema.RefType = refType
}
@@ -348,13 +531,10 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini
return tds, nil
}
-func (o OperationDefinition) HasMaskedRequestContentTypes() bool {
- for _, body := range o.Bodies {
- if !body.IsFixedContentType() {
- return true
- }
- }
- return false
+func (o *OperationDefinition) HasMaskedRequestContentTypes() bool {
+ return slices.ContainsFunc(o.Bodies, func(body RequestBodyDefinition) bool {
+ return !body.IsFixedContentType()
+ })
}
// RequestBodyDefinition describes a request body
@@ -507,10 +687,57 @@ func (r ResponseContentDefinition) IsJSON() bool {
return util.IsMediaTypeJson(r.ContentType)
}
+// IsStreamingContentType reports whether this response's media type matches
+// any configured streaming-content-types pattern (defaults merged with
+// OutputOptions.StreamingContentTypes). Templates use this to emit a
+// flush-per-chunk streaming path instead of a buffered io.Copy.
+func (r ResponseContentDefinition) IsStreamingContentType() bool {
+ for _, re := range globalState.streamingContentTypeRegexes {
+ if re.MatchString(r.ContentType) {
+ return true
+ }
+ }
+ return false
+}
+
type ResponseHeaderDefinition struct {
- Name string
- GoName string
- Schema Schema
+ Name string
+ GoName string
+ Schema Schema
+ Required bool
+ Nullable bool
+}
+
+// GoTypeDef returns the Go type string for this header, applying pointer or
+// nullable wrapping based on the Required/Nullable fields and global config.
+func (h ResponseHeaderDefinition) GoTypeDef() string {
+ typeDef := h.Schema.TypeDecl()
+ if globalState.options.OutputOptions.NullableType && h.Nullable {
+ return "nullable.Nullable[" + typeDef + "]"
+ }
+ if !h.Schema.SkipOptionalPointer && (!h.Required || h.Nullable) {
+ typeDef = "*" + typeDef
+ }
+ return typeDef
+}
+
+// IsOptional returns true if this header's Go type is indirect (pointer or
+// nullable wrapper), meaning the template should guard before calling
+// w.Header().Set(). This must stay in sync with GoTypeDef().
+func (h ResponseHeaderDefinition) IsOptional() bool {
+ if h.IsNullable() {
+ return true
+ }
+ if h.Schema.SkipOptionalPointer {
+ return false
+ }
+ return !h.Required || h.Nullable
+}
+
+// IsNullable returns true if the header type uses nullable.Nullable[T]
+// rather than a pointer for optionality.
+func (h ResponseHeaderDefinition) IsNullable() bool {
+ return globalState.options.OutputOptions.NullableType && h.Nullable
}
// FilterParameterDefinitionByType returns the subset of the specified parameters which are of the
@@ -526,18 +753,29 @@ func FilterParameterDefinitionByType(params []ParameterDefinition, in string) []
}
// OperationDefinitions returns all operations for a swagger definition.
-func OperationDefinitions(swagger *openapi3.T, initialismOverrides bool) ([]OperationDefinition, error) {
+func OperationDefinitions(swagger *openapi3.T) ([]OperationDefinition, error) {
var operations []OperationDefinition
- var toCamelCaseFunc func(string) string
- if initialismOverrides {
- toCamelCaseFunc = ToCamelCaseWithInitialism
- } else {
- toCamelCaseFunc = ToCamelCase
+ if swagger == nil || swagger.Paths == nil {
+ return operations, nil
+ }
+
+ // Collect the names of security schemes actually defined under
+ // components/securitySchemes. Requirements that reference an undefined
+ // scheme are filtered out below so generated code stays compilable.
+ definedSecuritySchemes := map[string]struct{}{}
+ if swagger.Components != nil {
+ for name := range swagger.Components.SecuritySchemes {
+ definedSecuritySchemes[name] = struct{}{}
+ }
}
- for _, requestPath := range SortedPathsKeys(swagger.Paths) {
- pathItem := swagger.Paths[requestPath]
+ // Track alias counters for generating unique client method names
+ // when multiple paths $ref the same path item.
+ aliasCounters := map[string]int{}
+
+ for _, requestPath := range SortedMapKeys(swagger.Paths.Map()) {
+ pathItem := swagger.Paths.Value(requestPath)
// These are parameters defined for all methods on a given path. They
// are shared by all methods.
globalParams, err := DescribeParameters(pathItem.Parameters, nil)
@@ -548,26 +786,57 @@ func OperationDefinitions(swagger *openapi3.T, initialismOverrides bool) ([]Oper
// Each path can have a number of operations, POST, GET, OPTIONS, etc.
pathOps := pathItem.Operations()
- for _, opName := range SortedOperationsKeys(pathOps) {
+ for _, opName := range SortedMapKeys(pathOps) {
+ // NOTE that this is a reference to the existing copy of the Operation, so any modifications will modify our shared copy of the spec
op := pathOps[opName]
+
if pathItem.Servers != nil {
op.Servers = &pathItem.Servers
}
+ // take a copy of operationId, so we don't modify the underlying spec
+ operationId := op.OperationID
+ // Preserve the raw spec value (pre-normalization, pre-prefix, pre-alias-suffix)
+ // so templates that need to mirror the OpenAPI spec verbatim — e.g. echo's
+ // per-operation middleware map key — can do so without seeing the
+ // Go-identifier-friendly transformations applied below.
+ specOperationId := op.OperationID
// We rely on OperationID to generate function names, it's required
- if op.OperationID == "" {
- op.OperationID, err = generateDefaultOperationID(opName, requestPath, toCamelCaseFunc)
+ if operationId == "" {
+ operationId, err = generateDefaultOperationID(opName, requestPath)
if err != nil {
return nil, fmt.Errorf("error generating default OperationID for %s/%s: %s",
opName, requestPath, err)
}
} else {
- op.OperationID = toCamelCaseFunc(op.OperationID)
+ operationId = nameNormalizer(operationId)
+ }
+ operationId = typeNamePrefix(operationId) + operationId
+
+ // Detect path aliases: when a path item has an internal $ref
+ // pointing to another path in the same document (e.g.
+ // "#/paths/~1test"), it's a duplicate that would produce
+ // identical server methods. External $refs (pointing to other
+ // files) are not aliases — they're the sole definition of
+ // that path, just stored externally.
+ isAlias := strings.HasPrefix(pathItem.Ref, "#/paths/")
+ var aliasTarget string
+ if isAlias {
+ aliasTarget = nameNormalizer(operationId)
+ n := aliasCounters[operationId]
+ aliasCounters[operationId] = n + 1
+ operationId = operationId + fmt.Sprintf("Alias%d", n)
+ }
+
+ if !globalState.options.Compatibility.PreserveOriginalOperationIdCasingInEmbeddedSpec && !isAlias {
+ // update the existing, shared, copy of the spec if we're not wanting to preserve it.
+ // Skip for aliases: they share the same *Operation as the canonical path,
+ // and writing the suffixed name back would corrupt the original.
+ op.OperationID = operationId
}
- op.OperationID = typeNamePrefix(op.OperationID) + op.OperationID
// These are parameters defined for the specific path method that
// we're iterating over.
- localParams, err := DescribeParameters(op.Parameters, []string{op.OperationID + "Params"})
+ localParams, err := DescribeParameters(op.Parameters, []string{operationId + "Params"})
if err != nil {
return nil, fmt.Errorf("error describing global parameters for %s/%s: %s",
opName, requestPath, err)
@@ -579,6 +848,8 @@ func OperationDefinitions(swagger *openapi3.T, initialismOverrides bool) ([]Oper
return nil, err
}
+ ensureExternalRefsInParameterDefinitions(&allParams, pathItem.Ref)
+
// Order the path parameters to match the order as specified in
// the path, not in the swagger spec, and validate that the parameter
// names match, as downstream code depends on that.
@@ -588,22 +859,27 @@ func OperationDefinitions(swagger *openapi3.T, initialismOverrides bool) ([]Oper
return nil, err
}
- bodyDefinitions, typeDefinitions, err := GenerateBodyDefinitions(op.OperationID, op.RequestBody)
+ bodyDefinitions, typeDefinitions, err := GenerateBodyDefinitions(operationId, op.RequestBody, pathItem.Ref)
if err != nil {
return nil, fmt.Errorf("error generating body definitions: %w", err)
}
- responseDefinitions, err := GenerateResponseDefinitions(op.OperationID, op.Responses)
+ ensureExternalRefsInRequestBodyDefinitions(&bodyDefinitions, pathItem.Ref)
+
+ responseDefinitions, err := GenerateResponseDefinitions(operationId, op.Responses.Map(), pathItem.Ref)
if err != nil {
return nil, fmt.Errorf("error generating response definitions: %w", err)
}
+ ensureExternalRefsInResponseDefinitions(&responseDefinitions, pathItem.Ref)
+
opDef := OperationDefinition{
- PathParams: pathParams,
- HeaderParams: FilterParameterDefinitionByType(allParams, "header"),
- QueryParams: FilterParameterDefinitionByType(allParams, "query"),
- CookieParams: FilterParameterDefinitionByType(allParams, "cookie"),
- OperationId: toCamelCaseFunc(op.OperationID),
+ PathParams: pathParams,
+ HeaderParams: FilterParameterDefinitionByType(allParams, "header"),
+ QueryParams: FilterParameterDefinitionByType(allParams, "query"),
+ CookieParams: FilterParameterDefinitionByType(allParams, "cookie"),
+ OperationId: nameNormalizer(operationId),
+ SpecOperationId: specOperationId,
// Replace newlines in summary.
Summary: op.Summary,
Method: opName,
@@ -612,6 +888,9 @@ func OperationDefinitions(swagger *openapi3.T, initialismOverrides bool) ([]Oper
Bodies: bodyDefinitions,
Responses: responseDefinitions,
TypeDefinitions: typeDefinitions,
+ IsAlias: isAlias,
+ AliasTarget: aliasTarget,
+ PathItemRef: pathItem.Ref,
}
// check for overrides of SecurityDefinitions.
@@ -627,6 +906,7 @@ func OperationDefinitions(swagger *openapi3.T, initialismOverrides bool) ([]Oper
opDef.SecurityDefinitions = DescribeSecurityDefinition(swagger.Security)
}
+ opDef.SecurityDefinitions = filterOutUndefinedSecuritySchemes(opDef.SecurityDefinitions, definedSecuritySchemes)
if op.RequestBody != nil {
opDef.BodyRequired = op.RequestBody.Value.Required
@@ -641,29 +921,34 @@ func OperationDefinitions(swagger *openapi3.T, initialismOverrides bool) ([]Oper
return operations, nil
}
-func generateDefaultOperationID(opName string, requestPath string, toCamelCaseFunc func(string) string) (string, error) {
- var operationId = strings.ToLower(opName)
-
+func generateDefaultOperationID(opName string, requestPath string) (string, error) {
if opName == "" {
return "", fmt.Errorf("operation name cannot be an empty string")
}
-
if requestPath == "" {
return "", fmt.Errorf("request path cannot be an empty string")
}
- for _, part := range strings.Split(requestPath, "/") {
+ operationID := strings.ToLower(opName)
+ for part := range strings.SplitSeq(requestPath, "/") {
if part != "" {
- operationId = operationId + "-" + part
+ operationID = operationID + "-" + part
}
}
- return toCamelCaseFunc(operationId), nil
+ return nameNormalizer(operationID), nil
}
// GenerateBodyDefinitions turns the Swagger body definitions into a list of our body
// definitions which will be used for code generation.
-func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBodyRef) ([]RequestBodyDefinition, []TypeDefinition, error) {
+//
+// pathItemRef is the path item's $ref (if any). When non-empty and pointing at
+// an external file, the body type that would otherwise be hoisted locally is
+// replaced by a reference to the imported package's same-named type — the
+// imported package already declares it (with any As/From/Merge methods), so
+// redeclaring locally would just produce an awkward duplicate with
+// package-qualified union elements.
+func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBodyRef, pathItemRef string) ([]RequestBodyDefinition, []TypeDefinition, error) {
if bodyOrRef == nil {
return nil, nil, nil
}
@@ -672,7 +957,7 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody
var bodyDefinitions []RequestBodyDefinition
var typeDefinitions []TypeDefinition
- for _, contentType := range SortedContentKeys(body.Content) {
+ for _, contentType := range SortedMapKeys(body.Content) {
content := body.Content[contentType]
var tag string
var defaultBody bool
@@ -718,24 +1003,31 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody
// type under #/components, we'll define a type for it, so
// that we have an easy to use type for marshaling.
if bodySchema.RefType == "" {
- if contentType == "application/x-www-form-urlencoded" {
- // Apply the appropriate structure tag if the request
- // schema was defined under the operations' section.
- for i := range bodySchema.Properties {
- bodySchema.Properties[i].NeedsFormTag = true
- }
+ if externalPkg := externalPackageFor(pathItemRef); externalPkg != "" {
+ // The operation's path item came from an external file; the
+ // imported package already declares this body type with the
+ // matching name. Reference it instead of redeclaring.
+ bodySchema.RefType = fmt.Sprintf("%s.%s", externalPkg, bodyTypeName)
+ } else {
+ if contentType == "application/x-www-form-urlencoded" {
+ // Apply the appropriate structure tag if the request
+ // schema was defined under the operations' section.
+ for i := range bodySchema.Properties {
+ bodySchema.Properties[i].NeedsFormTag = true
+ }
- // Regenerate the Golang struct adding the new form tag.
- bodySchema.GoType = GenStructFromSchema(bodySchema)
- }
+ // Regenerate the Golang struct adding the new form tag.
+ bodySchema.GoType = GenStructFromSchema(bodySchema)
+ }
- td := TypeDefinition{
- TypeName: bodyTypeName,
- Schema: bodySchema,
+ td := TypeDefinition{
+ TypeName: bodyTypeName,
+ Schema: bodySchema,
+ }
+ typeDefinitions = append(typeDefinitions, td)
+ // The body schema now is a reference to a type
+ bodySchema.RefType = bodyTypeName
}
- typeDefinitions = append(typeDefinitions, td)
- // The body schema now is a reference to a type
- bodySchema.RefType = bodyTypeName
}
bd := RequestBodyDefinition{
@@ -747,7 +1039,7 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody
}
if len(content.Encoding) != 0 {
- bd.Encoding = make(map[string]RequestBodyEncoding)
+ bd.Encoding = make(map[string]RequestBodyEncoding, len(content.Encoding))
for k, v := range content.Encoding {
encoding := RequestBodyEncoding{ContentType: v.ContentType, Style: v.Style, Explode: v.Explode}
bd.Encoding[k] = encoding
@@ -756,18 +1048,20 @@ func GenerateBodyDefinitions(operationID string, bodyOrRef *openapi3.RequestBody
bodyDefinitions = append(bodyDefinitions, bd)
}
- sort.Slice(bodyDefinitions, func(i, j int) bool {
- return bodyDefinitions[i].ContentType < bodyDefinitions[j].ContentType
+ slices.SortFunc(bodyDefinitions, func(a, b RequestBodyDefinition) int {
+ return cmp.Compare(a.ContentType, b.ContentType)
})
return bodyDefinitions, typeDefinitions, nil
}
-func GenerateResponseDefinitions(operationID string, responses openapi3.Responses) ([]ResponseDefinition, error) {
+func GenerateResponseDefinitions(operationID string, responses map[string]*openapi3.ResponseRef, pathItemRef string) ([]ResponseDefinition, error) {
+ externalPkg := externalPackageFor(pathItemRef)
+
var responseDefinitions []ResponseDefinition
// do not let multiple status codes ref to same response, it will break the type switch
refSet := make(map[string]struct{})
- for _, statusCode := range SortedResponsesKeys(responses) {
+ for _, statusCode := range SortedMapKeys(responses) {
responseOrRef := responses[statusCode]
if responseOrRef == nil {
continue
@@ -776,7 +1070,7 @@ func GenerateResponseDefinitions(operationID string, responses openapi3.Response
var responseContentDefinitions []ResponseContentDefinition
- for _, contentType := range SortedContentKeys(response.Content) {
+ for _, contentType := range SortedMapKeys(response.Content) {
content := response.Content[contentType]
var tag string
switch {
@@ -799,27 +1093,68 @@ func GenerateResponseDefinitions(operationID string, responses openapi3.Response
}
responseTypeName := operationID + statusCode + tag + "Response"
- contentSchema, err := GenerateGoSchema(content.Schema, []string{responseTypeName})
+ // The strict-server envelope keeps the bare ...Response name
+ // (e.g. "GetPing200JSONResponse"); the hoisted body type is
+ // suffixed so the envelope can reference it without colliding
+ // (the strict envelope is sometimes a struct that wraps the
+ // body in a Body field, which would self-reference if the
+ // names matched).
+ responseBodyTypeName := responseTypeName + "Body"
+ contentSchema, err := GenerateGoSchema(content.Schema, []string{responseBodyTypeName})
if err != nil {
return nil, fmt.Errorf("error generating request body definition: %w", err)
}
+ // Hoist inline response-root schemas that need method-emitting
+ // boilerplate (UnionElements / AdditionalProperties) to a
+ // synthetic top-level TypeDefinition. The hoisted typedef flows
+ // via op.TypeDefinitions (collected in
+ // GenerateTypeDefsForOperation) and gets declared once via
+ // typedef.tmpl with full union/additionalProperties methods.
+ // The strict-server template references it as the body type
+ // from the envelope.
+ //
+ // When the operation came from an externally-ref'd path item,
+ // the imported package generated the same hoisted name, so we
+ // reference it instead of redeclaring locally.
+ if !IsGoTypeReference(responseOrRef.Ref) && contentSchema.RefType == "" &&
+ (len(contentSchema.UnionElements) != 0 || contentSchema.HasAdditionalProperties) {
+ if externalPkg != "" {
+ contentSchema.RefType = fmt.Sprintf("%s.%s", externalPkg, responseBodyTypeName)
+ } else {
+ contentSchema.AdditionalTypes = append(contentSchema.AdditionalTypes, TypeDefinition{
+ TypeName: responseBodyTypeName,
+ JsonName: responseBodyTypeName,
+ Schema: contentSchema,
+ })
+ contentSchema.RefType = responseBodyTypeName
+ }
+ }
+
rcd := ResponseContentDefinition{
ContentType: contentType,
NameTag: tag,
Schema: contentSchema,
}
+
responseContentDefinitions = append(responseContentDefinitions, rcd)
}
var responseHeaderDefinitions []ResponseHeaderDefinition
- for _, headerName := range SortedHeadersKeys(response.Headers) {
+ for _, headerName := range SortedMapKeys(response.Headers) {
header := response.Headers[headerName]
contentSchema, err := GenerateGoSchema(header.Value.Schema, []string{})
if err != nil {
return nil, fmt.Errorf("error generating response header definition: %w", err)
}
- headerDefinition := ResponseHeaderDefinition{Name: headerName, GoName: SchemaNameToTypeName(headerName), Schema: contentSchema}
+ nullable := header.Value.Schema != nil && header.Value.Schema.Value != nil && header.Value.Schema.Value.Nullable
+ headerDefinition := ResponseHeaderDefinition{
+ Name: headerName,
+ GoName: SchemaNameToTypeName(headerName),
+ Schema: contentSchema,
+ Required: header.Value.Required || globalState.options.Compatibility.HeadersImplicitlyRequired,
+ Nullable: nullable,
+ }
responseHeaderDefinitions = append(responseHeaderDefinitions, headerDefinition)
}
@@ -844,6 +1179,12 @@ func GenerateResponseDefinitions(operationID string, responses openapi3.Response
rd.Ref = refType
refSet[refType] = struct{}{}
}
+ // Ensure content schemas get the external ref qualifier so that
+ // non-fixed status code paths (e.g. "default") emit the qualified type.
+ for i, rcd := range rd.Contents {
+ ensureExternalRefsInSchema(&rcd.Schema, responseOrRef.Ref)
+ rd.Contents[i] = rcd
+ }
}
responseDefinitions = append(responseDefinitions, rd)
}
@@ -860,11 +1201,17 @@ func GenerateTypeDefsForOperation(op OperationDefinition) []TypeDefinition {
// Now, go through all the additional types we need to declare.
for _, param := range op.AllParams() {
- typeDefs = append(typeDefs, param.Schema.GetAdditionalTypeDefs()...)
+ typeDefs = append(typeDefs, param.Schema.AdditionalTypes...)
}
for _, body := range op.Bodies {
- typeDefs = append(typeDefs, body.Schema.GetAdditionalTypeDefs()...)
+ typeDefs = append(typeDefs, body.Schema.AdditionalTypes...)
+ }
+
+ for _, resp := range op.Responses {
+ for _, content := range resp.Contents {
+ typeDefs = append(typeDefs, content.Schema.AdditionalTypes...)
+ }
}
return typeDefs
}
@@ -892,18 +1239,27 @@ func GenerateParamsTypes(op OperationDefinition) []TypeDefinition {
Schema: param.Schema,
})
}
+ // Merge extensions, in order of increasing precedence:
+ // 1. extensions on the referenced schema (param.Spec.Schema.Value)
+ // 2. extensions placed as siblings of a $ref inside the
+ // parameter's schema (param.Spec.Schema.Extensions)
+ // 3. extensions on the Parameter object itself
+ extensions := make(map[string]any)
+ if param.Spec.Schema != nil {
+ maps.Copy(extensions, combinedSchemaExtensions(param.Spec.Schema))
+ }
+ maps.Copy(extensions, param.Spec.Extensions)
prop := Property{
Description: param.Spec.Description,
JsonFieldName: param.ParamName,
Required: param.Required,
Schema: pSchema,
NeedsFormTag: param.Style() == "form",
- Extensions: param.Spec.Extensions,
+ Extensions: extensions,
}
s.Properties = append(s.Properties, prop)
}
- s.Description = op.Spec.Description
s.GoType = GenStructFromSchema(s)
td := TypeDefinition{
@@ -926,25 +1282,6 @@ func GenerateTypesForOperations(t *template.Template, ops []OperationDefinition)
return "", fmt.Errorf("error writing boilerplate to buffer: %w", err)
}
- // Generate boiler plate for all additional types.
- var td []TypeDefinition
- for _, op := range ops {
- td = append(td, op.TypeDefinitions...)
- }
-
- addProps, err := GenerateAdditionalPropertyBoilerplate(t, td)
- if err != nil {
- return "", fmt.Errorf("error generating additional properties boilerplate for operations: %w", err)
- }
-
- if _, err := w.WriteString("\n"); err != nil {
- return "", fmt.Errorf("error generating additional properties boilerplate for operations: %w", err)
- }
-
- if _, err := w.WriteString(addProps); err != nil {
- return "", fmt.Errorf("error generating additional properties boilerplate for operations: %w", err)
- }
-
if err = w.Flush(); err != nil {
return "", fmt.Errorf("error flushing output buffer for server interface: %w", err)
}
@@ -976,6 +1313,12 @@ func GenerateEchoServer(t *template.Template, operations []OperationDefinition)
return GenerateTemplates([]string{"echo/echo-interface.tmpl", "echo/echo-wrappers.tmpl", "echo/echo-register.tmpl"}, t, operations)
}
+// GenerateEcho5Server generates all the go code for the ServerInterface as well as
+// all the wrapper functions around our handlers.
+func GenerateEcho5Server(t *template.Template, operations []OperationDefinition) (string, error) {
+ return GenerateTemplates([]string{"echo/v5/echo-interface.tmpl", "echo/v5/echo-wrappers.tmpl", "echo/v5/echo-register.tmpl"}, t, operations)
+}
+
// GenerateGinServer generates all the go code for the ServerInterface as well as
// all the wrapper functions around our handlers.
func GenerateGinServer(t *template.Template, operations []OperationDefinition) (string, error) {
@@ -988,11 +1331,17 @@ func GenerateGorillaServer(t *template.Template, operations []OperationDefinitio
return GenerateTemplates([]string{"gorilla/gorilla-interface.tmpl", "gorilla/gorilla-middleware.tmpl", "gorilla/gorilla-register.tmpl"}, t, operations)
}
+// GenerateStdHTTPServer generates all the go code for the ServerInterface as well as
+// all the wrapper functions around our handlers.
+func GenerateStdHTTPServer(t *template.Template, operations []OperationDefinition) (string, error) {
+ return GenerateTemplates([]string{"stdhttp/std-http-interface.tmpl", "stdhttp/std-http-middleware.tmpl", "stdhttp/std-http-handler.tmpl"}, t, operations)
+}
+
func GenerateStrictServer(t *template.Template, operations []OperationDefinition, opts Configuration) (string, error) {
var templates []string
- if opts.Generate.ChiServer || opts.Generate.GorillaServer {
+ if opts.Generate.ChiServer || opts.Generate.GorillaServer || opts.Generate.StdHTTPServer {
templates = append(templates, "strict/strict-interface.tmpl", "strict/strict-http.tmpl")
}
if opts.Generate.EchoServer {
@@ -1007,6 +1356,9 @@ func GenerateStrictServer(t *template.Template, operations []OperationDefinition
if opts.Generate.IrisServer {
templates = append(templates, "strict/strict-iris-interface.tmpl", "strict/strict-iris.tmpl")
}
+ if opts.Generate.Echo5Server {
+ templates = append(templates, "strict/strict-interface.tmpl", "strict/strict-echo5.tmpl")
+ }
return GenerateTemplates(templates, t, operations)
}
@@ -1028,7 +1380,7 @@ func GenerateClientWithResponses(t *template.Template, ops []OperationDefinition
}
// GenerateTemplates used to generate templates
-func GenerateTemplates(templates []string, t *template.Template, ops interface{}) (string, error) {
+func GenerateTemplates(templates []string, t *template.Template, ops any) (string, error) {
var generatedTemplates []string
for _, tmpl := range templates {
var buf bytes.Buffer
diff --git a/pkg/codegen/operations_test.go b/pkg/codegen/operations_test.go
index 77a54a8c25..fae988bbf6 100644
--- a/pkg/codegen/operations_test.go
+++ b/pkg/codegen/operations_test.go
@@ -18,6 +18,7 @@ import (
"testing"
"github.com/getkin/kin-openapi/openapi3"
+ "github.com/stretchr/testify/assert"
)
func TestIsJson(t *testing.T) {
@@ -131,7 +132,7 @@ func TestGenerateDefaultOperationID(t *testing.T) {
}
for _, test := range suite {
- got, err := generateDefaultOperationID(test.op, test.path, ToCamelCase)
+ got, err := generateDefaultOperationID(test.op, test.path)
if err != nil {
if !test.wantErr {
t.Fatalf("did not expected error but got %v", err)
@@ -146,3 +147,84 @@ func TestGenerateDefaultOperationID(t *testing.T) {
}
}
}
+
+func TestJsonTag(t *testing.T) {
+ t.Run("required param with no extra tags", func(t *testing.T) {
+ pd := ParameterDefinition{
+ ParamName: "foo",
+ Required: true,
+ Spec: &openapi3.Parameter{},
+ }
+ assert.Equal(t, "`json:\"foo\"`", pd.JsonTag())
+ })
+
+ t.Run("optional param with no extra tags", func(t *testing.T) {
+ pd := ParameterDefinition{
+ ParamName: "foo",
+ Required: false,
+ Spec: &openapi3.Parameter{},
+ }
+ assert.Equal(t, "`json:\"foo,omitempty\"`", pd.JsonTag())
+ })
+
+ t.Run("extra tags at parameter level", func(t *testing.T) {
+ pd := ParameterDefinition{
+ ParamName: "foo",
+ Required: true,
+ Spec: &openapi3.Parameter{
+ Extensions: map[string]any{
+ "x-oapi-codegen-extra-tags": map[string]any{
+ "validate": "required",
+ "db": "foo_col",
+ },
+ },
+ },
+ }
+ assert.Equal(t, "`db:\"foo_col\" json:\"foo\" validate:\"required\"`", pd.JsonTag())
+ })
+
+ t.Run("extra tags at schema level", func(t *testing.T) {
+ pd := ParameterDefinition{
+ ParamName: "foo",
+ Required: true,
+ Spec: &openapi3.Parameter{
+ Schema: &openapi3.SchemaRef{
+ Value: &openapi3.Schema{
+ Extensions: map[string]any{
+ "x-oapi-codegen-extra-tags": map[string]any{
+ "validate": "required",
+ },
+ },
+ },
+ },
+ },
+ }
+ assert.Equal(t, "`json:\"foo\" validate:\"required\"`", pd.JsonTag())
+ })
+
+ t.Run("parameter level takes precedence over schema level", func(t *testing.T) {
+ pd := ParameterDefinition{
+ ParamName: "foo",
+ Required: true,
+ Spec: &openapi3.Parameter{
+ Extensions: map[string]any{
+ "x-oapi-codegen-extra-tags": map[string]any{
+ "validate": "param-level",
+ },
+ },
+ Schema: &openapi3.SchemaRef{
+ Value: &openapi3.Schema{
+ Extensions: map[string]any{
+ "x-oapi-codegen-extra-tags": map[string]any{
+ "validate": "schema-level",
+ "db": "foo_col",
+ },
+ },
+ },
+ },
+ },
+ }
+ // Parameter-level "validate" wins, schema-level "db" is kept
+ assert.Equal(t, "`db:\"foo_col\" json:\"foo\" validate:\"param-level\"`", pd.JsonTag())
+ })
+}
diff --git a/pkg/codegen/prune.go b/pkg/codegen/prune.go
index 9dc4fd8719..efdac65f0b 100644
--- a/pkg/codegen/prune.go
+++ b/pkg/codegen/prune.go
@@ -2,31 +2,23 @@ package codegen
import (
"fmt"
+ "slices"
"github.com/getkin/kin-openapi/openapi3"
)
-func stringInSlice(a string, list []string) bool {
- for _, b := range list {
- if b == a {
- return true
- }
- }
- return false
-}
-
type RefWrapper struct {
Ref string
HasValue bool
- SourceRef interface{}
+ SourceRef any
}
func walkSwagger(swagger *openapi3.T, doFn func(RefWrapper) (bool, error)) error {
- if swagger == nil {
+ if swagger == nil || swagger.Paths == nil {
return nil
}
- for _, p := range swagger.Paths {
+ for _, p := range swagger.Paths.Map() {
for _, param := range p.Parameters {
_ = walkParameterRef(param, doFn)
}
@@ -52,8 +44,10 @@ func walkOperation(op *openapi3.Operation, doFn func(RefWrapper) (bool, error))
_ = walkRequestBodyRef(op.RequestBody, doFn)
- for _, response := range op.Responses {
- _ = walkResponseRef(response, doFn)
+ if op.Responses != nil {
+ for _, response := range op.Responses.Map() {
+ _ = walkResponseRef(response, doFn)
+ }
}
for _, callback := range op.Callbacks {
@@ -273,7 +267,7 @@ func walkCallbackRef(ref *openapi3.CallbackRef, doFn func(RefWrapper) (bool, err
return nil
}
- for _, pathItem := range *ref.Value {
+ for _, pathItem := range ref.Value.Map() {
for _, parameter := range pathItem.Parameters {
_ = walkParameterRef(parameter, doFn)
}
@@ -400,7 +394,7 @@ func removeOrphanedComponents(swagger *openapi3.T, refs []string) int {
for key := range swagger.Components.Schemas {
ref := fmt.Sprintf("#/components/schemas/%s", key)
- if !stringInSlice(ref, refs) {
+ if !slices.Contains(refs, ref) {
countRemoved++
delete(swagger.Components.Schemas, key)
}
@@ -408,7 +402,7 @@ func removeOrphanedComponents(swagger *openapi3.T, refs []string) int {
for key := range swagger.Components.Parameters {
ref := fmt.Sprintf("#/components/parameters/%s", key)
- if !stringInSlice(ref, refs) {
+ if !slices.Contains(refs, ref) {
countRemoved++
delete(swagger.Components.Parameters, key)
}
@@ -419,7 +413,7 @@ func removeOrphanedComponents(swagger *openapi3.T, refs []string) int {
// for key, _ := range swagger.Components.SecuritySchemes {
// ref := fmt.Sprintf("#/components/securitySchemes/%s", key)
- // if !stringInSlice(ref, refs) {
+ // if !slices.Contains(refs, ref) {
// countRemoved++
// delete(swagger.Components.SecuritySchemes, key)
// }
@@ -427,7 +421,7 @@ func removeOrphanedComponents(swagger *openapi3.T, refs []string) int {
for key := range swagger.Components.RequestBodies {
ref := fmt.Sprintf("#/components/requestBodies/%s", key)
- if !stringInSlice(ref, refs) {
+ if !slices.Contains(refs, ref) {
countRemoved++
delete(swagger.Components.RequestBodies, key)
}
@@ -435,7 +429,7 @@ func removeOrphanedComponents(swagger *openapi3.T, refs []string) int {
for key := range swagger.Components.Responses {
ref := fmt.Sprintf("#/components/responses/%s", key)
- if !stringInSlice(ref, refs) {
+ if !slices.Contains(refs, ref) {
countRemoved++
delete(swagger.Components.Responses, key)
}
@@ -443,7 +437,7 @@ func removeOrphanedComponents(swagger *openapi3.T, refs []string) int {
for key := range swagger.Components.Headers {
ref := fmt.Sprintf("#/components/headers/%s", key)
- if !stringInSlice(ref, refs) {
+ if !slices.Contains(refs, ref) {
countRemoved++
delete(swagger.Components.Headers, key)
}
@@ -451,7 +445,7 @@ func removeOrphanedComponents(swagger *openapi3.T, refs []string) int {
for key := range swagger.Components.Examples {
ref := fmt.Sprintf("#/components/examples/%s", key)
- if !stringInSlice(ref, refs) {
+ if !slices.Contains(refs, ref) {
countRemoved++
delete(swagger.Components.Examples, key)
}
@@ -459,7 +453,7 @@ func removeOrphanedComponents(swagger *openapi3.T, refs []string) int {
for key := range swagger.Components.Links {
ref := fmt.Sprintf("#/components/links/%s", key)
- if !stringInSlice(ref, refs) {
+ if !slices.Contains(refs, ref) {
countRemoved++
delete(swagger.Components.Links, key)
}
@@ -467,7 +461,7 @@ func removeOrphanedComponents(swagger *openapi3.T, refs []string) int {
for key := range swagger.Components.Callbacks {
ref := fmt.Sprintf("#/components/callbacks/%s", key)
- if !stringInSlice(ref, refs) {
+ if !slices.Contains(refs, ref) {
countRemoved++
delete(swagger.Components.Callbacks, key)
}
diff --git a/pkg/codegen/prune_test.go b/pkg/codegen/prune_test.go
index e0cc16c08a..9972f5bac7 100644
--- a/pkg/codegen/prune_test.go
+++ b/pkg/codegen/prune_test.go
@@ -67,9 +67,9 @@ func TestFilterOnlyCat(t *testing.T) {
refs = findComponentRefs(swagger)
assert.Len(t, refs, 7)
- assert.NotEmpty(t, swagger.Paths["/cat"], "/cat path should still be in spec")
- assert.NotEmpty(t, swagger.Paths["/cat"].Get, "GET /cat operation should still be in spec")
- assert.Empty(t, swagger.Paths["/dog"].Get, "GET /dog should have been removed from spec")
+ assert.NotEmpty(t, swagger.Paths.Value("/cat"), "/cat path should still be in spec")
+ assert.NotEmpty(t, swagger.Paths.Value("/cat").Get, "GET /cat operation should still be in spec")
+ assert.Empty(t, swagger.Paths.Value("/dog").Get, "GET /dog should have been removed from spec")
pruneUnusedComponents(swagger)
@@ -97,9 +97,9 @@ func TestFilterOnlyDog(t *testing.T) {
assert.Len(t, swagger.Components.Schemas, 5)
- assert.NotEmpty(t, swagger.Paths["/dog"])
- assert.NotEmpty(t, swagger.Paths["/dog"].Get)
- assert.Empty(t, swagger.Paths["/cat"].Get)
+ assert.NotEmpty(t, swagger.Paths.Value("/dog"))
+ assert.NotEmpty(t, swagger.Paths.Value("/dog").Get)
+ assert.Empty(t, swagger.Paths.Value("/cat").Get)
pruneUnusedComponents(swagger)
diff --git a/pkg/codegen/resolve_names.go b/pkg/codegen/resolve_names.go
new file mode 100644
index 0000000000..1695d67f35
--- /dev/null
+++ b/pkg/codegen/resolve_names.go
@@ -0,0 +1,339 @@
+package codegen
+
+import (
+ "fmt"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+// ResolvedName holds the final Go type name assigned to a gathered schema.
+type ResolvedName struct {
+ Schema *GatheredSchema
+ GoName string // The resolved Go type name
+ Candidate string // The initial candidate name before collision resolution
+ Pinned bool // True if name came from x-go-name; must not be renamed
+}
+
+// ResolveNames takes the gathered schemas and assigns unique Go type names to each.
+// It returns a map from the schema's path string to the resolved Go type name.
+func ResolveNames(schemas []*GatheredSchema) map[string]string {
+ // Step 1: Generate candidate names for all schemas
+ candidates := make([]*ResolvedName, len(schemas))
+ for i, s := range schemas {
+ candidate := generateCandidateName(s)
+ candidates[i] = &ResolvedName{
+ Schema: s,
+ GoName: candidate,
+ Candidate: candidate,
+ Pinned: s.GoNameOverride != "",
+ }
+ }
+
+ // Step 2: Resolve collisions iteratively
+ resolveCollisions(candidates)
+
+ // Step 3: Build the result map
+ result := make(map[string]string, len(candidates))
+ for _, c := range candidates {
+ result[c.Schema.Path.String()] = c.GoName
+ }
+ return result
+}
+
+// generateCandidateName produces an initial Go type name candidate based on
+// the schema's location and context in the OpenAPI document.
+func generateCandidateName(s *GatheredSchema) string {
+ if s.GoNameOverride != "" {
+ return s.GoNameOverride
+ }
+
+ switch s.Context {
+ case ContextComponentSchema:
+ return SchemaNameToTypeName(s.ComponentName)
+
+ case ContextComponentParameter:
+ return SchemaNameToTypeName(s.ComponentName)
+
+ case ContextComponentResponse:
+ return SchemaNameToTypeName(s.ComponentName)
+
+ case ContextComponentRequestBody:
+ return SchemaNameToTypeName(s.ComponentName)
+
+ case ContextComponentHeader:
+ return SchemaNameToTypeName(s.ComponentName)
+
+ case ContextClientResponseWrapper:
+ // Client response wrappers use: OperationId + responseTypeSuffix
+ return fmt.Sprintf("%s%s", SchemaNameToTypeName(s.OperationID), responseTypeSuffix)
+
+ case ContextOperationParameter:
+ if s.OperationID != "" {
+ return SchemaNameToTypeName(s.OperationID) + "Parameter"
+ }
+ return SchemaNameToTypeName(s.ComponentName) + "Parameter"
+
+ case ContextOperationRequestBody:
+ if s.OperationID != "" {
+ ct := contentTypeSuffix(s.ContentType)
+ return SchemaNameToTypeName(s.OperationID) + ct + "Request"
+ }
+ return SchemaNameToTypeName(s.ComponentName) + "Request"
+
+ case ContextOperationResponse:
+ if s.OperationID != "" {
+ ct := contentTypeSuffix(s.ContentType)
+ return SchemaNameToTypeName(s.OperationID) + s.StatusCode + ct + "Response"
+ }
+ return SchemaNameToTypeName(s.ComponentName) + "Response"
+
+ default:
+ return SchemaNameToTypeName(s.ComponentName)
+ }
+}
+
+// resolveCollisions detects and resolves naming collisions among the resolved names.
+// It applies strategies in global phases of increasing aggressiveness:
+// 1. Context suffix (Schema, Parameter, Response, etc.)
+// 2. Per-schema disambiguation (content type, status code, etc.)
+// 3. Numeric fallback
+//
+// Each strategy is applied to ALL colliding groups, then collisions are
+// re-checked globally before moving to the next strategy. This prevents
+// oscillation between strategies (e.g., context suffix and content type
+// suffix repeatedly appending to the same names without resolution).
+func resolveCollisions(names []*ResolvedName) {
+ strategies := []func([]*ResolvedName) bool{
+ strategyContextSuffix,
+ strategyPerSchemaDisambiguate,
+ strategyNumericFallback,
+ }
+
+ const maxIterations = 20
+
+ for _, strategy := range strategies {
+ for range maxIterations {
+ groups := groupByName(names)
+ anyCollision := false
+ anyProgress := false
+ for _, group := range groups {
+ if len(group) <= 1 {
+ continue
+ }
+ anyCollision = true
+ if strategy(group) {
+ anyProgress = true
+ }
+ }
+ if !anyCollision {
+ return
+ }
+ if !anyProgress {
+ break // This strategy can't help; try the next one
+ }
+ }
+ }
+}
+
+// groupByName groups ResolvedNames by their current GoName.
+func groupByName(names []*ResolvedName) map[string][]*ResolvedName {
+ groups := make(map[string][]*ResolvedName)
+ for _, n := range names {
+ groups[n.GoName] = append(groups[n.GoName], n)
+ }
+ return groups
+}
+
+// strategyContextSuffix attempts to resolve collisions by appending a suffix
+// derived from the schema's context (Schema, Parameter, Response, etc.).
+// Component schemas are "privileged" — if exactly one member is a component
+// schema, it keeps the bare name and only the others get suffixed.
+// Returns true if any name was modified, false if no progress was made.
+func strategyContextSuffix(group []*ResolvedName) bool {
+ // Count how many are component schemas (privileged)
+ var componentSchemaCount int
+ for _, n := range group {
+ if n.Schema.IsComponentSchema() {
+ componentSchemaCount++
+ }
+ }
+
+ progress := false
+ for _, n := range group {
+ if n.Pinned {
+ continue
+ }
+
+ suffix := n.Schema.Context.Suffix()
+ if suffix == "" {
+ continue
+ }
+
+ // If exactly one is a component schema, it keeps the bare name
+ if componentSchemaCount == 1 && n.Schema.IsComponentSchema() {
+ continue
+ }
+
+ // Don't add suffix if name already ends with it
+ if strings.HasSuffix(n.GoName, suffix) {
+ continue
+ }
+
+ n.GoName = n.GoName + suffix
+ progress = true
+ }
+ return progress
+}
+
+// strategyPerSchemaDisambiguate tries several per-schema disambiguation strategies.
+// Returns true if any name was modified, false if no progress was made.
+func strategyPerSchemaDisambiguate(group []*ResolvedName) bool {
+ progress := tryContentTypeSuffix(group)
+ if !progress && tryStatusCodeSuffix(group) {
+ progress = true
+ }
+ if !progress && tryParamIndexSuffix(group) {
+ progress = true
+ }
+ return progress
+}
+
+// tryContentTypeSuffix appends a content type discriminator when schemas
+// differ by media type (e.g., JSON vs XML).
+// Returns true if any name was modified, false if no progress was made.
+func tryContentTypeSuffix(group []*ResolvedName) bool {
+ // Check if any members have different content types
+ contentTypes := make(map[string]bool)
+ for _, n := range group {
+ if n.Schema.ContentType != "" {
+ contentTypes[n.Schema.ContentType] = true
+ }
+ }
+ if len(contentTypes) <= 1 {
+ return false
+ }
+
+ progress := false
+ for _, n := range group {
+ if n.Pinned {
+ continue
+ }
+ if n.Schema.ContentType == "" {
+ continue
+ }
+ suffix := contentTypeSuffix(n.Schema.ContentType)
+ if suffix != "" && !strings.HasSuffix(n.GoName, suffix) {
+ n.GoName = n.GoName + suffix
+ progress = true
+ }
+ }
+ return progress
+}
+
+// tryStatusCodeSuffix appends the HTTP status code when schemas differ by status.
+// Returns true if any name was modified, false if no progress was made.
+func tryStatusCodeSuffix(group []*ResolvedName) bool {
+ statusCodes := make(map[string]bool)
+ for _, n := range group {
+ if n.Schema.StatusCode != "" {
+ statusCodes[n.Schema.StatusCode] = true
+ }
+ }
+ if len(statusCodes) <= 1 {
+ return false
+ }
+
+ progress := false
+ for _, n := range group {
+ if n.Pinned {
+ continue
+ }
+ if n.Schema.StatusCode != "" && !strings.HasSuffix(n.GoName, n.Schema.StatusCode) {
+ n.GoName = n.GoName + n.Schema.StatusCode
+ progress = true
+ }
+ }
+ return progress
+}
+
+// tryParamIndexSuffix appends a parameter index when schemas differ by position.
+// Returns true if any name was modified, false if no progress was made.
+func tryParamIndexSuffix(group []*ResolvedName) bool {
+ hasMultipleParams := false
+ for i := range group {
+ for j := i + 1; j < len(group); j++ {
+ if group[i].Schema.ParamIndex != group[j].Schema.ParamIndex {
+ hasMultipleParams = true
+ break
+ }
+ }
+ if hasMultipleParams {
+ break
+ }
+ }
+ if !hasMultipleParams {
+ return false
+ }
+
+ progress := false
+ for _, n := range group {
+ if n.Pinned {
+ continue
+ }
+ suffix := strconv.Itoa(n.Schema.ParamIndex)
+ if !strings.HasSuffix(n.GoName, suffix) {
+ n.GoName = n.GoName + suffix
+ progress = true
+ }
+ }
+ return progress
+}
+
+// strategyNumericFallback is the last resort: append increasing numbers.
+// Returns true if any name was modified (always true when group has 2+ members).
+func strategyNumericFallback(group []*ResolvedName) bool {
+ // Sort for determinism: pinned first, then component schemas, then by path
+ sort.Slice(group, func(i, j int) bool {
+ if group[i].Pinned != group[j].Pinned {
+ return group[i].Pinned
+ }
+ if group[i].Schema.IsComponentSchema() != group[j].Schema.IsComponentSchema() {
+ return group[i].Schema.IsComponentSchema()
+ }
+ return group[i].Schema.Path.String() < group[j].Schema.Path.String()
+ })
+
+ // First non-pinned keeps name, rest get numeric suffix
+ for i := 1; i < len(group); i++ {
+ if group[i].Pinned {
+ continue
+ }
+ group[i].GoName = group[i].GoName + strconv.Itoa(i+1)
+ }
+ return len(group) > 1
+}
+
+// contentTypeSuffix returns a short suffix for a media type.
+func contentTypeSuffix(ct string) string {
+ if ct == "" {
+ return ""
+ }
+ ct = strings.ToLower(ct)
+ switch {
+ case strings.Contains(ct, "json"):
+ return "JSON"
+ case strings.Contains(ct, "xml"):
+ return "XML"
+ case strings.Contains(ct, "form"):
+ return "Form"
+ case strings.Contains(ct, "text"):
+ return "Text"
+ case strings.Contains(ct, "octet"):
+ return "Binary"
+ case strings.Contains(ct, "yaml"):
+ return "YAML"
+ default:
+ return mediaTypeToCamelCase(ct)
+ }
+}
diff --git a/pkg/codegen/resolve_names_test.go b/pkg/codegen/resolve_names_test.go
new file mode 100644
index 0000000000..806eaf6740
--- /dev/null
+++ b/pkg/codegen/resolve_names_test.go
@@ -0,0 +1,379 @@
+package codegen
+
+import (
+ "testing"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/stretchr/testify/assert"
+)
+
+func TestResolveNames_NoCollisions(t *testing.T) {
+ schemas := []*GatheredSchema{
+ {
+ Path: SchemaPath{"components", "schemas", "Pet"},
+ Context: ContextComponentSchema,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Pet",
+ },
+ {
+ Path: SchemaPath{"components", "schemas", "Owner"},
+ Context: ContextComponentSchema,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Owner",
+ },
+ }
+
+ result := ResolveNames(schemas)
+
+ assert.Equal(t, "Pet", result["components/schemas/Pet"])
+ assert.Equal(t, "Owner", result["components/schemas/Owner"])
+}
+
+func TestResolveNames_Issue200_CrossSectionCollisions(t *testing.T) {
+ // "Bar" appears in schemas, parameters, responses, requestBodies, headers
+ schemas := []*GatheredSchema{
+ {
+ Path: SchemaPath{"components", "schemas", "Bar"},
+ Context: ContextComponentSchema,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Bar",
+ },
+ {
+ Path: SchemaPath{"components", "parameters", "Bar"},
+ Context: ContextComponentParameter,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Bar",
+ },
+ {
+ Path: SchemaPath{"components", "responses", "Bar", "content", "application/json"},
+ Context: ContextComponentResponse,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Bar",
+ ContentType: "application/json",
+ },
+ {
+ Path: SchemaPath{"components", "requestBodies", "Bar", "content", "application/json"},
+ Context: ContextComponentRequestBody,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Bar",
+ ContentType: "application/json",
+ },
+ {
+ Path: SchemaPath{"components", "headers", "Bar"},
+ Context: ContextComponentHeader,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Bar",
+ },
+ }
+
+ result := ResolveNames(schemas)
+
+ // Component schema is privileged — keeps bare name
+ assert.Equal(t, "Bar", result["components/schemas/Bar"])
+ // Others get context suffixes
+ assert.Equal(t, "BarParameter", result["components/parameters/Bar"])
+ assert.Equal(t, "BarResponse", result["components/responses/Bar/content/application/json"])
+ assert.Equal(t, "BarRequestBody", result["components/requestBodies/Bar/content/application/json"])
+ assert.Equal(t, "BarHeader", result["components/headers/Bar"])
+}
+
+func TestResolveNames_Issue1474_ClientWrapperCollision(t *testing.T) {
+ // Schema named "CreateChatCompletionResponse" collides with
+ // client wrapper for operation "createChatCompletion" which
+ // would generate "CreateChatCompletionResponse".
+ schemas := []*GatheredSchema{
+ {
+ Path: SchemaPath{"components", "schemas", "CreateChatCompletionResponse"},
+ Context: ContextComponentSchema,
+ Schema: &openapi3.Schema{},
+ ComponentName: "CreateChatCompletionResponse",
+ },
+ {
+ Path: SchemaPath{"paths", "/chat/completions", "POST", "x-client-response-wrapper"},
+ Context: ContextClientResponseWrapper,
+ OperationID: "createChatCompletion",
+ },
+ }
+
+ result := ResolveNames(schemas)
+
+ // Component schema is privileged — keeps its name
+ assert.Equal(t, "CreateChatCompletionResponse", result["components/schemas/CreateChatCompletionResponse"])
+ // Client wrapper gets a suffix to avoid collision
+ wrapperName := result["paths//chat/completions/POST/x-client-response-wrapper"]
+ assert.NotEqual(t, "CreateChatCompletionResponse", wrapperName,
+ "client wrapper should not collide with component schema")
+ assert.Contains(t, wrapperName, "Response",
+ "client wrapper should still contain 'Response'")
+}
+
+func TestResolveNames_PrivilegedComponentSchema(t *testing.T) {
+ // When exactly one collision member is a component schema,
+ // it keeps the bare name
+ schemas := []*GatheredSchema{
+ {
+ Path: SchemaPath{"components", "schemas", "Foo"},
+ Context: ContextComponentSchema,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Foo",
+ },
+ {
+ Path: SchemaPath{"components", "parameters", "Foo"},
+ Context: ContextComponentParameter,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Foo",
+ },
+ }
+
+ result := ResolveNames(schemas)
+
+ assert.Equal(t, "Foo", result["components/schemas/Foo"])
+ assert.Equal(t, "FooParameter", result["components/parameters/Foo"])
+}
+
+func TestResolveNames_NoComponentSchema_AllGetSuffixes(t *testing.T) {
+ // When no member is a component schema, all get suffixed
+ schemas := []*GatheredSchema{
+ {
+ Path: SchemaPath{"components", "parameters", "Foo"},
+ Context: ContextComponentParameter,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Foo",
+ },
+ {
+ Path: SchemaPath{"components", "responses", "Foo", "content", "application/json"},
+ Context: ContextComponentResponse,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Foo",
+ ContentType: "application/json",
+ },
+ }
+
+ result := ResolveNames(schemas)
+
+ assert.Equal(t, "FooParameter", result["components/parameters/Foo"])
+ assert.Equal(t, "FooResponse", result["components/responses/Foo/content/application/json"])
+}
+
+func TestResolveNames_NumericFallback(t *testing.T) {
+ // Two schemas with same context that can't be disambiguated
+ // by context suffix (both are component schemas)
+ schemas := []*GatheredSchema{
+ {
+ Path: SchemaPath{"components", "schemas", "Foo"},
+ Context: ContextComponentSchema,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Foo",
+ },
+ {
+ // Hypothetical: same candidate name from a different path
+ // This shouldn't normally happen with real specs, but tests the fallback
+ Path: SchemaPath{"components", "schemas", "foo"},
+ Context: ContextComponentSchema,
+ Schema: &openapi3.Schema{},
+ ComponentName: "foo",
+ },
+ }
+
+ result := ResolveNames(schemas)
+
+ names := make(map[string]bool)
+ for _, name := range result {
+ names[name] = true
+ }
+ // Both should have unique names
+ assert.Len(t, names, 2, "should have two unique names")
+}
+
+func TestResolveNames_MultipleJsonContentTypes(t *testing.T) {
+ // "Order" appears in schemas and requestBodies. The requestBody has
+ // 3 content types that all contain "json" and map to the same "JSON"
+ // suffix. The global phase approach should prevent oscillation between
+ // context suffix and content type suffix, letting numeric fallback resolve.
+ schemas := []*GatheredSchema{
+ {
+ Path: SchemaPath{"components", "schemas", "Order"},
+ Context: ContextComponentSchema,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Order",
+ },
+ {
+ Path: SchemaPath{"components", "requestBodies", "Order", "content", "application/json"},
+ Context: ContextComponentRequestBody,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Order",
+ ContentType: "application/json",
+ },
+ {
+ Path: SchemaPath{"components", "requestBodies", "Order", "content", "application/merge-patch+json"},
+ Context: ContextComponentRequestBody,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Order",
+ ContentType: "application/merge-patch+json",
+ },
+ {
+ Path: SchemaPath{"components", "requestBodies", "Order", "content", "application/json-patch+json"},
+ Context: ContextComponentRequestBody,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Order",
+ ContentType: "application/json-patch+json",
+ },
+ }
+
+ result := ResolveNames(schemas)
+
+ // Component schema keeps bare name
+ assert.Equal(t, "Order", result["components/schemas/Order"])
+
+ // All 3 requestBody types must have unique names
+ names := make(map[string]bool)
+ for _, name := range result {
+ names[name] = true
+ }
+ assert.Len(t, names, 4, "all 4 types should have unique names")
+
+ // The first requestBody should get RequestBody+JSON suffixes
+ assert.Equal(t, "OrderRequestBodyJSON",
+ result["components/requestBodies/Order/content/application/json"])
+
+ // The remaining two collide on OrderRequestBodyJSON and get numeric fallback
+ jsonPatchName := result["components/requestBodies/Order/content/application/json-patch+json"]
+ mergePatchName := result["components/requestBodies/Order/content/application/merge-patch+json"]
+ assert.NotEqual(t, jsonPatchName, mergePatchName,
+ "json-patch and merge-patch types must have different names")
+ assert.Contains(t, jsonPatchName, "OrderRequestBodyJSON")
+ assert.Contains(t, mergePatchName, "OrderRequestBodyJSON")
+}
+
+func TestResolveNames_XGoNamePinned_Schema(t *testing.T) {
+ // Pattern K: schema "Renamer" has x-go-name="SpecialName" which collides
+ // with nothing, but a response also named "Renamer" should keep its
+ // normal resolved name. The schema is pinned.
+ schemas := []*GatheredSchema{
+ {
+ Path: SchemaPath{"components", "schemas", "Renamer"},
+ Context: ContextComponentSchema,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Renamer",
+ GoNameOverride: "SpecialName",
+ },
+ {
+ Path: SchemaPath{"components", "responses", "Renamer", "content", "application/json"},
+ Context: ContextComponentResponse,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Renamer",
+ ContentType: "application/json",
+ },
+ }
+
+ result := ResolveNames(schemas)
+
+ // Schema pinned to SpecialName
+ assert.Equal(t, "SpecialName", result["components/schemas/Renamer"])
+ // Response keeps bare name since there's no collision with "Renamer"
+ assert.Equal(t, "Renamer", result["components/responses/Renamer/content/application/json"])
+}
+
+func TestResolveNames_XGoNamePinned_Response(t *testing.T) {
+ // Pattern L: response "Outcome" has x-go-name="OutcomeResult" and
+ // schema also named "Outcome". The response is pinned as "OutcomeResult",
+ // so the schema keeps "Outcome" (no collision).
+ schemas := []*GatheredSchema{
+ {
+ Path: SchemaPath{"components", "schemas", "Outcome"},
+ Context: ContextComponentSchema,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Outcome",
+ },
+ {
+ Path: SchemaPath{"components", "responses", "Outcome", "content", "application/json"},
+ Context: ContextComponentResponse,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Outcome",
+ ContentType: "application/json",
+ GoNameOverride: "OutcomeResult",
+ },
+ }
+
+ result := ResolveNames(schemas)
+
+ // Schema keeps bare name
+ assert.Equal(t, "Outcome", result["components/schemas/Outcome"])
+ // Response pinned to OutcomeResult
+ assert.Equal(t, "OutcomeResult", result["components/responses/Outcome/content/application/json"])
+}
+
+func TestResolveNames_XGoNamePinned_RequestBody(t *testing.T) {
+ // Pattern M: requestBody "Payload" has x-go-name="PayloadBody" and
+ // schema also named "Payload". The requestBody is pinned.
+ schemas := []*GatheredSchema{
+ {
+ Path: SchemaPath{"components", "schemas", "Payload"},
+ Context: ContextComponentSchema,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Payload",
+ },
+ {
+ Path: SchemaPath{"components", "requestBodies", "Payload", "content", "application/json"},
+ Context: ContextComponentRequestBody,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Payload",
+ ContentType: "application/json",
+ GoNameOverride: "PayloadBody",
+ },
+ }
+
+ result := ResolveNames(schemas)
+
+ // Schema keeps bare name
+ assert.Equal(t, "Payload", result["components/schemas/Payload"])
+ // RequestBody pinned to PayloadBody
+ assert.Equal(t, "PayloadBody", result["components/requestBodies/Payload/content/application/json"])
+}
+
+func TestResolveNames_PinnedNotModifiedByStrategies(t *testing.T) {
+ // Pinned name "Foo" vs non-pinned parameter "Foo" → parameter gets suffixed
+ schemas := []*GatheredSchema{
+ {
+ Path: SchemaPath{"components", "schemas", "Foo"},
+ Context: ContextComponentSchema,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Foo",
+ GoNameOverride: "Foo",
+ },
+ {
+ Path: SchemaPath{"components", "parameters", "Foo"},
+ Context: ContextComponentParameter,
+ Schema: &openapi3.Schema{},
+ ComponentName: "Foo",
+ },
+ }
+
+ result := ResolveNames(schemas)
+
+ // Pinned schema stays as "Foo"
+ assert.Equal(t, "Foo", result["components/schemas/Foo"])
+ // Parameter gets suffixed to resolve collision
+ assert.Equal(t, "FooParameter", result["components/parameters/Foo"])
+}
+
+func TestContentTypeSuffix(t *testing.T) {
+ tests := []struct {
+ input string
+ expected string
+ }{
+ {"application/json", "JSON"},
+ {"application/xml", "XML"},
+ {"application/x-www-form-urlencoded", "Form"},
+ {"text/plain", "Text"},
+ {"application/octet-stream", "Binary"},
+ {"application/yaml", "YAML"},
+ {"", ""},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.input, func(t *testing.T) {
+ assert.Equal(t, tt.expected, contentTypeSuffix(tt.input))
+ })
+ }
+}
diff --git a/pkg/codegen/schema.go b/pkg/codegen/schema.go
index 7f48f71050..2e216537f0 100644
--- a/pkg/codegen/schema.go
+++ b/pkg/codegen/schema.go
@@ -3,6 +3,8 @@ package codegen
import (
"errors"
"fmt"
+ "maps"
+ "slices"
"strings"
"github.com/getkin/kin-openapi/openapi3"
@@ -33,16 +35,62 @@ type Schema struct {
// If this is set, the schema will declare a type via alias, eg,
// `type Foo = bool`. If this is not set, we will define this type via
// type definition `type Foo bool`
+ //
+ // Can be overriden by the OutputOptions#DisableTypeAliasesForType field
DefineViaAlias bool
// The original OpenAPIv3 Schema.
OAPISchema *openapi3.Schema
}
+// IsPrimitive returns true if the schema represents a primitive OpenAPI type
+// (string, integer, number, or boolean) as opposed to an object, array, or
+// composed type.
+func (s Schema) IsPrimitive() bool {
+ if s.OAPISchema == nil {
+ return false
+ }
+ t := s.OAPISchema.Type
+ return t.Is("string") || t.Is("integer") || t.Is("number") || t.Is("boolean")
+}
+
func (s Schema) IsRef() bool {
return s.RefType != ""
}
+func (s Schema) IsExternalRef() bool {
+ if !s.IsRef() {
+ return false
+ }
+ return strings.Contains(s.RefType, ".")
+}
+
+// HasCustomMarshalJSON reports whether using this schema position as an
+// underlying type of a named defined type (e.g. `type X Event` where Event is
+// a oneOf union defined in components.schemas) would lose a custom
+// MarshalJSON/UnmarshalJSON that we need to delegate to. This is true when
+// the schema is a $ref to a oneOf/anyOf union defined elsewhere.
+//
+// For *local* inline unions it is deliberately false: those are generated by
+// emitting the union struct at this schema position, with its own
+// MarshalJSON. The template's existing $hasUnionElements branch handles
+// encoding by writing .union directly, so no delegation is needed.
+//
+// For *external* inline unions (the response-root hoist set RefType to a
+// type living in an imported package), the strict envelope is rendered as a
+// defined type — `type X externalRef0.Y` — and methods on Y don't transfer.
+// The .union shortcut also can't reach across packages. So we still need the
+// MarshalJSON delegator here, even though UnionElements is non-empty.
+func (s Schema) HasCustomMarshalJSON() bool {
+ if s.OAPISchema == nil {
+ return false
+ }
+ if len(s.UnionElements) > 0 {
+ return s.IsExternalRef()
+ }
+ return len(s.OAPISchema.OneOf) > 0 || len(s.OAPISchema.AnyOf) > 0
+}
+
func (s Schema) TypeDecl() string {
if s.IsRef() {
return s.RefType
@@ -53,7 +101,7 @@ func (s Schema) TypeDecl() string {
// AddProperty adds a new property to the current Schema, and returns an error
// if it collides. Two identical fields will not collide, but two properties by
// the same name, but different definition, will collide. It's safe to merge the
-// fields of two schemas with overalapping properties if those properties are
+// fields of two schemas with overlapping properties if those properties are
// identical.
func (s *Schema) AddProperty(p Property) error {
// Scan all existing properties for a conflict
@@ -67,12 +115,7 @@ func (s *Schema) AddProperty(p Property) error {
}
func (s Schema) GetAdditionalTypeDefs() []TypeDefinition {
- var result []TypeDefinition
- for _, p := range s.Properties {
- result = append(result, p.Schema.GetAdditionalTypeDefs()...)
- }
- result = append(result, s.AdditionalTypes...)
- return result
+ return s.AdditionalTypes
}
type Property struct {
@@ -84,16 +127,36 @@ type Property struct {
ReadOnly bool
WriteOnly bool
NeedsFormTag bool
- Extensions map[string]interface{}
+ Extensions map[string]any
Deprecated bool
}
func (p Property) GoFieldName() string {
- return SchemaNameToTypeName(p.JsonFieldName)
+ goFieldName := p.JsonFieldName
+ if extension, ok := p.Extensions[extGoName]; ok {
+ if extGoFieldName, err := extParseGoFieldName(extension); err == nil {
+ goFieldName = extGoFieldName
+ }
+ }
+
+ if globalState.options.Compatibility.AllowUnexportedStructFieldNames {
+ if extension, ok := p.Extensions[extOapiCodegenOnlyHonourGoName]; ok {
+ if extOapiCodegenOnlyHonourGoName, err := extParseOapiCodegenOnlyHonourGoName(extension); err == nil {
+ if extOapiCodegenOnlyHonourGoName {
+ return goFieldName
+ }
+ }
+ }
+ }
+
+ return SchemaNameToTypeName(goFieldName)
}
func (p Property) GoTypeDef() string {
typeDef := p.Schema.TypeDecl()
+ if globalState.options.OutputOptions.NullableType && p.Nullable {
+ return "nullable.Nullable[" + typeDef + "]"
+ }
if !p.Schema.SkipOptionalPointer &&
(!p.Required || p.Nullable ||
(p.ReadOnly && (!p.Required || !globalState.options.Compatibility.DisableRequiredReadOnlyAsPointer)) ||
@@ -104,6 +167,35 @@ func (p Property) GoTypeDef() string {
return typeDef
}
+// RequiresNilCheck indicates whether the generated property should have a nil check performed on it before other checks.
+// This should be used in templates when performing `nil` checks, but NOT when i.e. determining if there should be an optional pointer given to the type - in that case, use `HasOptionalPointer`
+func (p Property) RequiresNilCheck() bool {
+ return p.ZeroValueIsNil() || p.HasOptionalPointer()
+}
+
+// HasOptionalPointer indicates whether the generated property has an optional pointer associated with it.
+// This takes into account the `x-go-type-skip-optional-pointer` extension, allowing a parameter definition to control whether the pointer should be skipped.
+func (p Property) HasOptionalPointer() bool {
+ return !p.Required && !p.Schema.SkipOptionalPointer
+}
+
+// ZeroValueIsNil is a helper function to determine if the given Go type used
+// for this property has `nil` as its Go zero value. Slices (OpenAPI `array`)
+// and maps (OpenAPI `object` with only `additionalProperties`, rendered as
+// `map[K]V`) both satisfy this — the custom-marshal templates use it to decide
+// whether to emit a nil-check before reading the field.
+func (p Property) ZeroValueIsNil() bool {
+ if p.Schema.OAPISchema == nil {
+ return false
+ }
+
+ if p.Schema.OAPISchema.Type.Is("array") {
+ return true
+ }
+
+ return strings.HasPrefix(p.Schema.GoType, "map[")
+}
+
// EnumDefinition holds type information for enum
type EnumDefinition struct {
// Schema is the scheme of a type which has a list of enum values, eg, the
@@ -141,6 +233,9 @@ type Constants struct {
SecuritySchemeProviderNames []string
// EnumDefinitions holds type and value information for all enums
EnumDefinitions []EnumDefinition
+ // SkipEnumValidate suppresses generation of the `Valid()` method on
+ // enum types. Mirrors OutputOptions.SkipEnumValidate.
+ SkipEnumValidate bool
}
// TypeDefinition describes a Go type definition in generated code.
@@ -164,6 +259,14 @@ type TypeDefinition struct {
// This is the Schema wrapper is used to populate the type description
Schema Schema
+
+ // ForceEnumPrefix, when true, forces the enum-value constants generated
+ // from this TypeDefinition to be prefixed with the type name, regardless
+ // of whether GenerateEnums detects a cross-enum conflict. Used for
+ // synthesised enum types (e.g. server-URL variable enums) whose
+ // generated identifiers must remain stable to avoid colliding with
+ // other constants emitted alongside them.
+ ForceEnumPrefix bool
}
// ResponseTypeDefinition is an extension of TypeDefinition, specifically for
@@ -175,6 +278,8 @@ type ResponseTypeDefinition struct {
// The type name of a response model.
ResponseName string
+
+ AdditionalTypeDefinitions []TypeDefinition
}
func (t *TypeDefinition) IsAlias() bool {
@@ -207,11 +312,11 @@ func (u UnionElement) String() string {
// Method generate union method name for template functions `As/From/Merge`.
func (u UnionElement) Method() string {
- var method string
- for _, part := range strings.Split(string(u), `.`) {
- method += UppercaseFirstCharacter(part)
+ var method strings.Builder
+ for part := range strings.SplitSeq(string(u), `.`) {
+ method.WriteString(UppercaseFirstCharacter(part))
}
- return method
+ return method.String()
}
func PropertiesEqual(a, b Property) bool {
@@ -227,45 +332,62 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
}
schema := sref.Value
+ extensions := combinedSchemaExtensions(sref)
+
+ // Check x-go-type-skip-optional-pointer, which will override if the type
+ // should be a pointer or not when the field is optional.
+ // NOTE skipOptionalPointer will be defaulted to the global value, but can be overridden on a per-type/-field basis
+ skipOptionalPointer := globalState.options.OutputOptions.PreferSkipOptionalPointer
+ if extension, ok := extensions[extPropGoTypeSkipOptionalPointer]; ok {
+ var err error
+ skipOptionalPointer, err = extParsePropGoTypeSkipOptionalPointer(extension)
+ if err != nil {
+ return Schema{}, fmt.Errorf("invalid value for %q: %w", extPropGoTypeSkipOptionalPointer, err)
+ }
+ }
// If Ref is set on the SchemaRef, it means that this type is actually a reference to
// another type. We're not de-referencing, so simply use the referenced type.
if IsGoTypeReference(sref.Ref) {
- // Convert the reference path to Go type
- refType, err := RefPathToGoType(sref.Ref)
- if err != nil {
- return Schema{}, fmt.Errorf("error turning reference (%s) into a Go type: %s",
- sref.Ref, err)
+ var refType string
+
+ // check if there is an x-go-type extension next to the $ref and use that over the overrided type.
+ if extension, ok := sref.Extensions[extPropGoType]; ok {
+ var ok bool
+ refType, ok = extension.(string)
+ if !ok {
+ return Schema{}, fmt.Errorf("error turning '%s: %v' into string",
+ extPropGoType, extension)
+ }
+ } else {
+ // Convert the reference path to Go type
+ var err error
+ refType, err = RefPathToGoType(sref.Ref)
+ if err != nil {
+ return Schema{}, fmt.Errorf("error turning reference (%s) into a Go type: %s",
+ sref.Ref, err)
+ }
}
+
return Schema{
- GoType: refType,
- Description: schema.Description,
- DefineViaAlias: true,
- OAPISchema: schema,
+ GoType: refType,
+ Description: schema.Description,
+ DefineViaAlias: true,
+ SkipOptionalPointer: skipOptionalPointer,
+ OAPISchema: schema,
}, nil
}
outSchema := Schema{
- Description: schema.Description,
- OAPISchema: schema,
- }
-
- // AllOf is interesting, and useful. It's the union of a number of other
- // schemas. A common usage is to create a union of an object with an ID,
- // so that in a RESTful paradigm, the Create operation can return
- // (object, id), so that other operations can refer to (id)
- if schema.AllOf != nil {
- mergedSchema, err := MergeSchemas(schema.AllOf, path)
- if err != nil {
- return Schema{}, fmt.Errorf("error merging schemas: %w", err)
- }
- mergedSchema.OAPISchema = schema
- return mergedSchema, nil
+ Description: schema.Description,
+ OAPISchema: schema,
+ SkipOptionalPointer: skipOptionalPointer,
}
// Check x-go-type, which will completely override the definition of this
- // schema with the provided type.
- if extension, ok := schema.Extensions[extPropGoType]; ok {
+ // schema with the provided type. This must be checked before AllOf so
+ // that an override on the outer schema wins over allOf composition.
+ if extension, ok := extensions[extPropGoType]; ok {
typeName, err := extTypeName(extension)
if err != nil {
return outSchema, fmt.Errorf("invalid value for %q: %w", extPropGoType, err)
@@ -276,33 +398,85 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
return outSchema, nil
}
- // Check x-go-type-skip-optional-pointer, which will override if the type
- // should be a pointer or not when the field is optional.
- if extension, ok := schema.Extensions[extPropGoTypeSkipOptionalPointer]; ok {
- skipOptionalPointer, err := extParsePropGoTypeSkipOptionalPointer(extension)
+ // AllOf is interesting, and useful. It's the union of a number of other
+ // schemas. A common usage is to create a union of an object with an ID,
+ // so that in a RESTful paradigm, the Create operation can return
+ // (object, id), so that other operations can refer to (id)
+ if schema.AllOf != nil {
+ var mergedSchema Schema
+ var err error
+ // Behavior is gated on Compatibility.OldAllOfSiblingMerging:
+ // when set, the parent's structural siblings and Description are
+ // silently discarded (the historical behavior). When unset
+ // (default), they are merged into the result.
+ mergeSiblings := !globalState.options.Compatibility.OldAllOfSiblingMerging
+ if mergeSiblings && hasStructuralSiblings(schema) {
+ // Inject the parent (with AllOf cleared) as the final allOf
+ // member so its structural siblings — Properties, Required,
+ // AdditionalProperties — are merged with the allOf members
+ // rather than discarded. Issues #697, #931, #1710, #2102.
+ //
+ // Allocate a fresh slice rather than appending to schema.AllOf
+ // directly: if kin-openapi gave us a slice with spare capacity,
+ // `append` would write the new element into the shared backing
+ // array, mutating any other view that has been extended past
+ // len(schema.AllOf).
+ s := *schema
+ s.AllOf = nil
+ allOfRefs := make([]*openapi3.SchemaRef, 0, len(schema.AllOf)+1)
+ allOfRefs = append(allOfRefs, schema.AllOf...)
+ allOfRefs = append(allOfRefs, &openapi3.SchemaRef{Value: &s})
+ mergedSchema, err = MergeSchemas(allOfRefs, path)
+ } else {
+ // Either the user opted into legacy behavior, or the parent is
+ // a pure wrapper with no structural siblings. In the wrapper
+ // case, MergeSchemas' single-element fast path returns the
+ // referenced type unchanged, preserving named-type identity.
+ mergedSchema, err = MergeSchemas(schema.AllOf, path)
+ }
if err != nil {
- return outSchema, fmt.Errorf("invalid value for %q: %w", extPropGoTypeSkipOptionalPointer, err)
+ return Schema{}, fmt.Errorf("error merging schemas: %w", err)
}
- outSchema.SkipOptionalPointer = skipOptionalPointer
+ mergedSchema.OAPISchema = schema
+ // Description is metadata, not a structural constraint, so it
+ // doesn't go through the merge. Copy it from the parent when set.
+ // Issue #1960. Gated on the same compatibility flag as the
+ // sibling-merge above.
+ if mergeSiblings && schema.Description != "" {
+ mergedSchema.Description = schema.Description
+ }
+ // x-go-type on the parent is handled by the early return above
+ // (combined extensions). For x-go-type-skip-optional-pointer, only
+ // override the merged value when the parent sets it explicitly —
+ // otherwise we would clobber the value MergeSchemas computed from
+ // the decorator idiom (an inline allOf member that carries the
+ // extension; see merge_schemas.go and issue #1957).
+ if _, ok := extensions[extPropGoTypeSkipOptionalPointer]; ok {
+ mergedSchema.SkipOptionalPointer = skipOptionalPointer
+ }
+ return mergedSchema, nil
}
// Schema type and format, eg. string / binary
t := schema.Type
// Handle objects and empty schemas first as a special case
- if t == "" || t == "object" {
+ if t.Slice() == nil || t.Is("object") {
var outType string
if len(schema.Properties) == 0 && !SchemaHasAdditionalProperties(schema) && schema.AnyOf == nil && schema.OneOf == nil {
// If the object has no properties or additional properties, we
// have some special cases for its type.
- if t == "object" {
+ if t.Is("object") {
// We have an object with no properties. This is a generic object
// expressed as a map.
outType = "map[string]interface{}"
+ setSkipOptionalPointerForContainerType(&outSchema)
} else { // t == ""
// If we don't even have the object designator, we're a completely
// generic type.
outType = "interface{}"
+ // this should never have an "optional pointer", as it doesn't make sense to be a `*interface{}`
+ outSchema.SkipOptionalPointer = true
}
outSchema.GoType = outType
outSchema.DefineViaAlias = true
@@ -359,6 +533,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
// since we don't need them for a simple map.
outSchema.HasAdditionalProperties = false
outSchema.GoType = fmt.Sprintf("map[string]%s", additionalPropertiesType(outSchema))
+ setSkipOptionalPointerForContainerType(&outSchema)
return outSchema, nil
}
@@ -371,7 +546,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
return Schema{}, fmt.Errorf("error generating Go schema for property '%s': %w", pName, err)
}
- required := StringInArray(pName, schema.Required)
+ required := slices.Contains(schema.Required, pName)
if (pSchema.HasAdditionalProperties || len(pSchema.UnionElements) != 0) && pSchema.RefType == "" {
// If we have fields present which have additional properties or union values,
@@ -393,6 +568,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
if p.Value != nil {
description = p.Value.Description
}
+
prop := Property{
JsonFieldName: pName,
Schema: pSchema,
@@ -401,10 +577,13 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
Nullable: p.Value.Nullable,
ReadOnly: p.Value.ReadOnly,
WriteOnly: p.Value.WriteOnly,
- Extensions: p.Value.Extensions,
+ Extensions: combinedSchemaExtensions(p),
Deprecated: p.Value.Deprecated,
}
outSchema.Properties = append(outSchema.Properties, prop)
+ if len(pSchema.AdditionalTypes) > 0 {
+ outSchema.AdditionalTypes = append(outSchema.AdditionalTypes, pSchema.AdditionalTypes...)
+ }
}
if schema.AnyOf != nil {
@@ -424,7 +603,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
// Check for x-go-type-name. It behaves much like x-go-type, however, it will
// create a type definition for the named type, and use the named type in place
// of this schema.
- if extension, ok := schema.Extensions[extGoTypeName]; ok {
+ if extension, ok := extensions[extGoTypeName]; ok {
typeName, err := extTypeName(extension)
if err != nil {
return outSchema, fmt.Errorf("invalid value for %q: %w", extGoTypeName, err)
@@ -438,7 +617,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
Description: newTypeDef.Schema.Description,
GoType: typeName,
DefineViaAlias: true,
- AdditionalTypes: []TypeDefinition{newTypeDef},
+ AdditionalTypes: append(outSchema.AdditionalTypes, newTypeDef),
}
}
@@ -460,8 +639,8 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
enumNames := enumValues
for _, key := range []string{extEnumVarNames, extEnumNames} {
- if _, ok := schema.Extensions[key]; ok {
- if extEnumNames, err := extParseEnumVarNames(schema.Extensions[key]); err == nil {
+ if extension, ok := extensions[key]; ok {
+ if extEnumNames, err := extParseEnumVarNames(extension); err == nil {
enumNames = extEnumNames
break
}
@@ -486,9 +665,9 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
}
if len(path) > 1 { // handle additional type only on non-toplevel types
// Allow overriding autogenerated enum type names, since these may
- // cause conflicts - see https://github.com/deepmap/oapi-codegen/issues/832
+ // cause conflicts - see https://github.com/oapi-codegen/oapi-codegen/issues/832
var typeName string
- if extension, ok := schema.Extensions[extGoTypeName]; ok {
+ if extension, ok := extensions[extGoTypeName]; ok {
typeName, err = extString(extension)
if err != nil {
return outSchema, fmt.Errorf("invalid value for %q: %w", extGoTypeName, err)
@@ -520,14 +699,14 @@ func oapiSchemaToGoType(schema *openapi3.Schema, path []string, outSchema *Schem
f := schema.Format
t := schema.Type
- switch t {
- case "array":
+ if t.Is("array") {
// For arrays, we'll get the type of the Items and throw a
// [] in front of it.
arrayType, err := GenerateGoSchema(schema.Items, path)
if err != nil {
return fmt.Errorf("error generating type for array: %w", err)
}
+
if (arrayType.HasAdditionalProperties || len(arrayType.UnionElements) != 0) && arrayType.RefType == "" {
// If we have items which have additional properties or union values,
// but are not a pre-defined type, we need to define a type
@@ -544,78 +723,51 @@ func oapiSchemaToGoType(schema *openapi3.Schema, path []string, outSchema *Schem
arrayType.RefType = typeName
}
+
+ typeDeclaration := arrayType.TypeDecl()
+ if arrayType.OAPISchema != nil && arrayType.OAPISchema.Nullable {
+ if globalState.options.OutputOptions.NullableType {
+ typeDeclaration = "nullable.Nullable[" + typeDeclaration + "]"
+ } else {
+ typeDeclaration = "*" + typeDeclaration
+ }
+ }
+
outSchema.ArrayType = &arrayType
- outSchema.GoType = "[]" + arrayType.TypeDecl()
+ outSchema.GoType = "[]" + typeDeclaration
outSchema.AdditionalTypes = arrayType.AdditionalTypes
outSchema.Properties = arrayType.Properties
outSchema.DefineViaAlias = true
- case "integer":
- // We default to int if format doesn't ask for something else.
- if f == "int64" {
- outSchema.GoType = "int64"
- } else if f == "int32" {
- outSchema.GoType = "int32"
- } else if f == "int16" {
- outSchema.GoType = "int16"
- } else if f == "int8" {
- outSchema.GoType = "int8"
- } else if f == "int" {
- outSchema.GoType = "int"
- } else if f == "uint64" {
- outSchema.GoType = "uint64"
- } else if f == "uint32" {
- outSchema.GoType = "uint32"
- } else if f == "uint16" {
- outSchema.GoType = "uint16"
- } else if f == "uint8" {
- outSchema.GoType = "uint8"
- } else if f == "uint" {
- outSchema.GoType = "uint"
- } else {
- outSchema.GoType = "int"
+ if slices.Contains(globalState.options.OutputOptions.DisableTypeAliasesForType, "array") {
+ outSchema.DefineViaAlias = false
}
+ setSkipOptionalPointerForContainerType(outSchema)
+
+ } else if t.Is("integer") {
+ spec := globalState.typeMapping.Integer.Resolve(f)
+ outSchema.GoType = spec.Type
outSchema.DefineViaAlias = true
- case "number":
- // We default to float for "number"
- if f == "double" {
- outSchema.GoType = "float64"
- } else if f == "float" || f == "" {
- outSchema.GoType = "float32"
- } else {
- return fmt.Errorf("invalid number format: %s", f)
- }
+ } else if t.Is("number") {
+ spec := globalState.typeMapping.Number.Resolve(f)
+ outSchema.GoType = spec.Type
outSchema.DefineViaAlias = true
- case "boolean":
- if f != "" {
- return fmt.Errorf("invalid format (%s) for boolean", f)
- }
- outSchema.GoType = "bool"
+ } else if t.Is("boolean") {
+ spec := globalState.typeMapping.Boolean.Resolve(f)
+ outSchema.GoType = spec.Type
outSchema.DefineViaAlias = true
- case "string":
- // Special case string formats here.
- switch f {
- case "byte":
- outSchema.GoType = "[]byte"
- case "email":
- outSchema.GoType = "openapi_types.Email"
- case "date":
- outSchema.GoType = "openapi_types.Date"
- case "date-time":
- outSchema.GoType = "time.Time"
- case "json":
- outSchema.GoType = "json.RawMessage"
+ } else if t.Is("string") {
+ spec := globalState.typeMapping.String.Resolve(f)
+ outSchema.GoType = spec.Type
+ // Preserve special behaviors for specific types
+ if outSchema.GoType == "[]byte" {
+ setSkipOptionalPointerForContainerType(outSchema)
+ }
+ if outSchema.GoType == "json.RawMessage" {
outSchema.SkipOptionalPointer = true
- case "uuid":
- outSchema.GoType = "openapi_types.UUID"
- case "binary":
- outSchema.GoType = "openapi_types.File"
- default:
- // All unrecognized formats are simply a regular string.
- outSchema.GoType = "string"
}
outSchema.DefineViaAlias = true
- default:
- return fmt.Errorf("unhandled Schema type: %s", t)
+ } else {
+ return fmt.Errorf("unhandled Schema type: %v", t)
}
return nil
}
@@ -635,6 +787,13 @@ type FieldDescriptor struct {
IsRef bool // Is this schema a reference to predefined object?
}
+func stringOrEmpty(b bool, s string) string {
+ if b {
+ return s
+ }
+ return ""
+}
+
// GenFieldsFromProperties produce corresponding field names with JSON annotations,
// given a list of schema descriptors
func GenFieldsFromProperties(props []Property) []string {
@@ -643,11 +802,6 @@ func GenFieldsFromProperties(props []Property) []string {
field := ""
goFieldName := p.GoFieldName()
- if _, ok := p.Extensions[extGoName]; ok {
- if extGoFieldName, err := extParseGoFieldName(p.Extensions[extGoName]); err == nil {
- goFieldName = extGoFieldName
- }
- }
// Add a comment to a field in case we have one, otherwise skip.
if p.Description != "" {
@@ -662,9 +816,9 @@ func GenFieldsFromProperties(props []Property) []string {
if p.Deprecated {
// This comment has to be on its own line for godoc & IDEs to pick up
var deprecationReason string
- if _, ok := p.Extensions[extDeprecationReason]; ok {
- if extOmitEmpty, err := extParseDeprecationReason(p.Extensions[extDeprecationReason]); err == nil {
- deprecationReason = extOmitEmpty
+ if extension, ok := p.Extensions[extDeprecationReason]; ok {
+ if extDeprecationReason, err := extParseDeprecationReason(extension); err == nil {
+ deprecationReason = extDeprecationReason
}
}
@@ -681,34 +835,47 @@ func GenFieldsFromProperties(props []Property) []string {
field += fmt.Sprintf(" %s %s", goFieldName, p.GoTypeDef())
- omitEmpty := !p.Nullable &&
- (!p.Required || p.ReadOnly || p.WriteOnly) &&
+ shouldOmitEmpty := (!p.Required || p.ReadOnly || p.WriteOnly) &&
(!p.Required || !p.ReadOnly || !globalState.options.Compatibility.DisableRequiredReadOnlyAsPointer)
- // Support x-omitempty
+ omitEmpty := shouldOmitEmpty
+
+ omitZero := false
+
+ // default, but allow turning of
+ if shouldOmitEmpty && p.Schema.SkipOptionalPointer && globalState.options.OutputOptions.PreferSkipOptionalPointerWithOmitzero {
+ omitZero = true
+ }
+
+ // Support x-omitempty and x-omitzero
if extOmitEmptyValue, ok := p.Extensions[extPropOmitEmpty]; ok {
- if extOmitEmpty, err := extParseOmitEmpty(extOmitEmptyValue); err == nil {
- omitEmpty = extOmitEmpty
+ if xValue, err := extParseOmitEmpty(extOmitEmptyValue); err == nil {
+ omitEmpty = xValue
+ }
+ }
+
+ if extOmitEmptyValue, ok := p.Extensions[extPropOmitZero]; ok {
+ if xValue, err := extParseOmitZero(extOmitEmptyValue); err == nil {
+ omitZero = xValue
}
}
fieldTags := make(map[string]string)
- if !omitEmpty {
- fieldTags["json"] = p.JsonFieldName
- if p.NeedsFormTag {
- fieldTags["form"] = p.JsonFieldName
- }
- } else {
- fieldTags["json"] = p.JsonFieldName + ",omitempty"
- if p.NeedsFormTag {
- fieldTags["form"] = p.JsonFieldName + ",omitempty"
- }
+ fieldTags["json"] = p.JsonFieldName +
+ stringOrEmpty(omitEmpty, ",omitempty") +
+ stringOrEmpty(omitZero, ",omitzero")
+
+ if globalState.options.OutputOptions.EnableYamlTags {
+ fieldTags["yaml"] = p.JsonFieldName + stringOrEmpty(omitEmpty, ",omitempty")
+ }
+ if p.NeedsFormTag {
+ fieldTags["form"] = p.JsonFieldName + stringOrEmpty(omitEmpty, ",omitempty")
}
// Support x-go-json-ignore
- if _, ok := p.Extensions[extPropGoJsonIgnore]; ok {
- if goJsonIgnore, err := extParseGoJsonIgnore(p.Extensions[extPropGoJsonIgnore]); err == nil && goJsonIgnore {
+ if extension, ok := p.Extensions[extPropGoJsonIgnore]; ok {
+ if goJsonIgnore, err := extParseGoJsonIgnore(extension); err == nil && goJsonIgnore {
fieldTags["json"] = "-"
}
}
@@ -716,14 +883,14 @@ func GenFieldsFromProperties(props []Property) []string {
// Support x-oapi-codegen-extra-tags
if extension, ok := p.Extensions[extPropExtraTags]; ok {
if tags, err := extExtraTags(extension); err == nil {
- keys := SortedStringKeys(tags)
+ keys := SortedMapKeys(tags)
for _, k := range keys {
fieldTags[k] = tags[k]
}
}
}
// Convert the fieldTags map into Go field annotations.
- keys := SortedStringKeys(fieldTags)
+ keys := SortedMapKeys(fieldTags)
tags := make([]string, len(keys))
for i, k := range keys {
tags[i] = fmt.Sprintf(`%s:"%s"`, k, fieldTags[k])
@@ -837,10 +1004,9 @@ func generateUnion(outSchema *Schema, elements openapi3.SchemaRefs, discriminato
// Explicit mapping.
var mapped bool
for k, v := range discriminator.Mapping {
- if v == element.Ref {
+ if v.Ref == element.Ref {
outSchema.Discriminator.Mapping[k] = elementSchema.GoType
mapped = true
- break
}
}
// Implicit mapping.
@@ -851,9 +1017,54 @@ func generateUnion(outSchema *Schema, elements openapi3.SchemaRefs, discriminato
outSchema.UnionElements = append(outSchema.UnionElements, UnionElement(elementSchema.GoType))
}
- if (outSchema.Discriminator != nil) && len(outSchema.Discriminator.Mapping) != len(elements) {
+ if (outSchema.Discriminator != nil) && len(outSchema.Discriminator.Mapping) < len(elements) {
return errors.New("discriminator: not all schemas were mapped")
}
return nil
}
+
+// setSkipOptionalPointerForContainerType ensures that the "optional pointer" is skipped on container types (such as a slice or a map).
+// This is controlled using the `prefer-skip-optional-pointer-on-container-types` Output Option
+// NOTE that it is still possible to override this on a per-field basis with `x-go-type-skip-optional-pointer`
+func setSkipOptionalPointerForContainerType(outSchema *Schema) {
+ if !globalState.options.OutputOptions.PreferSkipOptionalPointerOnContainerTypes {
+ return
+ }
+
+ outSchema.SkipOptionalPointer = true
+}
+
+// combinedSchemaExtensions returns one set of extensions taking
+// those from next to the $ref and the referenced schema itself.
+// Extensions next to the $ref take precedence.
+func combinedSchemaExtensions(r *openapi3.SchemaRef) map[string]any {
+ combined := map[string]any{}
+
+ if r.Value != nil {
+ maps.Copy(combined, r.Value.Extensions)
+ }
+
+ maps.Copy(combined, r.Extensions)
+
+ return combined
+}
+
+// hasStructuralSiblings reports whether a schema with allOf also carries
+// fields outside allOf that materially affect the generated Go type.
+// Such fields must be merged with the allOf members rather than discarded.
+//
+// Description and Title are excluded — they are metadata, not structural,
+// and the caller propagates them separately. Nullable/ReadOnly/WriteOnly
+// are also excluded for now: their strict-equality check in
+// mergeOpenapiSchemas conflates the bool zero value with "unset" and would
+// regress simple wrappers like {allOf: [X-with-nullable:true]}.
+func hasStructuralSiblings(s *openapi3.Schema) bool {
+ if s == nil {
+ return false
+ }
+ return len(s.Properties) > 0 ||
+ len(s.Required) > 0 ||
+ s.AdditionalProperties.Has != nil ||
+ s.AdditionalProperties.Schema != nil
+}
diff --git a/pkg/codegen/schema_test.go b/pkg/codegen/schema_test.go
new file mode 100644
index 0000000000..77c1a8751a
--- /dev/null
+++ b/pkg/codegen/schema_test.go
@@ -0,0 +1,529 @@
+package codegen
+
+import (
+ "testing"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestProperty_GoTypeDef(t *testing.T) {
+ type fields struct {
+ GlobalStateDisableRequiredReadOnlyAsPointer bool
+ Schema Schema
+ Required bool
+ Nullable bool
+ ReadOnly bool
+ WriteOnly bool
+ }
+ tests := []struct {
+ name string
+ fields fields
+ want string
+ }{
+ {
+ // When pointer is skipped by setting flag SkipOptionalPointer, the
+ // flag will never be pointer irrespective of other flags.
+ name: "Set skip optional pointer type for go type",
+ fields: fields{
+ Schema: Schema{
+ SkipOptionalPointer: true,
+ RefType: "",
+ GoType: "int",
+ },
+ },
+ want: "int",
+ },
+
+ {
+ // if the field is optional, it will always be pointer irrespective of other
+ // flags, given that pointer type is not skipped by setting SkipOptionalPointer
+ // flag to true
+ name: "When the field is optional",
+ fields: fields{
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ RefType: "",
+ GoType: "int",
+ },
+ Required: false,
+ },
+ want: "*int",
+ },
+
+ {
+ // if the field(custom-type) is optional, it will NOT be a pointer if
+ // SkipOptionalPointer flag is set to true
+ name: "Set skip optional pointer type for ref type",
+ fields: fields{
+ Schema: Schema{
+ SkipOptionalPointer: true,
+ RefType: "CustomType",
+ GoType: "int",
+ },
+ Required: false,
+ },
+ want: "CustomType",
+ },
+
+ // For the following test cases, SkipOptionalPointer flag is false.
+ {
+ name: "When field is required and not nullable",
+ fields: fields{
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ Required: true,
+ Nullable: false,
+ },
+ want: "int",
+ },
+
+ {
+ name: "When field is required and nullable",
+ fields: fields{
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ Required: true,
+ Nullable: true,
+ },
+ want: "*int",
+ },
+
+ {
+ name: "When field is optional and not nullable",
+ fields: fields{
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ Required: false,
+ Nullable: false,
+ },
+ want: "*int",
+ },
+
+ {
+ name: "When field is optional and nullable",
+ fields: fields{
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ Required: false,
+ Nullable: true,
+ },
+ want: "*int",
+ },
+
+ // Following tests cases for non-nullable and required; and skip pointer is not opted
+ {
+ name: "When field is readOnly it will always be pointer",
+ fields: fields{
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ ReadOnly: true,
+ Required: true,
+ },
+ want: "*int",
+ },
+
+ {
+ name: "When field is readOnly and read only pointer disabled",
+ fields: fields{
+ GlobalStateDisableRequiredReadOnlyAsPointer: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ ReadOnly: true,
+ Required: true,
+ },
+ want: "int",
+ },
+
+ {
+ name: "When field is readOnly and optional",
+ fields: fields{
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ ReadOnly: true,
+ Required: false,
+ },
+ want: "*int",
+ },
+ {
+ name: "When field is readOnly and optional and read only pointer disabled",
+ fields: fields{
+ GlobalStateDisableRequiredReadOnlyAsPointer: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ ReadOnly: true,
+ Required: false,
+ },
+ want: "*int",
+ },
+
+ // When field is write only, it will always be pointer unless pointer is
+ // skipped by setting SkipOptionalPointer flag
+ {
+ name: "When field is write only and read only pointer disabled",
+ fields: fields{
+ GlobalStateDisableRequiredReadOnlyAsPointer: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ WriteOnly: true,
+ },
+ want: "*int",
+ },
+
+ {
+ name: "When field is write only and read only pointer enabled",
+ fields: fields{
+ GlobalStateDisableRequiredReadOnlyAsPointer: false,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ WriteOnly: true,
+ },
+ want: "*int",
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ globalState.options.Compatibility.DisableRequiredReadOnlyAsPointer = tt.fields.GlobalStateDisableRequiredReadOnlyAsPointer
+ p := Property{
+ Schema: tt.fields.Schema,
+ Required: tt.fields.Required,
+ Nullable: tt.fields.Nullable,
+ ReadOnly: tt.fields.ReadOnly,
+ WriteOnly: tt.fields.WriteOnly,
+ }
+ assert.Equal(t, tt.want, p.GoTypeDef())
+ })
+ }
+}
+
+func TestProperty_GoTypeDef_nullable(t *testing.T) {
+ type fields struct {
+ GlobalStateDisableRequiredReadOnlyAsPointer bool
+ GlobalStateNullableType bool
+ Schema Schema
+ Required bool
+ Nullable bool
+ ReadOnly bool
+ WriteOnly bool
+ }
+ tests := []struct {
+ name string
+ fields fields
+ want string
+ }{
+ {
+ // Field not nullable.
+ // When pointer is skipped by setting flag SkipOptionalPointer, the
+ // flag will never be pointer irrespective of other flags.
+ name: "Set skip optional pointer type for go type",
+ fields: fields{
+ GlobalStateNullableType: true,
+ Schema: Schema{
+ SkipOptionalPointer: true,
+ RefType: "",
+ GoType: "int",
+ },
+ },
+ want: "int",
+ },
+
+ {
+ // Field not nullable.
+ // if the field is optional, it will always be pointer irrespective of other
+ // flags, given that pointer type is not skipped by setting SkipOptionalPointer
+ // flag to true
+ name: "When the field is optional",
+ fields: fields{
+ GlobalStateNullableType: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ RefType: "",
+ GoType: "int",
+ },
+ Required: false,
+ },
+ want: "*int",
+ },
+
+ {
+ // Field not nullable.
+ // if the field(custom type) is optional, it will NOT be a pointer if
+ // SkipOptionalPointer flag is set to true
+ name: "Set skip optional pointer type for ref type",
+ fields: fields{
+ GlobalStateNullableType: true,
+ Schema: Schema{
+ SkipOptionalPointer: true,
+ RefType: "CustomType",
+ GoType: "int",
+ },
+ Required: false,
+ },
+ want: "CustomType",
+ },
+
+ // Field not nullable.
+ // For the following test case, SkipOptionalPointer flag is false.
+ {
+ name: "When field is required and not nullable",
+ fields: fields{
+ GlobalStateNullableType: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ Required: true,
+ Nullable: false,
+ },
+ want: "int",
+ },
+
+ {
+ name: "When field is required and nullable",
+ fields: fields{
+ GlobalStateNullableType: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ Required: true,
+ Nullable: true,
+ },
+ want: "nullable.Nullable[int]",
+ },
+
+ {
+ name: "When field is optional and not nullable",
+ fields: fields{
+ GlobalStateNullableType: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ Required: false,
+ Nullable: false,
+ },
+ want: "*int",
+ },
+
+ {
+ name: "When field is optional and nullable",
+ fields: fields{
+ GlobalStateNullableType: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ Required: false,
+ Nullable: true,
+ },
+ want: "nullable.Nullable[int]",
+ },
+
+ {
+ name: "When field is readOnly, non-nullable and required and skip pointer is not opted",
+ fields: fields{
+ GlobalStateNullableType: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ ReadOnly: true,
+ Required: true,
+ },
+ want: "*int",
+ },
+
+ {
+ name: "When field is readOnly, required, non-nullable and read only pointer disabled",
+ fields: fields{
+ GlobalStateNullableType: true,
+ GlobalStateDisableRequiredReadOnlyAsPointer: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ ReadOnly: true,
+ Required: true,
+ },
+ want: "int",
+ },
+
+ {
+ name: "When field is readOnly, optional and non nullable",
+ fields: fields{
+ GlobalStateNullableType: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ ReadOnly: true,
+ Required: false,
+ },
+ want: "*int",
+ },
+ {
+ name: "When field is readOnly and optional and read only pointer disabled",
+ fields: fields{
+ GlobalStateNullableType: true,
+ GlobalStateDisableRequiredReadOnlyAsPointer: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ ReadOnly: true,
+ Required: false,
+ },
+ want: "*int",
+ },
+
+ {
+ name: "When field is write only and non nullable",
+ fields: fields{
+ GlobalStateNullableType: true,
+ GlobalStateDisableRequiredReadOnlyAsPointer: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ WriteOnly: true,
+ },
+ want: "*int",
+ },
+
+ {
+ name: "When field is write only and nullable",
+ fields: fields{
+ GlobalStateNullableType: true,
+ GlobalStateDisableRequiredReadOnlyAsPointer: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ WriteOnly: true,
+ Nullable: true,
+ },
+ want: "nullable.Nullable[int]",
+ },
+
+ {
+ name: "When field is write only, nullable and read only pointer enabled",
+ fields: fields{
+ GlobalStateNullableType: true,
+ Schema: Schema{
+ SkipOptionalPointer: false,
+ GoType: "int",
+ },
+ WriteOnly: true,
+ Nullable: true,
+ },
+ want: "nullable.Nullable[int]",
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ globalState.options.Compatibility.DisableRequiredReadOnlyAsPointer = tt.fields.GlobalStateDisableRequiredReadOnlyAsPointer
+ globalState.options.OutputOptions.NullableType = tt.fields.GlobalStateNullableType
+ p := Property{
+ Schema: tt.fields.Schema,
+ Required: tt.fields.Required,
+ Nullable: tt.fields.Nullable,
+ ReadOnly: tt.fields.ReadOnly,
+ WriteOnly: tt.fields.WriteOnly,
+ }
+ assert.Equal(t, tt.want, p.GoTypeDef())
+ })
+ }
+}
+
+func TestProperty_ZeroValueIsNil(t *testing.T) {
+ newType := func(typ string) *openapi3.Types {
+ return &openapi3.Types{typ}
+ }
+
+ tests := []struct {
+ name string
+ oapiSchema *openapi3.Schema
+ goType string
+ expectIsNil bool
+ }{
+ {
+ name: "when an array, returns true",
+ oapiSchema: &openapi3.Schema{Type: newType("array")},
+ expectIsNil: true,
+ },
+ {
+ name: "when an object, returns false",
+ oapiSchema: &openapi3.Schema{Type: newType("object")},
+ expectIsNil: false,
+ },
+ {
+ name: "when an object rendered as a map, returns true",
+ oapiSchema: &openapi3.Schema{Type: newType("object")},
+ goType: "map[string]string",
+ expectIsNil: true,
+ },
+ {
+ name: "when a string, returns false",
+ oapiSchema: &openapi3.Schema{Type: newType("string")},
+ expectIsNil: false,
+ },
+ {
+ name: "when an integer, returns false",
+ oapiSchema: &openapi3.Schema{Type: newType("integer")},
+ expectIsNil: false,
+ },
+ {
+ name: "when a number, returns false",
+ oapiSchema: &openapi3.Schema{Type: newType("number")},
+ expectIsNil: false,
+ },
+ {
+ name: "when OAPISchema is nil, returns false",
+ oapiSchema: nil,
+ expectIsNil: false,
+ },
+ {
+ name: "when OAPISchema is zero value, returns false",
+ oapiSchema: &openapi3.Schema{},
+ expectIsNil: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ prop := Property{
+ Schema: Schema{
+ OAPISchema: tt.oapiSchema,
+ GoType: tt.goType,
+ },
+ }
+ if tt.expectIsNil {
+ require.True(t, prop.ZeroValueIsNil())
+ } else {
+ require.False(t, prop.ZeroValueIsNil())
+ }
+ })
+ }
+}
diff --git a/pkg/codegen/server_urls.go b/pkg/codegen/server_urls.go
new file mode 100644
index 0000000000..b70a52fd54
--- /dev/null
+++ b/pkg/codegen/server_urls.go
@@ -0,0 +1,403 @@
+package codegen
+
+import (
+ "fmt"
+ "regexp"
+ "sort"
+ "strconv"
+ "strings"
+ "text/template"
+
+ "github.com/getkin/kin-openapi/openapi3"
+)
+
+const serverURLPrefix = "ServerUrl"
+const serverURLSuffixIterations = 10
+
+// serverURLPlaceholderRE captures `{name}` placeholders in a Server URL
+// template. Per OpenAPI 3.0.3 §4.7.7, server-variable names are bound to
+// the {name} tokens in `Server Object` URL templates; we treat anything
+// matching `{[^/{}]+}` as a placeholder candidate. The character class
+// excludes `/` so we don't accidentally span path segments, and `{`/`}`
+// so nested braces (which the spec doesn't define anyway) don't merge.
+var serverURLPlaceholderRE = regexp.MustCompile(`\{([^/{}]+)\}`)
+
+// urlPlaceholders returns the set of variable names referenced as
+// `{name}` placeholders in a Server URL template, deduplicated.
+func urlPlaceholders(url string) map[string]struct{} {
+ matches := serverURLPlaceholderRE.FindAllStringSubmatch(url, -1)
+ if len(matches) == 0 {
+ return nil
+ }
+ set := make(map[string]struct{}, len(matches))
+ for _, m := range matches {
+ set[m[1]] = struct{}{}
+ }
+ return set
+}
+
+// ServerObjectDefinition defines the definition of an OpenAPI Server object (https://spec.openapis.org/oas/v3.0.3#server-object) as it is provided to code generation in `oapi-codegen`
+type ServerObjectDefinition struct {
+ // GoName is the name of the variable for this Server URL
+ GoName string
+
+ // OAPISchema is the underlying OpenAPI representation of the Server
+ OAPISchema *openapi3.Server
+}
+
+// UsedVariables returns the subset of OAPISchema.Variables whose
+// `{name}` placeholder actually appears in OAPISchema.URL. Variables
+// declared but unused are skipped — they would otherwise produce a
+// type, constant, function parameter, and a no-op `strings.ReplaceAll`
+// (https://github.com/oapi-codegen/oapi-codegen/issues/2004). Used by
+// both server-urls.tmpl and BuildServerURLTypeDefinitions so that
+// emitted types and the generated function signature stay in sync.
+func (s ServerObjectDefinition) UsedVariables() map[string]*openapi3.ServerVariable {
+ if s.OAPISchema == nil || len(s.OAPISchema.Variables) == 0 {
+ return nil
+ }
+ placeholders := urlPlaceholders(s.OAPISchema.URL)
+ used := make(map[string]*openapi3.ServerVariable, len(s.OAPISchema.Variables))
+ for name, v := range s.OAPISchema.Variables {
+ if _, ok := placeholders[name]; ok {
+ used[name] = v
+ }
+ }
+ return used
+}
+
+// UndeclaredPlaceholders returns the sorted list of `{name}`
+// placeholder names that appear in OAPISchema.URL but have no
+// corresponding entry in OAPISchema.Variables. The previous code
+// generated a function that referenced only declared variables, so
+// any undeclared placeholder remained in the URL after substitution
+// and the trailing `{`/`}` runtime check tripped on every call —
+// making the generated function permanently unusable
+// (https://github.com/oapi-codegen/oapi-codegen/issues/2005). The
+// template now adds these as plain `string` parameters so callers
+// can fill them in directly.
+func (s ServerObjectDefinition) UndeclaredPlaceholders() []string {
+ if s.OAPISchema == nil {
+ return nil
+ }
+ placeholders := urlPlaceholders(s.OAPISchema.URL)
+ if len(placeholders) == 0 {
+ return nil
+ }
+ var undeclared []string
+ for name := range placeholders {
+ if _, declared := s.OAPISchema.Variables[name]; !declared {
+ undeclared = append(undeclared, name)
+ }
+ }
+ if len(undeclared) == 0 {
+ return nil
+ }
+ sort.Strings(undeclared)
+ return undeclared
+}
+
+// serverObjectDefinitions deconflicts server names and returns the
+// stable, deterministically-named ServerObjectDefinitions for `spec`.
+// Used by both BuildServerURLTypeDefinitions and GenerateServerURLs so
+// they generate identifiers that match.
+func serverObjectDefinitions(spec *openapi3.T) ([]ServerObjectDefinition, error) {
+ names := make(map[string]*openapi3.Server)
+
+ for _, server := range spec.Servers {
+ var name string
+ if goNameExt, ok := server.Extensions[extGoName]; ok {
+ customName, err := extParseGoFieldName(goNameExt)
+ if err != nil {
+ return nil, fmt.Errorf("invalid value for %q: %w", extGoName, err)
+ }
+ if customName != "" {
+ name = customName
+ }
+ }
+ if name == "" {
+ suffix := server.Description
+ if suffix == "" {
+ suffix = nameNormalizer(server.URL)
+ }
+ name = serverURLPrefix + UppercaseFirstCharacter(suffix)
+ name = nameNormalizer(name)
+ }
+
+ // if this is the only type with this name, store it
+ if _, conflict := names[name]; !conflict {
+ names[name] = server
+ continue
+ }
+
+ // otherwise, try appending a number to the name. Start at 1 so
+ // `Foo` / `Foo1` reads better than `Foo` / `Foo0`.
+ saved := false
+ for i := 1; i < 1+serverURLSuffixIterations; i++ {
+ suffixed := name + strconv.Itoa(i)
+ if _, suffixConflict := names[suffixed]; !suffixConflict {
+ names[suffixed] = server
+ saved = true
+ break
+ }
+ }
+
+ if saved {
+ continue
+ }
+
+ return nil, fmt.Errorf("failed to create a unique name for the Server URL (%#v) with description (%#v) after %d iterations", server.URL, server.Description, serverURLSuffixIterations)
+ }
+
+ keys := SortedMapKeys(names)
+ servers := make([]ServerObjectDefinition, len(keys))
+ for i, k := range keys {
+ servers[i] = ServerObjectDefinition{
+ GoName: k,
+ OAPISchema: names[k],
+ }
+ }
+ return servers, nil
+}
+
+// serverURLVariableTypeName returns the Go type identifier for the
+// `enum`-typed variable `varName` on the server with deconflicted Go
+// name `serverGoName`. Mirrors the naming scheme used by
+// server-urls.tmpl (`%sVariable`) so that synthesized
+// TypeDefinitions, the function signature emitted by the template,
+// and any user references all resolve to the same identifier.
+func serverURLVariableTypeName(serverGoName, varName string) string {
+ return serverGoName + UppercaseFirstCharacter(varName) + "Variable"
+}
+
+// serverURLEnumKeys returns deterministic identifier suffixes for each
+// enum value of `v`, in `v.Enum` order. Each suffix is just the value
+// with its first character upper-cased — matching what the previous
+// template-only path produced for happy-path specs (``),
+// so adopters with non-colliding enums keep their existing identifiers.
+//
+// When two values fold to the same suffix (e.g. `enum: ["foo", "FOO"]`,
+// both → `Foo`), later occurrences get a numeric suffix (`Foo`, `Foo1`,
+// `Foo2`, …) — same scheme as `SanitizeEnumNames`. The previous
+// template path didn't dedup at all and would have produced a
+// duplicate-const compile error for these specs; this is purely a
+// correctness improvement, not a naming change for any spec that
+// actually compiled before.
+func serverURLEnumKeys(v *openapi3.ServerVariable) []string {
+ keys := make([]string, len(v.Enum))
+ seen := make(map[string]int, len(v.Enum))
+ for i, val := range v.Enum {
+ base := UppercaseFirstCharacter(val)
+ if n, dup := seen[base]; dup {
+ keys[i] = base + strconv.Itoa(n)
+ seen[base] = n + 1
+ } else {
+ keys[i] = base
+ seen[base] = 1
+ }
+ }
+ return keys
+}
+
+// serverURLEnumValues returns the EnumValues map handed to GenerateEnums
+// for variable `v`: key is the deduplicated identifier suffix from
+// serverURLEnumKeys, value is the original enum string.
+func serverURLEnumValues(v *openapi3.ServerVariable) map[string]string {
+ keys := serverURLEnumKeys(v)
+ out := make(map[string]string, len(keys))
+ for i, k := range keys {
+ out[k] = v.Enum[i]
+ }
+ return out
+}
+
+// ServerURLDefaultPointer carries the pre-computed identifier names
+// needed to emit a typed default-pointer constant for an enum-typed
+// server-URL variable. Computed in Go (not the template) so that the
+// pointer's reference to the enum-value constant always agrees with
+// the identifier the const-block actually emitted, including in
+// dedup-suffix cases (e.g. `enum: ["foo", "FOO"]` with `default: "FOO"`
+// → enum const is `Foo1`, pointer must reference exactly that).
+type ServerURLDefaultPointer struct {
+ // VariableName is the OpenAPI variable name (for doc comments).
+ VariableName string
+ // TypeName is the enum's Go type, e.g. `ServerUrlFooBarVariable`.
+ TypeName string
+ // PointerName is the constant being declared. Normally it is
+ // `Default` (matching the historical naming). Switches
+ // to `DefaultValue` only when the variable's enum
+ // contains a value whose identifier suffix is the literal string
+ // "Default" — i.e. exactly the case that produced #2003's
+ // duplicate-const compile error under the old codegen. Specs that
+ // compiled cleanly before keep their `Default` name.
+ PointerName string
+ // TargetName is the fully-qualified enum-value constant that the
+ // pointer references, e.g. `N443` or `Foo1`.
+ TargetName string
+ // Description is the variable's OpenAPI description (doc comment).
+ Description string
+}
+
+// NewServerFunctionParams returns the formatted parameter list for
+// the generated `New(...)` function — one typed parameter
+// per declared-and-used variable, plus one `string` parameter per
+// `{name}` placeholder that appears in the URL but isn't in
+// `variables` (#2005). The two groups are sorted together
+// alphabetically so the generated signature is deterministic.
+//
+// Equivalent to calling `genServerURLWithVariablesFunctionParams` for
+// the typed half and concatenating the undeclared half — but exposing
+// it as a method keeps server-urls.tmpl free of that combination
+// logic and means the template helper itself stayed at its
+// pre-existing two-argument shape (so any user-supplied custom
+// `server-urls.tmpl` override that calls the helper directly is
+// unaffected).
+func (s ServerObjectDefinition) NewServerFunctionParams() string {
+ used := s.UsedVariables()
+ undeclared := s.UndeclaredPlaceholders()
+ if len(used) == 0 && len(undeclared) == 0 {
+ return ""
+ }
+
+ type param struct {
+ name string
+ typ string
+ }
+ parts := make([]param, 0, len(used)+len(undeclared))
+ for _, k := range SortedMapKeys(used) {
+ parts = append(parts, param{
+ name: k,
+ typ: serverURLVariableTypeName(s.GoName, k),
+ })
+ }
+ for _, k := range undeclared {
+ parts = append(parts, param{name: k, typ: "string"})
+ }
+ sort.Slice(parts, func(i, j int) bool { return parts[i].name < parts[j].name })
+
+ out := make([]string, len(parts))
+ for i, p := range parts {
+ out[i] = p.name + " " + p.typ
+ }
+ return strings.Join(out, ", ")
+}
+
+// EnumDefaultPointers returns one entry per enum-typed used variable
+// with a `default` set. The template iterates this directly rather
+// than recomputing identifier names from `$v.Default`.
+func (s ServerObjectDefinition) EnumDefaultPointers() []ServerURLDefaultPointer {
+ used := s.UsedVariables()
+ var out []ServerURLDefaultPointer
+ for _, varName := range SortedMapKeys(used) {
+ v := used[varName]
+ if v == nil || len(v.Enum) == 0 || v.Default == "" {
+ continue
+ }
+ keys := serverURLEnumKeys(v)
+ var targetKey string
+ for i, val := range v.Enum {
+ if val == v.Default {
+ targetKey = keys[i]
+ break
+ }
+ }
+ if targetKey == "" {
+ // `default` not in `enum`; BuildServerURLTypeDefinitions
+ // already errors on this at codegen time, so we'd never
+ // actually reach the template emission. Skip defensively.
+ continue
+ }
+ prefix := serverURLVariableTypeName(s.GoName, varName)
+ pointerName := prefix + "Default"
+ for _, k := range keys {
+ if k == "Default" {
+ pointerName = prefix + "DefaultValue"
+ break
+ }
+ }
+ out = append(out, ServerURLDefaultPointer{
+ VariableName: varName,
+ TypeName: prefix,
+ PointerName: pointerName,
+ TargetName: prefix + targetKey,
+ Description: v.Description,
+ })
+ }
+ return out
+}
+
+// BuildServerURLTypeDefinitions synthesizes a TypeDefinition for every
+// server-URL variable that defines an `enum`. These are appended into
+// the same TypeDefinition slices used by GenerateTypes (typedef.tmpl)
+// and GenerateEnums (constants.tmpl), so that server-URL enum
+// variables get the same `type X string`, `const ( … )` block, and
+// `Valid()` method as any other enum-bearing schema. The
+// server-urls.tmpl template no longer emits these declarations
+// directly.
+//
+// Variables without an `enum` are not handled here: server-urls.tmpl
+// continues to emit their `type` and (optional) default constant
+// inline, since the generic enum path has nothing to contribute for a
+// non-enum string.
+func BuildServerURLTypeDefinitions(spec *openapi3.T) ([]TypeDefinition, error) {
+ servers, err := serverObjectDefinitions(spec)
+ if err != nil {
+ return nil, err
+ }
+
+ var defs []TypeDefinition
+ for _, srv := range servers {
+ used := srv.UsedVariables()
+ // Iterate variables in deterministic order.
+ for _, varName := range SortedMapKeys(used) {
+ v := used[varName]
+ if v == nil || len(v.Enum) == 0 {
+ continue
+ }
+ // Validate that `default`, if set, is one of the
+ // declared `enum` values. Per OpenAPI 3.0.3 §4.7.10,
+ // the default MUST be in the enum list when both are
+ // present; the previous template trusted the spec
+ // blindly and emitted a const referencing an
+ // undeclared identifier when the spec violated the
+ // rule, producing a confusing user-side compile error
+ // (https://github.com/oapi-codegen/oapi-codegen/issues/2007).
+ // Catch the violation at codegen time so the user sees
+ // a clear message pointing at their spec.
+ if v.Default != "" {
+ inEnum := false
+ for _, ev := range v.Enum {
+ if ev == v.Default {
+ inEnum = true
+ break
+ }
+ }
+ if !inEnum {
+ return nil, fmt.Errorf("server URL %q: variable %q has default value %q which is not one of the declared enum values %v",
+ srv.OAPISchema.URL, varName, v.Default, v.Enum)
+ }
+ }
+ typeName := serverURLVariableTypeName(srv.GoName, varName)
+ enumValues := serverURLEnumValues(v)
+ defs = append(defs, TypeDefinition{
+ TypeName: typeName,
+ JsonName: varName,
+ Schema: Schema{
+ GoType: "string",
+ EnumValues: enumValues,
+ Description: v.Description,
+ },
+ ForceEnumPrefix: true,
+ })
+ }
+ }
+ return defs, nil
+}
+
+func GenerateServerURLs(t *template.Template, spec *openapi3.T) (string, error) {
+ servers, err := serverObjectDefinitions(spec)
+ if err != nil {
+ return "", err
+ }
+ return GenerateTemplates([]string{"server-urls.tmpl"}, t, servers)
+}
diff --git a/pkg/codegen/server_urls_test.go b/pkg/codegen/server_urls_test.go
new file mode 100644
index 0000000000..1fbc7e4577
--- /dev/null
+++ b/pkg/codegen/server_urls_test.go
@@ -0,0 +1,348 @@
+package codegen
+
+import (
+ "go/ast"
+ "go/parser"
+ "go/token"
+ "testing"
+ "text/template"
+
+ "github.com/getkin/kin-openapi/openapi3"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+func TestURLPlaceholders(t *testing.T) {
+ t.Run("returns nil for a URL with no placeholders", func(t *testing.T) {
+ assert.Nil(t, urlPlaceholders("https://api.example.com/v1"))
+ })
+
+ t.Run("extracts a single placeholder", func(t *testing.T) {
+ got := urlPlaceholders("https://{host}.example.com/v1")
+ assert.Len(t, got, 1)
+ assert.Contains(t, got, "host")
+ })
+
+ t.Run("extracts multiple placeholders and dedupes repeats", func(t *testing.T) {
+ got := urlPlaceholders("https://{host}.example.com:{port}/{base}/{host}")
+ assert.Len(t, got, 3)
+ assert.Contains(t, got, "host")
+ assert.Contains(t, got, "port")
+ assert.Contains(t, got, "base")
+ })
+
+ t.Run("does not span across `/`", func(t *testing.T) {
+ // "{a/b}" must not be treated as a single placeholder named "a/b".
+ assert.Nil(t, urlPlaceholders("https://{a/b}.example.com"))
+ })
+}
+
+func TestUsedAndUndeclaredVariables(t *testing.T) {
+ srv := ServerObjectDefinition{
+ GoName: "ServerUrlExample",
+ OAPISchema: &openapi3.Server{
+ URL: "https://{host}.example.com:{port}/{path}",
+ Variables: map[string]*openapi3.ServerVariable{
+ "host": {Default: "demo"},
+ "port": {Default: "443", Enum: []string{"443", "8443"}},
+ "unused": {Default: "x"}, // declared, but not referenced in URL
+ // "path" is referenced in URL but not declared
+ },
+ },
+ }
+
+ used := srv.UsedVariables()
+ assert.Len(t, used, 2)
+ assert.Contains(t, used, "host")
+ assert.Contains(t, used, "port")
+ assert.NotContains(t, used, "unused", "declared-but-unused must be filtered (#2004)")
+
+ undeclared := srv.UndeclaredPlaceholders()
+ assert.Equal(t, []string{"path"}, undeclared, "URL placeholder not in variables must be reported (#2005)")
+}
+
+// renderServerURLs parses the embedded templates and renders the
+// server-urls template for spec, mirroring the setup in Generate.
+func renderServerURLs(t *testing.T, spec *openapi3.T) string {
+ t.Helper()
+ // Generate registers `opts` before parsing; mirror that here so the
+ // (unrelated) framework templates parse cleanly.
+ TemplateFunctions["opts"] = func() Configuration { return globalState.options }
+ tmpl := template.New("oapi-codegen").Funcs(TemplateFunctions)
+ require.NoError(t, LoadTemplates(templates, tmpl))
+ out, err := GenerateServerURLs(tmpl, spec)
+ require.NoError(t, err)
+ return out
+}
+
+// injectSentinel is the identifier a malicious spec tries to smuggle in
+// as a real top-level declaration. The two escape techniques covered are:
+// - a newline that breaks out of a `//` line comment, and
+// - a `"` that breaks out of a `const … = "…"` string literal,
+//
+// both of which would land `var injectSentinel = …` at package scope.
+const injectSentinel = "OapiCodegenInjectedPwned"
+
+// TestServerURLInjection checks that attacker-controlled spec text (server
+// description, URL, and variable default), which flows into generated Go line
+// comments and string literals, cannot break out into an executable top-level
+// declaration.
+func TestServerURLInjection(t *testing.T) {
+ // commentBreakout escapes a `//` comment, declares the sentinel, then
+ // re-opens a comment so the surrounding template text stays valid.
+ commentBreakout := "benign\nvar " + injectSentinel + " = 1\n//"
+ // literalBreakout escapes a `"…"` string literal, declares the
+ // sentinel, then re-opens a literal to swallow the template's closing
+ // quote.
+ literalBreakout := `https://api.example.com"; var ` + injectSentinel + ` = 1; var _ = "`
+
+ t.Run("newline in description cannot escape the doc comment", func(t *testing.T) {
+ out := renderServerURLs(t, &openapi3.T{Servers: openapi3.Servers{
+ {URL: "https://api.example.com", Description: commentBreakout},
+ }})
+ assertSentinelNotDeclared(t, out)
+ })
+
+ t.Run("description in the function (variable-bearing) form cannot escape", func(t *testing.T) {
+ out := renderServerURLs(t, &openapi3.T{Servers: openapi3.Servers{
+ {URL: "https://api.example.com/{tenant}", Description: commentBreakout},
+ }})
+ assertSentinelNotDeclared(t, out)
+ })
+
+ t.Run("quote in URL cannot escape the const string literal", func(t *testing.T) {
+ out := renderServerURLs(t, &openapi3.T{Servers: openapi3.Servers{
+ {URL: literalBreakout},
+ }})
+ assertSentinelNotDeclared(t, out)
+ })
+
+ t.Run("quote in a variable default cannot escape the const string literal", func(t *testing.T) {
+ out := renderServerURLs(t, &openapi3.T{Servers: openapi3.Servers{
+ {
+ URL: "https://api.example.com/{base}",
+ Variables: map[string]*openapi3.ServerVariable{
+ // non-enum, used → emits `const …BaseVariableDefault = ""`
+ "base": {Default: `v2"; var ` + injectSentinel + ` = 1; var _ = "`},
+ },
+ },
+ }})
+ assertSentinelNotDeclared(t, out)
+ })
+}
+
+// assertSentinelNotDeclared parses the generated output as a package body
+// and fails if it is not valid Go or if injectSentinel appears as a
+// top-level declared identifier (i.e. the payload escaped its comment or
+// string literal and became real source).
+func assertSentinelNotDeclared(t *testing.T, out string) {
+ t.Helper()
+ src := "package p\n" + out
+ fset := token.NewFileSet()
+ file, err := parser.ParseFile(fset, "gen.go", src, parser.ParseComments)
+ require.NoError(t, err, "generated output must parse as valid Go:\n%s", src)
+
+ for _, name := range topLevelDeclNames(file) {
+ assert.NotEqual(t, injectSentinel, name,
+ "injected identifier became a real top-level declaration:\n%s", src)
+ }
+}
+
+// topLevelDeclNames returns every identifier declared at file scope.
+func topLevelDeclNames(file *ast.File) []string {
+ var names []string
+ for _, decl := range file.Decls {
+ switch d := decl.(type) {
+ case *ast.FuncDecl:
+ names = append(names, d.Name.Name)
+ case *ast.GenDecl:
+ for _, spec := range d.Specs {
+ switch s := spec.(type) {
+ case *ast.ValueSpec:
+ for _, n := range s.Names {
+ names = append(names, n.Name)
+ }
+ case *ast.TypeSpec:
+ names = append(names, s.Name.Name)
+ }
+ }
+ }
+ }
+ return names
+}
+
+func TestBuildServerURLTypeDefinitions(t *testing.T) {
+ t.Run("synthesises one TypeDefinition per enum-typed used variable", func(t *testing.T) {
+ spec := &openapi3.T{
+ Servers: openapi3.Servers{
+ {
+ URL: "https://api.example.com:{port}",
+ Variables: map[string]*openapi3.ServerVariable{
+ "port": {Default: "443", Enum: []string{"443", "8443"}},
+ },
+ },
+ },
+ }
+ defs, err := BuildServerURLTypeDefinitions(spec)
+ require.NoError(t, err)
+ require.Len(t, defs, 1)
+ assert.True(t, defs[0].ForceEnumPrefix, "server-URL enum types must keep prefixed identifiers")
+ assert.Equal(t, "string", defs[0].Schema.GoType)
+ assert.Len(t, defs[0].Schema.EnumValues, 2)
+ })
+
+ t.Run("skips non-enum variables", func(t *testing.T) {
+ spec := &openapi3.T{
+ Servers: openapi3.Servers{
+ {
+ URL: "https://{host}.example.com",
+ Variables: map[string]*openapi3.ServerVariable{
+ "host": {Default: "demo"}, // no enum
+ },
+ },
+ },
+ }
+ defs, err := BuildServerURLTypeDefinitions(spec)
+ require.NoError(t, err)
+ assert.Empty(t, defs)
+ })
+
+ t.Run("skips declared-but-unused variables (#2004)", func(t *testing.T) {
+ spec := &openapi3.T{
+ Servers: openapi3.Servers{
+ {
+ URL: "https://api.example.com",
+ Variables: map[string]*openapi3.ServerVariable{
+ "unused": {Default: "443", Enum: []string{"443", "8443"}},
+ },
+ },
+ },
+ }
+ defs, err := BuildServerURLTypeDefinitions(spec)
+ require.NoError(t, err)
+ assert.Empty(t, defs)
+ })
+
+ t.Run("errors when default is not in enum (#2007)", func(t *testing.T) {
+ spec := &openapi3.T{
+ Servers: openapi3.Servers{
+ {
+ URL: "https://api.example.com:{port}",
+ Description: "Production API server",
+ Variables: map[string]*openapi3.ServerVariable{
+ "port": {Default: "12345", Enum: []string{"443", "8443"}},
+ },
+ },
+ },
+ }
+ _, err := BuildServerURLTypeDefinitions(spec)
+ require.Error(t, err)
+ assert.Contains(t, err.Error(), "port")
+ assert.Contains(t, err.Error(), "12345")
+ })
+
+ t.Run("an enum value 'default' does not collide with the default-pointer (#2003)", func(t *testing.T) {
+ // Routing through GenerateEnums + emitting the default-pointer
+ // const with the asymmetric `…DefaultValue` rename means an
+ // enum literal "default" no longer produces a duplicate const
+ // declaration with the default pointer.
+ spec := &openapi3.T{
+ Servers: openapi3.Servers{
+ {
+ URL: "https://api.example.com:{port}",
+ Variables: map[string]*openapi3.ServerVariable{
+ "port": {Default: "default", Enum: []string{"default", "443"}},
+ },
+ },
+ },
+ }
+ defs, err := BuildServerURLTypeDefinitions(spec)
+ require.NoError(t, err)
+ require.Len(t, defs, 1)
+ assert.Len(t, defs[0].Schema.EnumValues, 2)
+ })
+}
+
+// TestEnumDefaultPointers verifies the asymmetric default-pointer
+// naming and the dedup-aware target reference — the two behaviours
+// raised in the PR #2358 review.
+func TestEnumDefaultPointers(t *testing.T) {
+ t.Run("happy-path enum keeps the historical `…Default` name", func(t *testing.T) {
+ // No enum value folds to the literal "Default", so there's no
+ // collision and the default-pointer keeps the pre-fix name.
+ // This is the asymmetric-rename criterion: only specs that
+ // would have collided under the old codegen see the rename.
+ srv := ServerObjectDefinition{
+ GoName: "ServerUrlExample",
+ OAPISchema: &openapi3.Server{
+ URL: "https://api.example.com:{port}",
+ Variables: map[string]*openapi3.ServerVariable{
+ "port": {Default: "8443", Enum: []string{"443", "8443"}},
+ },
+ },
+ }
+ ptrs := srv.EnumDefaultPointers()
+ require.Len(t, ptrs, 1)
+ assert.Equal(t, "ServerUrlExamplePortVariableDefault", ptrs[0].PointerName)
+ assert.Equal(t, "ServerUrlExamplePortVariable8443", ptrs[0].TargetName)
+ })
+
+ t.Run("colliding enum value triggers `…DefaultValue` rename (#2003)", func(t *testing.T) {
+ srv := ServerObjectDefinition{
+ GoName: "ServerUrlExample",
+ OAPISchema: &openapi3.Server{
+ URL: "https://api.example.com/{port}",
+ Variables: map[string]*openapi3.ServerVariable{
+ "port": {Default: "default", Enum: []string{"default", "443"}},
+ },
+ },
+ }
+ ptrs := srv.EnumDefaultPointers()
+ require.Len(t, ptrs, 1)
+ assert.Equal(t, "ServerUrlExamplePortVariableDefaultValue", ptrs[0].PointerName)
+ assert.Equal(t, "ServerUrlExamplePortVariableDefault", ptrs[0].TargetName,
+ "the target const for value \"default\" is …VariableDefault; the pointer is …VariableDefaultValue and references it")
+ })
+
+ t.Run("dedup-suffix value is referenced by the right name", func(t *testing.T) {
+ // `enum: [foo, Foo]` both `ucFirst`-fold to `Foo`; the second
+ // becomes `Foo1`. With `default: "Foo"` the pointer must
+ // reference …VariableFoo1, not …VariableFoo (which holds "foo").
+ // Greptile flagged this in PR #2358 review.
+ srv := ServerObjectDefinition{
+ GoName: "ServerUrlExample",
+ OAPISchema: &openapi3.Server{
+ URL: "https://api.example.com/{mode}",
+ Variables: map[string]*openapi3.ServerVariable{
+ "mode": {Default: "Foo", Enum: []string{"foo", "Foo"}},
+ },
+ },
+ }
+ ptrs := srv.EnumDefaultPointers()
+ require.Len(t, ptrs, 1)
+ assert.Equal(t, "ServerUrlExampleModeVariableDefault", ptrs[0].PointerName,
+ "no enum value folds to `Default`, so no rename")
+ assert.Equal(t, "ServerUrlExampleModeVariableFoo1", ptrs[0].TargetName,
+ "target must be the post-suffix const for `Foo`, not the unsuffixed `Foo` which holds `foo`")
+ })
+
+ t.Run("digit-leading enum values do not pick up an `N` prefix", func(t *testing.T) {
+ // The previous PR-2358 implementation routed values through
+ // SchemaNameToTypeName, which prefixed digit-leading values
+ // with `N`. The current synthesis uses UppercaseFirstCharacter
+ // directly, so `8443` stays `8443` — preserving the
+ // pre-fix-PR identifier shape for happy-path adopters.
+ srv := ServerObjectDefinition{
+ GoName: "ServerUrlExample",
+ OAPISchema: &openapi3.Server{
+ URL: "https://api.example.com:{port}",
+ Variables: map[string]*openapi3.ServerVariable{
+ "port": {Default: "443", Enum: []string{"443", "8443"}},
+ },
+ },
+ }
+ ptrs := srv.EnumDefaultPointers()
+ require.Len(t, ptrs, 1)
+ assert.Equal(t, "ServerUrlExamplePortVariable443", ptrs[0].TargetName)
+ })
+}
diff --git a/pkg/codegen/template_helpers.go b/pkg/codegen/template_helpers.go
index 9ca697e864..a72d2911ce 100644
--- a/pkg/codegen/template_helpers.go
+++ b/pkg/codegen/template_helpers.go
@@ -17,12 +17,16 @@ import (
"bytes"
"fmt"
"os"
+ "slices"
"strings"
"text/template"
- "github.com/deepmap/oapi-codegen/pkg/util"
"golang.org/x/text/cases"
"golang.org/x/text/language"
+
+ "github.com/getkin/kin-openapi/openapi3"
+
+ "github.com/oapi-codegen/oapi-codegen/v2/pkg/util"
)
const (
@@ -43,6 +47,28 @@ var (
titleCaser = cases.Title(language.English)
)
+// isMediaTypeSupported reports whether code generation produces a typed
+// body for this media type. Today this is the closed set of JSON / YAML /
+// XML variants the response and request templates know how to handle —
+// see the typeName switch in GetResponseTypeDefinitions and the body
+// definition switch in GenerateBodyDefinitions. A future configuration
+// option is intended to let users extend this list.
+func isMediaTypeSupported(mediaType string) bool {
+ switch {
+ case slices.Contains(contentTypesHalJSON, mediaType):
+ return true
+ case slices.Contains(contentTypesJSON, mediaType):
+ return true
+ case util.IsMediaTypeJson(mediaType):
+ return true
+ case slices.Contains(contentTypesYAML, mediaType):
+ return true
+ case slices.Contains(contentTypesXML, mediaType):
+ return true
+ }
+ return false
+}
+
// genParamArgs takes an array of Parameter definition, and generates a valid
// Go parameter declaration from them, eg:
// ", foo int, bar string, baz float32". The preceding comma is there to save
@@ -122,8 +148,8 @@ func genResponseUnmarshal(op *OperationDefinition) string {
responses := op.Spec.Responses
for _, typeDefinition := range typeDefinitions {
- responseRef, ok := responses[typeDefinition.ResponseName]
- if !ok {
+ responseRef := responses.Value(typeDefinition.ResponseName)
+ if responseRef == nil {
continue
}
@@ -142,15 +168,15 @@ func genResponseUnmarshal(op *OperationDefinition) string {
}
// If we made it this far then we need to handle unmarshaling for each content-type:
- sortedContentKeys := SortedContentKeys(responseRef.Value.Content)
+ SortedMapKeys := SortedMapKeys(responseRef.Value.Content)
jsonCount := 0
- for _, contentTypeName := range sortedContentKeys {
- if StringInArray(contentTypeName, contentTypesJSON) || util.IsMediaTypeJson(contentTypeName) {
+ for _, contentTypeName := range SortedMapKeys {
+ if slices.Contains(contentTypesJSON, contentTypeName) || util.IsMediaTypeJson(contentTypeName) {
jsonCount++
}
}
- for _, contentTypeName := range sortedContentKeys {
+ for _, contentTypeName := range SortedMapKeys {
// We get "interface{}" when using "anyOf" or "oneOf" (which doesn't work with Go types):
if typeDefinition.TypeName == "interface{}" {
@@ -162,7 +188,7 @@ func genResponseUnmarshal(op *OperationDefinition) string {
switch {
// JSON:
- case StringInArray(contentTypeName, contentTypesJSON) || util.IsMediaTypeJson(contentTypeName):
+ case slices.Contains(contentTypesJSON, contentTypeName) || util.IsMediaTypeJson(contentTypeName):
if typeDefinition.ContentTypeName == contentTypeName {
caseAction := fmt.Sprintf("var dest %s\n"+
"if err := json.Unmarshal(bodyBytes, &dest); err != nil { \n"+
@@ -182,7 +208,7 @@ func genResponseUnmarshal(op *OperationDefinition) string {
}
// YAML:
- case StringInArray(contentTypeName, contentTypesYAML):
+ case slices.Contains(contentTypesYAML, contentTypeName):
if typeDefinition.ContentTypeName == contentTypeName {
caseAction := fmt.Sprintf("var dest %s\n"+
"if err := yaml.Unmarshal(bodyBytes, &dest); err != nil { \n"+
@@ -196,7 +222,7 @@ func genResponseUnmarshal(op *OperationDefinition) string {
}
// XML:
- case StringInArray(contentTypeName, contentTypesXML):
+ case slices.Contains(contentTypesXML, contentTypeName):
if typeDefinition.ContentTypeName == contentTypeName {
caseAction := fmt.Sprintf("var dest %s\n"+
"if err := xml.Unmarshal(bodyBytes, &dest); err != nil { \n"+
@@ -224,14 +250,14 @@ func genResponseUnmarshal(op *OperationDefinition) string {
}
// Now build the switch statement in order of most-to-least specific:
- // See: https://github.com/deepmap/oapi-codegen/issues/127 for why we handle this in two separate
+ // See: https://github.com/oapi-codegen/oapi-codegen/issues/127 for why we handle this in two separate
// groups.
fmt.Fprintf(buffer, "switch {\n")
- for _, caseClauseKey := range SortedStringKeys(handledCaseClauses) {
+ for _, caseClauseKey := range SortedMapKeys(handledCaseClauses) {
fmt.Fprintf(buffer, "%s\n", handledCaseClauses[caseClauseKey])
}
- for _, caseClauseKey := range SortedStringKeys(unhandledCaseClauses) {
+ for _, caseClauseKey := range SortedMapKeys(unhandledCaseClauses) {
fmt.Fprintf(buffer, "%s\n", unhandledCaseClauses[caseClauseKey])
}
@@ -244,19 +270,26 @@ func genResponseUnmarshal(op *OperationDefinition) string {
func buildUnmarshalCase(typeDefinition ResponseTypeDefinition, caseAction string, contentType string) (caseKey string, caseClause string) {
caseKey = fmt.Sprintf("%s.%s.%s", prefixLeastSpecific, contentType, typeDefinition.ResponseName)
caseClauseKey := getConditionOfResponseName("rsp.StatusCode", typeDefinition.ResponseName)
- caseClause = fmt.Sprintf("case strings.Contains(rsp.Header.Get(\"%s\"), \"%s\") && %s:\n%s\n", "Content-Type", contentType, caseClauseKey, caseAction)
+ contentTypeLiteral := StringToGoString(contentType)
+ caseClause = fmt.Sprintf("case strings.Contains(rsp.Header.Get(\"%s\"), %s) && %s:\n%s\n", "Content-Type", contentTypeLiteral, caseClauseKey, caseAction)
return caseKey, caseClause
}
func buildUnmarshalCaseStrict(typeDefinition ResponseTypeDefinition, caseAction string, contentType string) (caseKey string, caseClause string) {
caseKey = fmt.Sprintf("%s.%s.%s", prefixLeastSpecific, contentType, typeDefinition.ResponseName)
caseClauseKey := getConditionOfResponseName("rsp.StatusCode", typeDefinition.ResponseName)
- caseClause = fmt.Sprintf("case rsp.Header.Get(\"%s\") == \"%s\" && %s:\n%s\n", "Content-Type", contentType, caseClauseKey, caseAction)
+ contentTypeLiteral := StringToGoString(contentType)
+ caseClause = fmt.Sprintf("case rsp.Header.Get(\"%s\") == %s && %s:\n%s\n", "Content-Type", contentTypeLiteral, caseClauseKey, caseAction)
return caseKey, caseClause
}
-// genResponseTypeName creates the name of generated response types (given the operationID):
+// genResponseTypeName creates the name of generated response types (given the operationID).
+// It first checks if the multi-pass name resolver has assigned a name for this
+// wrapper type (which would happen if the default name collides with a schema type).
func genResponseTypeName(operationID string) string {
+ if name, ok := globalState.resolvedClientWrapperNames[operationID]; ok {
+ return name
+ }
return fmt.Sprintf("%s%s", UppercaseFirstCharacter(operationID), responseTypeSuffix)
}
@@ -289,11 +322,65 @@ func toStringArray(sarr []string) string {
return `[]string{` + s + `}`
}
+// stripNewLines removes newlines so untrusted spec text stays inside a single
+// generated `//` line comment instead of breaking out into real Go source.
func stripNewLines(s string) string {
- r := strings.NewReplacer("\n", "")
+ r := strings.NewReplacer("\n", "", "\r", "")
return r.Replace(s)
}
+// genServerURLWithVariablesFunctionParams is a template helper method to generate the function parameters for the generated function for a Server object that contains `variables` (https://spec.openapis.org/oas/v3.0.3#server-object)
+//
+// goTypePrefix is the prefix being used to create underlying types in the template (likely the `ServerObjectDefinition.GoName`)
+// variables are this `ServerObjectDefinition`'s variables for the Server object (likely the `ServerObjectDefinition.OAPISchema`)
+//
+// Undeclared `{name}` placeholders that appear in the URL but have no
+// entry in `variables` are NOT handled here; they're emitted as plain
+// `string` parameters by `ServerObjectDefinition.NewFunctionParams`,
+// which the template calls instead of this helper. Custom
+// `server-urls.tmpl` overrides that still call this helper directly
+// keep their pre-existing two-argument signature.
+func genServerURLWithVariablesFunctionParams(goTypePrefix string, variables map[string]*openapi3.ServerVariable) string {
+ keys := SortedMapKeys(variables)
+
+ if len(variables) == 0 {
+ return ""
+ }
+ parts := make([]string, len(variables))
+
+ for i := range keys {
+ k := keys[i]
+ variableDefinitionPrefix := goTypePrefix + UppercaseFirstCharacter(k) + "Variable"
+ parts[i] = k + " " + variableDefinitionPrefix
+ }
+ return strings.Join(parts, ", ")
+}
+
+// httpMethodConstant converts an HTTP method string (e.g. "GET") to the
+// corresponding Go net/http constant (e.g. "http.MethodGet").
+func httpMethodConstant(method string) string {
+ switch method {
+ case "GET":
+ return "http.MethodGet"
+ case "POST":
+ return "http.MethodPost"
+ case "PUT":
+ return "http.MethodPut"
+ case "DELETE":
+ return "http.MethodDelete"
+ case "PATCH":
+ return "http.MethodPatch"
+ case "HEAD":
+ return "http.MethodHead"
+ case "OPTIONS":
+ return "http.MethodOptions"
+ case "TRACE":
+ return "http.MethodTrace"
+ default:
+ return fmt.Sprintf("%q", method)
+ }
+}
+
// TemplateFunctions is passed to the template engine, and we can call each
// function here by keyName from the template code.
var TemplateFunctions = template.FuncMap{
@@ -307,6 +394,7 @@ var TemplateFunctions = template.FuncMap{
"swaggerUriToChiUri": SwaggerUriToChiUri,
"swaggerUriToGinUri": SwaggerUriToGinUri,
"swaggerUriToGorillaUri": SwaggerUriToGorillaUri,
+ "swaggerUriToStdHttpUri": SwaggerUriToStdHttpUri,
"lcFirst": LowercaseFirstCharacter,
"ucFirst": UppercaseFirstCharacter,
"ucFirstWithPkgName": UppercaseFirstCharacterWithPkgName,
@@ -320,5 +408,10 @@ var TemplateFunctions = template.FuncMap{
"title": titleCaser.String,
"stripNewLines": stripNewLines,
"sanitizeGoIdentity": SanitizeGoIdentity,
+ "schemaNameToTypeName": SchemaNameToTypeName,
+ "toGoString": StringToGoString,
"toGoComment": StringWithTypeNameToGoComment,
+
+ "genServerURLWithVariablesFunctionParams": genServerURLWithVariablesFunctionParams,
+ "httpMethodConstant": httpMethodConstant,
}
diff --git a/pkg/codegen/templates/additional-properties.tmpl b/pkg/codegen/templates/additional-properties.tmpl
index 7b7c0ace4b..a103216c94 100644
--- a/pkg/codegen/templates/additional-properties.tmpl
+++ b/pkg/codegen/templates/additional-properties.tmpl
@@ -53,12 +53,12 @@ func (a {{.TypeName}}) MarshalJSON() ([]byte, error) {
var err error
object := make(map[string]json.RawMessage)
{{range .Schema.Properties}}
-{{if not .Required}}if a.{{.GoFieldName}} != nil { {{end}}
+{{if .RequiresNilCheck}}if a.{{.GoFieldName}} != nil { {{end}}
object["{{.JsonFieldName}}"], err = json.Marshal(a.{{.GoFieldName}})
if err != nil {
return nil, fmt.Errorf("error marshaling '{{.JsonFieldName}}': %w", err)
}
-{{if not .Required}} }{{end}}
+{{if .RequiresNilCheck}} }{{end}}
{{end}}
for fieldName, field := range a.AdditionalProperties {
object[fieldName], err = json.Marshal(field)
@@ -69,4 +69,4 @@ func (a {{.TypeName}}) MarshalJSON() ([]byte, error) {
return json.Marshal(object)
}
{{end}}
-{{end}}
\ No newline at end of file
+{{end}}
diff --git a/pkg/codegen/templates/chi/chi-handler.tmpl b/pkg/codegen/templates/chi/chi-handler.tmpl
index 113e4d7ada..72c57a6be6 100644
--- a/pkg/codegen/templates/chi/chi-handler.tmpl
+++ b/pkg/codegen/templates/chi/chi-handler.tmpl
@@ -43,7 +43,7 @@ ErrorHandlerFunc: options.ErrorHandlerFunc,
}
{{end}}
{{range .}}r.Group(func(r chi.Router) {
-r.{{.Method | lower | title }}(options.BaseURL+"{{.Path | swaggerUriToChiUri}}", wrapper.{{.OperationId}})
+r.{{.Method | lower | title }}(options.BaseURL+"{{.Path | swaggerUriToChiUri}}", wrapper.{{.HandlerName}})
})
{{end}}
return r
diff --git a/pkg/codegen/templates/chi/chi-interface.tmpl b/pkg/codegen/templates/chi/chi-interface.tmpl
index cfc393bde2..bec8452e75 100644
--- a/pkg/codegen/templates/chi/chi-interface.tmpl
+++ b/pkg/codegen/templates/chi/chi-interface.tmpl
@@ -1,17 +1,17 @@
// ServerInterface represents all server handlers.
type ServerInterface interface {
-{{range .}}{{.SummaryAsComment }}
+{{range .}}{{if not .IsAlias}}{{.SummaryAsComment }}
// ({{.Method}} {{.Path}})
{{.OperationId}}(w http.ResponseWriter, r *http.Request{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}})
-{{end}}
+{{end}}{{end}}
}
// Unimplemented server implementation that returns http.StatusNotImplemented for each endpoint.
type Unimplemented struct {}
- {{range .}}{{.SummaryAsComment }}
+ {{range .}}{{if not .IsAlias}}{{.SummaryAsComment }}
// ({{.Method}} {{.Path}})
func (_ Unimplemented) {{.OperationId}}(w http.ResponseWriter, r *http.Request{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) {
w.WriteHeader(http.StatusNotImplemented)
}
- {{end}}
\ No newline at end of file
+ {{end}}{{end}}
\ No newline at end of file
diff --git a/pkg/codegen/templates/chi/chi-middleware.tmpl b/pkg/codegen/templates/chi/chi-middleware.tmpl
index 313122a36e..08402e2aca 100644
--- a/pkg/codegen/templates/chi/chi-middleware.tmpl
+++ b/pkg/codegen/templates/chi/chi-middleware.tmpl
@@ -8,12 +8,12 @@ type ServerInterfaceWrapper struct {
type MiddlewareFunc func(http.Handler) http.Handler
{{range .}}{{$opid := .OperationId}}
-
+{{if not .IsAlias}}
// {{$opid}} operation middleware
func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
{{if or .RequiresParamObject (gt (len .PathParams) 0) }}
var err error
+ _ = err
{{end}}
{{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" -------------
@@ -30,7 +30,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
}
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationPath, chi.URLParam(r, "{{.ParamName}}"), &{{$varName}})
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", chi.URLParam(r, "{{.ParamName}}"), &{{$varName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
return
@@ -39,9 +39,13 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
+ {{if .SecurityDefinitions -}}
+ ctx := r.Context()
{{range .SecurityDefinitions}}
ctx = context.WithValue(ctx, {{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}})
{{end}}
+ r = r.WithContext(ctx)
+ {{end}}
{{if .RequiresParamObject}}
// Parameter object where we will unmarshal all parameters from the context
@@ -51,11 +55,11 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{- if (or (or .Required .IsPassThrough) (or .IsJson .IsStyled)) -}}
// ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
{{ end }}
- {{ if (or (or .Required .IsPassThrough) .IsJson) }}
+ {{ if (or .IsPassThrough .IsJson) }}
if paramValue := r.URL.Query().Get("{{.ParamName}}"); paramValue != "" {
{{if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}paramValue
{{end}}
{{if .IsJson}}
@@ -66,7 +70,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
return
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
}{{if .Required}} else {
siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"})
@@ -74,9 +78,14 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
}{{end}}
{{end}}
{{if .IsStyled}}
- err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", r.URL.Query(), ¶ms.{{.GoName}})
+ err = runtime.BindQueryParameterWithOptions("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", r.URL.Query(), ¶ms.{{.GoName}}, runtime.BindQueryParameterOptions{Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
- siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
+ }
return
}
{{end}}
@@ -95,7 +104,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
}
{{if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}valueList[0]
+ params.{{.GoName}} = {{if .HasOptionalPointer }}&{{end}}valueList[0]
{{end}}
{{if .IsJson}}
@@ -107,14 +116,14 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, valueList[0], &{{.GoName}})
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", valueList[0], &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
return
}
{{end}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}}
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}{{.GoName}}
} {{if .Required}}else {
err := fmt.Errorf("Header parameter {{.ParamName}} is required, but not found")
@@ -126,12 +135,13 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
{{range .CookieParams}}
+ {
var cookie *http.Cookie
if cookie, err = r.Cookie("{{.ParamName}}"); err == nil {
{{- if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}cookie.Value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}cookie.Value
{{end}}
{{- if .IsJson}}
@@ -150,17 +160,17 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
return
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
{{- if .IsStyled}}
var value {{.TypeDef}}
- err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie.Value, &value)
+ err = runtime.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
return
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
}
@@ -170,6 +180,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
return
}
{{- end}}
+ }
{{end}}
{{end}}
@@ -187,9 +198,9 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
}
{{end}}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
-{{end}}
+{{end}}{{end}}
type UnescapedCookieParamError struct {
ParamName string
diff --git a/pkg/codegen/templates/client-with-responses.tmpl b/pkg/codegen/templates/client-with-responses.tmpl
index c0b3ca5688..b2c9546639 100644
--- a/pkg/codegen/templates/client-with-responses.tmpl
+++ b/pkg/codegen/templates/client-with-responses.tmpl
@@ -44,14 +44,29 @@ type ClientWithResponsesInterface interface {
}
{{range .}}{{$opid := .OperationId}}{{$op := .}}
+{{$responseTypeDefinitions := getResponseTypeDefinitions .}}
type {{genResponseTypeName $opid | ucFirst}} struct {
Body []byte
HTTPResponse *http.Response
- {{- range getResponseTypeDefinitions .}}
+ {{- range $responseTypeDefinitions}}
{{.TypeName}} *{{.Schema.TypeDecl}}
{{- end}}
}
+{{ if not opts.OutputOptions.SkipResponseBodyGetters }}
+{{- range $responseTypeDefinitions}}
+ // Get{{.TypeName}} returns {{.TypeName}}
+ func (r {{genResponseTypeName $opid | ucFirst}}) Get{{.TypeName}}() *{{.Schema.TypeDecl}} {
+ return r.{{.TypeName}}
+ }
+{{- end}}
+
+// GetBody returns the raw response body bytes (Body)
+func (r {{genResponseTypeName $opid | ucFirst}}) GetBody() []byte {
+ return r.Body
+}
+{{end}}
+
// Status returns HTTPResponse.Status
func (r {{genResponseTypeName $opid | ucFirst}}) Status() string {
if r.HTTPResponse != nil {
@@ -67,6 +82,24 @@ func (r {{genResponseTypeName $opid | ucFirst}}) StatusCode() int {
}
return 0
}
+
+{{ if opts.OutputOptions.ClientResponseBytesFunction }}
+// Bytes is a convenience method to retrieve the raw bytes from the HTTP response
+func (r {{genResponseTypeName $opid | ucFirst}}) Bytes() []byte {
+ return r.Body
+}
+{{end}}
+
+{{ if not opts.OutputOptions.SkipClientResponseContentType }}
+// ContentType is a convenience method to retrieve the Content-Type value from the HTTP response headers
+func (r {{genResponseTypeName $opid | ucFirst}}) ContentType() string {
+ if r.HTTPResponse != nil {
+ return r.HTTPResponse.Header.Get("Content-Type")
+ }
+ return ""
+}
+{{end}}
+
{{end}}
diff --git a/pkg/codegen/templates/client.tmpl b/pkg/codegen/templates/client.tmpl
index 10ee5644d2..1f02997e1f 100644
--- a/pkg/codegen/templates/client.tmpl
+++ b/pkg/codegen/templates/client.tmpl
@@ -148,9 +148,17 @@ func New{{$opid}}Request{{.Suffix}}(server string{{genParamArgs $pathParams}}{{i
}
bodyReader = strings.NewReader(bodyStr.Encode())
{{else if eq .NameTag "Text" -}}
- bodyReader = strings.NewReader(string(body))
+ if stringer, ok := interface{}(body).(fmt.Stringer); ok {
+ bodyReader = strings.NewReader(stringer.String())
+ } else {
+ {{if .Schema.IsPrimitive -}}
+ bodyReader = strings.NewReader(fmt.Sprint(body))
+ {{else -}}
+ return nil, fmt.Errorf("text/plain is not supported for complex types, define a String() method on {{.Schema.TypeDecl}} to marshal it as text")
+ {{end -}}
+ }
{{end -}}
- return New{{$opid}}RequestWithBody(server{{genParamNames $pathParams}}{{if $hasParams}}, params{{end}}, "{{.ContentType}}", bodyReader)
+ return New{{$opid}}RequestWithBody(server{{genParamNames $pathParams}}{{if $hasParams}}, params{{end}}, {{.ContentType | toGoString}}, bodyReader)
}
{{end -}}
{{end}}
@@ -172,7 +180,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
pathParam{{$paramIdx}} = string(pathParamBuf{{$paramIdx}})
{{end}}
{{if .IsStyled}}
- pathParam{{$paramIdx}}, err = runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationPath, {{.GoVariableName}})
+ pathParam{{$paramIdx}}, err = runtime.StyleParamWithOptions("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{.GoVariableName}}, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationPath, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
return nil, err
}
@@ -195,14 +203,20 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
{{if .QueryParams}}
if params != nil {
+ // queryValues collects non-styled parameters (passthrough, JSON)
+ // that are safe to round-trip through url.Values.Encode().
queryValues := queryURL.Query()
+ // rawQueryFragments collects pre-encoded query fragments from
+ // styled parameters, preserving literal commas as delimiters
+ // per the OpenAPI spec (e.g. "color=blue,black,brown").
+ var rawQueryFragments []string
{{range $paramIdx, $param := .QueryParams}}
- {{if not .Required}} if params.{{.GoName}} != nil { {{end}}
+ {{if .RequiresNilCheck}} if params.{{.GoName}} != nil { {{end}}
{{if .IsPassThrough}}
- queryValues.Add("{{.ParamName}}", {{if not .Required}}*{{end}}params.{{.GoName}})
+ queryValues.Add("{{.ParamName}}", {{if .HasOptionalPointer}}*{{end}}params.{{.GoName}})
{{end}}
{{if .IsJson}}
- if queryParamBuf, err := json.Marshal({{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
+ if queryParamBuf, err := json.Marshal({{if .HasOptionalPointer}}*{{end}}params.{{.GoName}}); err != nil {
return nil, err
} else {
queryValues.Add("{{.ParamName}}", string(queryParamBuf))
@@ -210,24 +224,23 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
{{end}}
{{if .IsStyled}}
- if queryFrag, err := runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationQuery, {{if not .Required}}*{{end}}params.{{.GoName}}); err != nil {
+ if queryFrag, err := runtime.StyleParamWithOptions("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{if and .RequiresNilCheck .HasOptionalPointer}}*{{end}}params.{{.GoName}}, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationQuery, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"}); err != nil {
return nil, err
- } else if parsed, err := url.ParseQuery(queryFrag); err != nil {
- return nil, err
} else {
- for k, v := range parsed {
- for _, v2 := range v {
- queryValues.Add(k, v2)
- }
- }
+ for _, qp := range strings.Split(queryFrag, "&") {
+ rawQueryFragments = append(rawQueryFragments, qp)
+ }
}
{{end}}
- {{if not .Required}}}{{end}}
+ {{if .RequiresNilCheck}}}{{end}}
{{end}}
- queryURL.RawQuery = queryValues.Encode()
+ if encoded := queryValues.Encode(); encoded != "" {
+ rawQueryFragments = append(rawQueryFragments, encoded)
+ }
+ queryURL.RawQuery = strings.Join(rawQueryFragments, "&")
}
{{end}}{{/* if .QueryParams */}}
- req, err := http.NewRequest("{{.Method}}", queryURL.String(), {{if .HasBody}}body{{else}}nil{{end}})
+ req, err := http.NewRequest({{.Method | httpMethodConstant}}, queryURL.String(), {{if .HasBody}}body{{else}}nil{{end}})
if err != nil {
return nil, err
}
@@ -236,27 +249,27 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
{{ if .HeaderParams }}
if params != nil {
{{range $paramIdx, $param := .HeaderParams}}
- {{if not .Required}} if params.{{.GoName}} != nil { {{end}}
+ {{if .RequiresNilCheck}} if params.{{.GoName}} != nil { {{end}}
var headerParam{{$paramIdx}} string
{{if .IsPassThrough}}
- headerParam{{$paramIdx}} = {{if not .Required}}*{{end}}params.{{.GoName}}
+ headerParam{{$paramIdx}} = {{if .HasOptionalPointer}}*{{end}}params.{{.GoName}}
{{end}}
{{if .IsJson}}
var headerParamBuf{{$paramIdx}} []byte
- headerParamBuf{{$paramIdx}}, err = json.Marshal({{if not .Required}}*{{end}}params.{{.GoName}})
+ headerParamBuf{{$paramIdx}}, err = json.Marshal({{if .HasOptionalPointer}}*{{end}}params.{{.GoName}})
if err != nil {
return nil, err
}
headerParam{{$paramIdx}} = string(headerParamBuf{{$paramIdx}})
{{end}}
{{if .IsStyled}}
- headerParam{{$paramIdx}}, err = runtime.StyleParamWithLocation("{{.Style}}", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, {{if not .Required}}*{{end}}params.{{.GoName}})
+ headerParam{{$paramIdx}}, err = runtime.StyleParamWithOptions("{{.Style}}", {{.Explode}}, "{{.ParamName}}", {{if .HasOptionalPointer}}*{{end}}params.{{.GoName}}, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationHeader, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
return nil, err
}
{{end}}
req.Header.Set("{{.ParamName}}", headerParam{{$paramIdx}})
- {{if not .Required}}}{{end}}
+ {{if .RequiresNilCheck}}}{{end}}
{{end}}
}
{{- end }}{{/* if .HeaderParams */}}
@@ -264,21 +277,21 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
{{ if .CookieParams }}
if params != nil {
{{range $paramIdx, $param := .CookieParams}}
- {{if not .Required}} if params.{{.GoName}} != nil { {{end}}
+ {{if .RequiresNilCheck}} if params.{{.GoName}} != nil { {{end}}
var cookieParam{{$paramIdx}} string
{{if .IsPassThrough}}
- cookieParam{{$paramIdx}} = {{if not .Required}}*{{end}}params.{{.GoName}}
+ cookieParam{{$paramIdx}} = {{if .HasOptionalPointer}}*{{end}}params.{{.GoName}}
{{end}}
{{if .IsJson}}
var cookieParamBuf{{$paramIdx}} []byte
- cookieParamBuf{{$paramIdx}}, err = json.Marshal({{if not .Required}}*{{end}}params.{{.GoName}})
+ cookieParamBuf{{$paramIdx}}, err = json.Marshal({{if .HasOptionalPointer}}*{{end}}params.{{.GoName}})
if err != nil {
return nil, err
}
cookieParam{{$paramIdx}} = url.QueryEscape(string(cookieParamBuf{{$paramIdx}}))
{{end}}
{{if .IsStyled}}
- cookieParam{{$paramIdx}}, err = runtime.StyleParamWithLocation("simple", {{.Explode}}, "{{.ParamName}}", runtime.ParamLocationCookie, {{if not .Required}}*{{end}}params.{{.GoName}})
+ cookieParam{{$paramIdx}}, err = runtime.StyleParamWithOptions("simple", {{.Explode}}, "{{.ParamName}}", {{if .HasOptionalPointer}}*{{end}}params.{{.GoName}}, runtime.StyleParamOptions{ParamLocation: runtime.ParamLocationCookie, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
return nil, err
}
@@ -288,7 +301,7 @@ func New{{$opid}}Request{{if .HasBody}}WithBody{{end}}(server string{{genParamAr
Value:cookieParam{{$paramIdx}},
}
req.AddCookie(cookie{{$paramIdx}})
- {{if not .Required}}}{{end}}
+ {{if .RequiresNilCheck}}}{{end}}
{{ end -}}
}
{{- end }}{{/* if .CookieParams */}}
diff --git a/pkg/codegen/templates/constants.tmpl b/pkg/codegen/templates/constants.tmpl
index 8fad8764c4..07a03a2a38 100644
--- a/pkg/codegen/templates/constants.tmpl
+++ b/pkg/codegen/templates/constants.tmpl
@@ -1,7 +1,7 @@
{{- if gt (len .SecuritySchemeProviderNames) 0 }}
const (
{{range $ProviderName := .SecuritySchemeProviderNames}}
- {{- $ProviderName | sanitizeGoIdentity | ucFirst}}Scopes = "{{$ProviderName}}.Scopes"
+ {{- $ProviderName | sanitizeGoIdentity | ucFirst}}Scopes {{$ProviderName | schemaNameToTypeName | lcFirst}}ContextKey = "{{$ProviderName}}.Scopes"
{{end}}
)
{{end}}
@@ -12,4 +12,15 @@ const (
{{$name}} {{$Enum.TypeName}} = {{$Enum.ValueWrapper}}{{$value}}{{$Enum.ValueWrapper -}}
{{end}}
)
+{{if not $.SkipEnumValidate}}
+// Valid indicates whether the value is a known member of the {{$Enum.TypeName}} enum.
+func (e {{$Enum.TypeName}}) Valid() bool {
+ switch e {
+ {{range $name, $value := $Enum.GetValues}}case {{$name}}:
+ return true
+ {{end}}default:
+ return false
+ }
+}
+{{end}}
{{end}}
diff --git a/pkg/codegen/templates/echo/echo-interface.tmpl b/pkg/codegen/templates/echo/echo-interface.tmpl
index 7380091690..6834432709 100644
--- a/pkg/codegen/templates/echo/echo-interface.tmpl
+++ b/pkg/codegen/templates/echo/echo-interface.tmpl
@@ -1,7 +1,7 @@
// ServerInterface represents all server handlers.
type ServerInterface interface {
-{{range .}}{{.SummaryAsComment }}
+{{range .}}{{if not .IsAlias}}{{.SummaryAsComment }}
// ({{.Method}} {{.Path}})
{{.OperationId}}(ctx echo.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) error
-{{end}}
+{{end}}{{end}}
}
diff --git a/pkg/codegen/templates/echo/echo-register.tmpl b/pkg/codegen/templates/echo/echo-register.tmpl
index 21b52fe48b..def0917e31 100644
--- a/pkg/codegen/templates/echo/echo-register.tmpl
+++ b/pkg/codegen/templates/echo/echo-register.tmpl
@@ -15,19 +15,38 @@ type EchoRouter interface {
TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) *echo.Route
}
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
// RegisterHandlers adds each server route to the EchoRouter.
func RegisterHandlers(router EchoRouter, si ServerInterface) {
- RegisterHandlersWithBaseURL(router, si, "")
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
}
-// Registers handlers, and prepends BaseURL to the paths, so that the paths
-// can be served under a prefix.
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
{{if .}}
wrapper := ServerInterfaceWrapper{
Handler: si,
}
{{end}}
-{{range .}}router.{{.Method}}(baseURL + "{{.Path | swaggerUriToEchoUri}}", wrapper.{{.OperationId}})
+{{range .}}router.{{.Method}}(options.BaseURL + "{{.Path | swaggerUriToEchoUri}}", wrapper.{{.HandlerName}}, options.OperationMiddlewares["{{.MiddlewareKey}}"]...)
{{end}}
}
diff --git a/pkg/codegen/templates/echo/echo-wrappers.tmpl b/pkg/codegen/templates/echo/echo-wrappers.tmpl
index 21ba626ca2..064bd7f32f 100644
--- a/pkg/codegen/templates/echo/echo-wrappers.tmpl
+++ b/pkg/codegen/templates/echo/echo-wrappers.tmpl
@@ -3,7 +3,7 @@ type ServerInterfaceWrapper struct {
Handler ServerInterface
}
-{{range .}}{{$opid := .OperationId}}// {{$opid}} converts echo context to params.
+{{range .}}{{$opid := .OperationId}}{{if not .IsAlias}}// {{$opid}} converts echo context to params.
func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
var err error
{{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" -------------
@@ -18,7 +18,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
}
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationPath, ctx.Param("{{.ParamName}}"), &{{$varName}})
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", ctx.Param("{{.ParamName}}"), &{{$varName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err))
}
@@ -26,7 +26,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
{{end}}
{{range .SecurityDefinitions}}
- ctx.Set({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}})
+ ctx.Set(string({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes), {{toStringArray .Scopes}})
{{end}}
{{if .RequiresParamObject}}
@@ -37,14 +37,14 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
// ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
{{ end }}
{{if .IsStyled}}
- err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", ctx.QueryParams(), ¶ms.{{.GoName}})
+ err = runtime.BindQueryParameterWithOptions("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", ctx.QueryParams(), ¶ms.{{.GoName}}, runtime.BindQueryParameterOptions{Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err))
}
{{else}}
if paramValue := ctx.QueryParam("{{.ParamName}}"); paramValue != "" {
{{if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}paramValue
{{end}}
{{if .IsJson}}
var value {{.TypeDef}}
@@ -52,7 +52,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter '{{.ParamName}}' as JSON")
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
}{{if .Required}} else {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument {{.ParamName}} is required, but not found"))
@@ -70,7 +70,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for {{.ParamName}}, got %d", n))
}
{{if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}valueList[0]
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}valueList[0]
{{end}}
{{if .IsJson}}
err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}})
@@ -79,12 +79,12 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
}
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, valueList[0], &{{.GoName}})
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", valueList[0], &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err))
}
{{end}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}}
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}{{.GoName}}
} {{if .Required}}else {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Header parameter {{.ParamName}} is required, but not found"))
}{{end}}
@@ -94,7 +94,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
{{range .CookieParams}}
if cookie, err := ctx.Cookie("{{.ParamName}}"); err == nil {
{{if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}cookie.Value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}cookie.Value
{{end}}
{{if .IsJson}}
var value {{.TypeDef}}
@@ -107,15 +107,15 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter '{{.ParamName}}' as JSON")
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
{{if .IsStyled}}
var value {{.TypeDef}}
- err = runtime.BindStyledParameterWithLocation("simple",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationCookie, cookie.Value, &value)
+ err = runtime.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err))
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
}{{if .Required}} else {
return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument {{.ParamName}} is required, but not found"))
@@ -128,4 +128,4 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx echo.Context) error {
err = w.Handler.{{.OperationId}}(ctx{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
return err
}
-{{end}}
+{{end}}{{end}}
diff --git a/pkg/codegen/templates/echo/v5/echo-interface.tmpl b/pkg/codegen/templates/echo/v5/echo-interface.tmpl
new file mode 100644
index 0000000000..6d5b874bed
--- /dev/null
+++ b/pkg/codegen/templates/echo/v5/echo-interface.tmpl
@@ -0,0 +1,7 @@
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+{{range .}}{{if not .IsAlias}}{{.SummaryAsComment }}
+// ({{.Method}} {{.Path}})
+{{.OperationId}}(ctx *echo.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) error
+{{end}}{{end}}
+}
diff --git a/pkg/codegen/templates/echo/v5/echo-register.tmpl b/pkg/codegen/templates/echo/v5/echo-register.tmpl
new file mode 100644
index 0000000000..d311fefbe2
--- /dev/null
+++ b/pkg/codegen/templates/echo/v5/echo-register.tmpl
@@ -0,0 +1,52 @@
+
+
+// This is a simple interface which specifies echo.Route addition functions which
+// are present on both echo.Echo and echo.Group, since we want to allow using
+// either of them for path registration
+type EchoRouter interface {
+ CONNECT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ DELETE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ GET(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ HEAD(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ OPTIONS(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ PATCH(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ POST(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ PUT(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+ TRACE(path string, h echo.HandlerFunc, m ...echo.MiddlewareFunc) echo.RouteInfo
+}
+
+// RegisterHandlersOptions configures RegisterHandlersWithOptions.
+type RegisterHandlersOptions struct {
+ // BaseURL is prepended to every registered path so the API can be served
+ // under a prefix.
+ BaseURL string
+ // OperationMiddlewares lets the caller attach per-operation middleware at
+ // registration time. The map key is the OpenAPI `operationId` value as it
+ // appears in the spec (the raw, un-normalized form). Operations that have
+ // no entry are registered with no extra middleware. A nil map disables
+ // per-operation middleware entirely.
+ OperationMiddlewares map[string][]echo.MiddlewareFunc
+}
+
+// RegisterHandlers adds each server route to the EchoRouter.
+func RegisterHandlers(router EchoRouter, si ServerInterface) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{})
+}
+
+// RegisterHandlersWithBaseURL registers handlers and prepends BaseURL to the
+// paths so the API can be served under a prefix.
+func RegisterHandlersWithBaseURL(router EchoRouter, si ServerInterface, baseURL string) {
+ RegisterHandlersWithOptions(router, si, RegisterHandlersOptions{BaseURL: baseURL})
+}
+
+// RegisterHandlersWithOptions registers handlers using the supplied options,
+// including any per-operation middleware.
+func RegisterHandlersWithOptions(router EchoRouter, si ServerInterface, options RegisterHandlersOptions) {
+{{if .}}
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ }
+{{end}}
+{{range .}}router.{{.Method}}(options.BaseURL + "{{.Path | swaggerUriToEchoUri}}", wrapper.{{.HandlerName}}, options.OperationMiddlewares["{{.MiddlewareKey}}"]...)
+{{end}}
+}
diff --git a/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl b/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl
new file mode 100644
index 0000000000..0477ddcd34
--- /dev/null
+++ b/pkg/codegen/templates/echo/v5/echo-wrappers.tmpl
@@ -0,0 +1,131 @@
+// ServerInterfaceWrapper converts echo contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+}
+
+{{range .}}{{$opid := .OperationId}}{{if not .IsAlias}}// {{$opid}} converts echo context to params.
+func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx *echo.Context) error {
+ var err error
+{{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" -------------
+ var {{$varName := .GoVariableName}}{{$varName}} {{.TypeDef}}
+{{if .IsPassThrough}}
+ {{$varName}} = ctx.Param("{{.ParamName}}")
+{{end}}
+{{if .IsJson}}
+ err = json.Unmarshal([]byte(ctx.Param("{{.ParamName}}")), &{{$varName}})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter '{{.ParamName}}' as JSON")
+ }
+{{end}}
+{{if .IsStyled}}
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", ctx.Param("{{.ParamName}}"), &{{$varName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err))
+ }
+{{end}}
+{{end}}
+
+{{range .SecurityDefinitions}}
+ ctx.Set(string({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes), {{toStringArray .Scopes}})
+{{end}}
+
+{{if .RequiresParamObject}}
+ // Parameter object where we will unmarshal all parameters from the context
+ var params {{.OperationId}}Params
+{{range $paramIdx, $param := .QueryParams}}
+ {{- if (or (or .Required .IsPassThrough) (or .IsJson .IsStyled)) -}}
+ // ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
+ {{ end }}
+ {{if .IsStyled}}
+ err = runtime.BindQueryParameterWithOptions("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", ctx.QueryParams(), ¶ms.{{.GoName}}, runtime.BindQueryParameterOptions{Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err))
+ }
+ {{else}}
+ if paramValue := ctx.QueryParam("{{.ParamName}}"); paramValue != "" {
+ {{if .IsPassThrough}}
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}paramValue
+ {{end}}
+ {{if .IsJson}}
+ var value {{.TypeDef}}
+ err = json.Unmarshal([]byte(paramValue), &value)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter '{{.ParamName}}' as JSON")
+ }
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
+ {{end}}
+ }{{if .Required}} else {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument {{.ParamName}} is required, but not found"))
+ }{{end}}
+ {{end}}
+{{end}}
+
+{{if .HeaderParams}}
+ headers := ctx.Request().Header
+{{range .HeaderParams}}// ------------- {{if .Required}}Required{{else}}Optional{{end}} header parameter "{{.ParamName}}" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("{{.ParamName}}")]; found {
+ var {{.GoName}} {{.TypeDef}}
+ n := len(valueList)
+ if n != 1 {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Expected one value for {{.ParamName}}, got %d", n))
+ }
+{{if .IsPassThrough}}
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}valueList[0]
+{{end}}
+{{if .IsJson}}
+ err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter '{{.ParamName}}' as JSON")
+ }
+{{end}}
+{{if .IsStyled}}
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", valueList[0], &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err))
+ }
+{{end}}
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}{{.GoName}}
+ } {{if .Required}}else {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Header parameter {{.ParamName}} is required, but not found"))
+ }{{end}}
+{{end}}
+{{end}}
+
+{{range .CookieParams}}
+ if cookie, err := ctx.Cookie("{{.ParamName}}"); err == nil {
+ {{if .IsPassThrough}}
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}cookie.Value
+ {{end}}
+ {{if .IsJson}}
+ var value {{.TypeDef}}
+ var decoded string
+ decoded, err := url.QueryUnescape(cookie.Value)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unescaping cookie parameter '{{.ParamName}}'")
+ }
+ err = json.Unmarshal([]byte(decoded), &value)
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, "Error unmarshaling parameter '{{.ParamName}}' as JSON")
+ }
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
+ {{end}}
+ {{if .IsStyled}}
+ var value {{.TypeDef}}
+ err = runtime.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
+ if err != nil {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Invalid format for parameter {{.ParamName}}: %s", err))
+ }
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
+ {{end}}
+ }{{if .Required}} else {
+ return echo.NewHTTPError(http.StatusBadRequest, fmt.Sprintf("Query argument {{.ParamName}} is required, but not found"))
+ }{{end}}
+
+{{end}}{{/* .CookieParams */}}
+
+{{end}}{{/* .RequiresParamObject */}}
+ // Invoke the callback with all the unmarshaled arguments
+ err = w.Handler.{{.OperationId}}(ctx{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
+ return err
+}
+{{end}}{{end}}
diff --git a/pkg/codegen/templates/fiber/fiber-handler.tmpl b/pkg/codegen/templates/fiber/fiber-handler.tmpl
index 4a55b3c512..5ac8be929f 100644
--- a/pkg/codegen/templates/fiber/fiber-handler.tmpl
+++ b/pkg/codegen/templates/fiber/fiber-handler.tmpl
@@ -2,6 +2,7 @@
type FiberServerOptions struct {
BaseURL string
Middlewares []MiddlewareFunc
+ HandlerMiddlewares []HandlerMiddlewareFunc
}
// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
@@ -13,13 +14,14 @@ func RegisterHandlers(router fiber.Router, si ServerInterface) {
func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, options FiberServerOptions) {
{{if .}}wrapper := ServerInterfaceWrapper{
Handler: si,
+HandlerMiddlewares: options.HandlerMiddlewares,
}
for _, m := range options.Middlewares {
- router.Use(m)
+ router.Use(fiber.Handler(m))
}
{{end}}
{{range .}}
-router.{{.Method | lower | title }}(options.BaseURL+"{{.Path | swaggerUriToFiberUri}}", wrapper.{{.OperationId}})
+router.{{.Method | lower | title }}(options.BaseURL+"{{.Path | swaggerUriToFiberUri}}", wrapper.{{.HandlerName}})
{{end}}
}
diff --git a/pkg/codegen/templates/fiber/fiber-interface.tmpl b/pkg/codegen/templates/fiber/fiber-interface.tmpl
index 8ef90a851a..4459e8b0d6 100644
--- a/pkg/codegen/templates/fiber/fiber-interface.tmpl
+++ b/pkg/codegen/templates/fiber/fiber-interface.tmpl
@@ -1,7 +1,7 @@
// ServerInterface represents all server handlers.
type ServerInterface interface {
-{{range .}}{{.SummaryAsComment }}
+{{range .}}{{if not .IsAlias}}{{.SummaryAsComment }}
// ({{.Method}} {{.Path}})
{{.OperationId}}(c *fiber.Ctx{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) error
-{{end}}
+{{end}}{{end}}
}
diff --git a/pkg/codegen/templates/fiber/fiber-middleware.tmpl b/pkg/codegen/templates/fiber/fiber-middleware.tmpl
index ad3160d734..ce20c29a4d 100644
--- a/pkg/codegen/templates/fiber/fiber-middleware.tmpl
+++ b/pkg/codegen/templates/fiber/fiber-middleware.tmpl
@@ -1,33 +1,45 @@
// ServerInterfaceWrapper converts contexts to parameters.
type ServerInterfaceWrapper struct {
Handler ServerInterface
+ HandlerMiddlewares []HandlerMiddlewareFunc
}
type MiddlewareFunc fiber.Handler
+type HandlerMiddlewareFunc func(c *fiber.Ctx, next fiber.Handler) error
{{range .}}{{$opid := .OperationId}}
-
+{{if not .IsAlias}}
// {{$opid}} operation middleware
func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error {
{{if or .RequiresParamObject (gt (len .PathParams) 0) }}
var err error
+ _ = err
{{end}}
{{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" -------------
var {{$varName := .GoVariableName}}{{$varName}} {{.TypeDef}}
{{if .IsPassThrough}}
- {{$varName}} = c.Query("{{.ParamName}}")
+ {{$varName}}, err = url.PathUnescape(c.Params("{{.ParamName}}"))
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unescaping path parameter '{{.ParamName}}': %w", err).Error())
+ }
{{end}}
{{if .IsJson}}
- err = json.Unmarshal([]byte(c.Query("{{.ParamName}}")), &{{$varName}})
- if err != nil {
- return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshaling parameter '{{.ParamName}}' as JSON: %w", err).Error())
+ {
+ paramValue, decErr := url.PathUnescape(c.Params("{{.ParamName}}"))
+ if decErr != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unescaping path parameter '{{.ParamName}}': %w", decErr).Error())
+ }
+ err = json.Unmarshal([]byte(paramValue), &{{$varName}})
+ if err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshaling parameter '{{.ParamName}}' as JSON: %w", err).Error())
+ }
}
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", c.Params("{{.ParamName}}"), &{{$varName}})
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", c.Params("{{.ParamName}}"), &{{$varName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error())
}
@@ -36,7 +48,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error {
{{end}}
{{range .SecurityDefinitions}}
- c.Context().SetUserValue({{.ProviderName | ucFirst}}Scopes, {{toStringArray .Scopes}})
+ c.Context().SetUserValue(({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes), {{toStringArray .Scopes}})
{{end}}
{{if .RequiresParamObject}}
@@ -55,11 +67,11 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error {
{{- if (or (or .Required .IsPassThrough) (or .IsJson .IsStyled)) -}}
// ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
{{ end }}
- {{ if (or (or .Required .IsPassThrough) .IsJson) }}
+ {{ if (or .IsPassThrough .IsJson) }}
if paramValue := c.Query("{{.ParamName}}"); paramValue != "" {
{{if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}paramValue
{{end}}
{{if .IsJson}}
@@ -69,7 +81,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshaling parameter '{{.ParamName}}' as JSON: %w", err).Error())
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
}{{if .Required}} else {
err = fmt.Errorf("Query argument {{.ParamName}} is required, but not found")
@@ -78,7 +90,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error {
}{{end}}
{{end}}
{{if .IsStyled}}
- err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", query, ¶ms.{{.GoName}})
+ err = runtime.BindQueryParameterWithOptions("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", query, ¶ms.{{.GoName}}, runtime.BindQueryParameterOptions{Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error())
}
@@ -89,28 +101,32 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error {
headers := c.GetReqHeaders()
{{range .HeaderParams}}// ------------- {{if .Required}}Required{{else}}Optional{{end}} header parameter "{{.ParamName}}" -------------
- if value, found := headers[http.CanonicalHeaderKey("{{.ParamName}}")]; found {
+ if valueList, found := headers[http.CanonicalHeaderKey("{{.ParamName}}")]; found {
var {{.GoName}} {{.TypeDef}}
+ n := len(valueList)
+ if n != 1 {
+ return fiber.NewError(fiber.StatusBadRequest, fmt.Sprintf("Too many values for ParamName {{.ParamName}}, 1 is required, but %d found", n))
+ }
{{if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}valueList[0]
{{end}}
{{if .IsJson}}
- err = json.Unmarshal([]byte(value), &{{.GoName}})
+ err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}})
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshaling parameter '{{.ParamName}}' as JSON: %w", err).Error())
}
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, value, &{{.GoName}})
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", valueList[0], &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error())
}
{{end}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}}
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}{{.GoName}}
} {{if .Required}}else {
err = fmt.Errorf("Header parameter {{.ParamName}} is required, but not found: %w", err)
@@ -121,12 +137,13 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error {
{{end}}
{{range .CookieParams}}
- var cookie string
+ {
+ cookie := c.Cookies("{{.ParamName}}")
- if cookie = c.Cookies("{{.ParamName}}"); cookie == "" {
+ if cookie != "" {
{{- if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}cookie
+ params.{{.GoName}} = {{if .HasOptionalPointer}}}&{{end}}cookie
{{end}}
{{- if .IsJson}}
@@ -142,16 +159,16 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Error unmarshaling parameter '{{.ParamName}}' as JSON: %w", err).Error())
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
{{- if .IsStyled}}
var value {{.TypeDef}}
- err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie, &value)
+ err = runtime.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
return fiber.NewError(fiber.StatusBadRequest, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err).Error())
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
}
@@ -161,9 +178,22 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *fiber.Ctx) error {
return fiber.NewError(fiber.StatusBadRequest, err.Error())
}
{{- end}}
+ }
{{end}}
{{end}}
- return siw.Handler.{{.OperationId}}(c{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
+ handler := func(c *fiber.Ctx) error {
+ return siw.Handler.{{.OperationId}}(c{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
+ }
+
+ for i := len(siw.HandlerMiddlewares) - 1; i >= 0; i-- {
+ m := siw.HandlerMiddlewares[i]
+ next := handler
+ handler = func(c *fiber.Ctx) error {
+ return m(c, next)
+ }
+ }
+
+ return handler(c)
}
-{{end}}
+{{end}}{{end}}
diff --git a/pkg/codegen/templates/gin/gin-interface.tmpl b/pkg/codegen/templates/gin/gin-interface.tmpl
index 49a18f812a..dec255e713 100644
--- a/pkg/codegen/templates/gin/gin-interface.tmpl
+++ b/pkg/codegen/templates/gin/gin-interface.tmpl
@@ -1,7 +1,7 @@
// ServerInterface represents all server handlers.
type ServerInterface interface {
-{{range .}}{{.SummaryAsComment }}
+{{range .}}{{if not .IsAlias}}{{.SummaryAsComment }}
// ({{.Method}} {{.Path}})
{{.OperationId}}(c *gin.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}})
-{{end}}
+{{end}}{{end}}
}
diff --git a/pkg/codegen/templates/gin/gin-register.tmpl b/pkg/codegen/templates/gin/gin-register.tmpl
index 8f03722ab1..4bc17b3c74 100644
--- a/pkg/codegen/templates/gin/gin-register.tmpl
+++ b/pkg/codegen/templates/gin/gin-register.tmpl
@@ -28,6 +28,6 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options
{{end}}
{{range . -}}
- router.{{.Method }}(options.BaseURL+"{{.Path | swaggerUriToGinUri }}", wrapper.{{.OperationId}})
+ router.{{.Method }}(options.BaseURL+"{{.Path | swaggerUriToGinUri }}", wrapper.{{.HandlerName}})
{{end -}}
}
diff --git a/pkg/codegen/templates/gin/gin-wrappers.tmpl b/pkg/codegen/templates/gin/gin-wrappers.tmpl
index b7332b3c3d..87f16a56f8 100644
--- a/pkg/codegen/templates/gin/gin-wrappers.tmpl
+++ b/pkg/codegen/templates/gin/gin-wrappers.tmpl
@@ -8,29 +8,30 @@ type ServerInterfaceWrapper struct {
type MiddlewareFunc func(c *gin.Context)
{{range .}}{{$opid := .OperationId}}
-
+{{if not .IsAlias}}
// {{$opid}} operation middleware
func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
{{if or .RequiresParamObject (gt (len .PathParams) 0) }}
var err error
+ _ = err
{{end}}
{{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" -------------
var {{$varName := .GoVariableName}}{{$varName}} {{.TypeDef}}
{{if .IsPassThrough}}
- {{$varName}} = c.Query("{{.ParamName}}")
+ {{$varName}} = c.Param("{{.ParamName}}")
{{end}}
{{if .IsJson}}
- err = json.Unmarshal([]byte(c.Query("{{.ParamName}}")), &{{$varName}})
+ err = json.Unmarshal([]byte(c.Param("{{.ParamName}}")), &{{$varName}})
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Error unmarshaling parameter '{{.ParamName}}' as JSON"), http.StatusBadRequest)
return
}
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", c.Param("{{.ParamName}}"), &{{$varName}})
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", c.Param("{{.ParamName}}"), &{{$varName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err), http.StatusBadRequest)
return
@@ -40,7 +41,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
{{end}}
{{range .SecurityDefinitions}}
- c.Set({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}})
+ c.Set(string({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes), {{toStringArray .Scopes}})
{{end}}
{{if .RequiresParamObject}}
@@ -51,11 +52,11 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
{{- if (or (or .Required .IsPassThrough) (or .IsJson .IsStyled)) -}}
// ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
{{ end }}
- {{ if (or (or .Required .IsPassThrough) .IsJson) }}
+ {{ if (or .IsPassThrough .IsJson) }}
if paramValue := c.Query("{{.ParamName}}"); paramValue != "" {
{{if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}paramValue
{{end}}
{{if .IsJson}}
@@ -66,7 +67,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
return
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
}{{if .Required}} else {
siw.ErrorHandler(c, fmt.Errorf("Query argument {{.ParamName}} is required, but not found"), http.StatusBadRequest)
@@ -75,7 +76,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
{{end}}
{{if .IsStyled}}
- err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", c.Request.URL.Query(), ¶ms.{{.GoName}})
+ err = runtime.BindQueryParameterWithOptions("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", c.Request.URL.Query(), ¶ms.{{.GoName}}, runtime.BindQueryParameterOptions{Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err), http.StatusBadRequest)
return
@@ -96,7 +97,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
}
{{if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}valueList[0]
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}valueList[0]
{{end}}
{{if .IsJson}}
@@ -108,14 +109,14 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, valueList[0], &{{.GoName}})
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", valueList[0], &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err), http.StatusBadRequest)
return
}
{{end}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}}
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}{{.GoName}}
} {{if .Required}}else {
siw.ErrorHandler(c, fmt.Errorf("Header parameter {{.ParamName}} is required, but not found"), http.StatusBadRequest)
@@ -132,7 +133,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
if cookie, err = c.Cookie("{{.ParamName}}"); err == nil {
{{- if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}cookie
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}cookie
{{end}}
{{- if .IsJson}}
@@ -150,17 +151,17 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
return
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
{{- if .IsStyled}}
var value {{.TypeDef}}
- err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie, &value)
+ err = runtime.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
siw.ErrorHandler(c, fmt.Errorf("Invalid format for parameter {{.ParamName}}: %w", err), http.StatusBadRequest)
return
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
}
@@ -183,4 +184,4 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(c *gin.Context) {
siw.Handler.{{.OperationId}}(c{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
}
-{{end}}
+{{end}}{{end}}
diff --git a/pkg/codegen/templates/gorilla/gorilla-interface.tmpl b/pkg/codegen/templates/gorilla/gorilla-interface.tmpl
index 79a51fd75b..04baa51e39 100644
--- a/pkg/codegen/templates/gorilla/gorilla-interface.tmpl
+++ b/pkg/codegen/templates/gorilla/gorilla-interface.tmpl
@@ -1,7 +1,7 @@
// ServerInterface represents all server handlers.
type ServerInterface interface {
-{{range .}}{{.SummaryAsComment }}
+{{range .}}{{if not .IsAlias}}{{.SummaryAsComment }}
// ({{.Method}} {{.Path}})
{{.OperationId}}(w http.ResponseWriter, r *http.Request{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}})
-{{end}}
+{{end}}{{end}}
}
diff --git a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
index 0e0a5e17cf..c971395fb8 100644
--- a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
+++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
@@ -8,12 +8,12 @@ type ServerInterfaceWrapper struct {
type MiddlewareFunc func(http.Handler) http.Handler
{{range .}}{{$opid := .OperationId}}
-
+{{if not .IsAlias}}
// {{$opid}} operation middleware
func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Request) {
- ctx := r.Context()
{{if or .RequiresParamObject (gt (len .PathParams) 0) }}
var err error
+ _ = err
{{end}}
{{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" -------------
@@ -30,7 +30,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
}
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameter("{{.Style}}",{{.Explode}}, "{{.ParamName}}", mux.Vars(r)["{{.ParamName}}"], &{{$varName}})
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", mux.Vars(r)["{{.ParamName}}"], &{{$varName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
return
@@ -39,9 +39,13 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
+ {{if .SecurityDefinitions -}}
+ ctx := r.Context()
{{range .SecurityDefinitions}}
ctx = context.WithValue(ctx, {{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}})
{{end}}
+ r = r.WithContext(ctx)
+ {{end}}
{{if .RequiresParamObject}}
// Parameter object where we will unmarshal all parameters from the context
@@ -51,11 +55,11 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{- if (or (or .Required .IsPassThrough) (or .IsJson .IsStyled)) -}}
// ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
{{ end }}
- {{ if (or (or .Required .IsPassThrough) .IsJson) }}
+ {{ if (or .IsPassThrough .IsJson) }}
if paramValue := r.URL.Query().Get("{{.ParamName}}"); paramValue != "" {
{{if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}paramValue
{{end}}
{{if .IsJson}}
@@ -66,7 +70,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
return
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
}{{if .Required}} else {
siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"})
@@ -74,9 +78,14 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
}{{end}}
{{end}}
{{if .IsStyled}}
- err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", r.URL.Query(), ¶ms.{{.GoName}})
+ err = runtime.BindQueryParameterWithOptions("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", r.URL.Query(), ¶ms.{{.GoName}}, runtime.BindQueryParameterOptions{Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
- siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
+ }
return
}
{{end}}
@@ -95,7 +104,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
}
{{if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}valueList[0]
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}valueList[0]
{{end}}
{{if .IsJson}}
@@ -107,14 +116,14 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, valueList[0], &{{.GoName}})
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", valueList[0], &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
return
}
{{end}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}}
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}{{.GoName}}
} {{if .Required}}else {
err = fmt.Errorf("Header parameter {{.ParamName}} is required, but not found")
@@ -126,12 +135,13 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
{{range .CookieParams}}
+ {
var cookie *http.Cookie
if cookie, err = r.Cookie("{{.ParamName}}"); err == nil {
{{- if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}cookie.Value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}cookie.Value
{{end}}
{{- if .IsJson}}
@@ -150,17 +160,17 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
return
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
{{- if .IsStyled}}
var value {{.TypeDef}}
- err = runtime.BindStyledParameter("simple",{{.Explode}}, "{{.ParamName}}", cookie.Value, &value)
+ err = runtime.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
return
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
}
@@ -170,6 +180,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
return
}
{{- end}}
+ }
{{end}}
{{end}}
@@ -187,9 +198,9 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
}
{{end}}
- handler.ServeHTTP(w, r.WithContext(ctx))
+ handler.ServeHTTP(w, r)
}
-{{end}}
+{{end}}{{end}}
type UnescapedCookieParamError struct {
ParamName string
diff --git a/pkg/codegen/templates/gorilla/gorilla-register.tmpl b/pkg/codegen/templates/gorilla/gorilla-register.tmpl
index b019e1dbbf..b16f3fc9fc 100644
--- a/pkg/codegen/templates/gorilla/gorilla-register.tmpl
+++ b/pkg/codegen/templates/gorilla/gorilla-register.tmpl
@@ -43,7 +43,7 @@ ErrorHandlerFunc: options.ErrorHandlerFunc,
}
{{end}}
{{range .}}
-r.HandleFunc(options.BaseURL+"{{.Path | swaggerUriToGorillaUri }}", wrapper.{{.OperationId}}).Methods("{{.Method }}")
+r.HandleFunc(options.BaseURL+"{{.Path | swaggerUriToGorillaUri }}", wrapper.{{.HandlerName}}).Methods({{.Method | httpMethodConstant}})
{{end}}
return r
}
diff --git a/pkg/codegen/templates/imports.tmpl b/pkg/codegen/templates/imports.tmpl
index 6f41a419a0..d57c2d1cd4 100644
--- a/pkg/codegen/templates/imports.tmpl
+++ b/pkg/codegen/templates/imports.tmpl
@@ -1,3 +1,6 @@
+{{- if opts.Generate.StdHTTPServer}}//go:build go1.22
+
+{{- end}}
// Package {{.PackageName}} provides primitives to interact with the openapi HTTP API.
//
// Code generated by {{.ModuleName}} version {{.Version}} DO NOT EDIT.
@@ -5,16 +8,18 @@ package {{.PackageName}}
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
- "gopkg.in/yaml.v2"
+ "go.yaml.in/yaml/v3"
"io"
"os"
+ "mime"
+ "mime/multipart"
"net/http"
"net/url"
"path"
@@ -22,19 +27,12 @@ import (
"time"
"github.com/oapi-codegen/runtime"
- strictecho "github.com/oapi-codegen/runtime/strictmiddleware/echo"
- strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin"
- strictiris "github.com/oapi-codegen/runtime/strictmiddleware/iris"
- strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"
+ "github.com/oapi-codegen/nullable"
openapi_types "github.com/oapi-codegen/runtime/types"
"github.com/getkin/kin-openapi/openapi3"
- "github.com/go-chi/chi/v5"
- "github.com/labstack/echo/v4"
- "github.com/gin-gonic/gin"
- "github.com/gofiber/fiber/v2"
- "github.com/kataras/iris/v12"
- "github.com/kataras/iris/v12/core/router"
- "github.com/gorilla/mux"
+ {{- range .RouterImports}}
+ {{if .Alias}}{{.Alias}} {{end}}"{{.Package}}"
+ {{- end}}
{{- range .ExternalImports}}
{{ . }}
{{- end}}
diff --git a/pkg/codegen/templates/inline.tmpl b/pkg/codegen/templates/inline.tmpl
index 0124121566..b76ec33365 100644
--- a/pkg/codegen/templates/inline.tmpl
+++ b/pkg/codegen/templates/inline.tmpl
@@ -1,24 +1,26 @@
-// Base64 encoded, gzipped, json marshaled Swagger object
+// Base64 encoded, compressed with deflate, json marshaled OpenAPI spec.
+// Stored as a slice of fixed-width chunks rather than one concatenated
+// const string: with thousands of chunks the chained `+` fold is several
+// times slower for the Go compiler than parsing a slice literal.
var swaggerSpec = []string{
-{{range .SpecParts}}
- "{{.}}",{{end}}
-}
+{{range .SpecParts}} "{{.}}",
+{{end}}}
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+// decodeSpec returns the embedded OpenAPI spec as raw JSON bytes,
+// after base64-decoding and flate-decompressing the embedded blob.
func decodeSpec() ([]byte, error) {
- zipped, err := base64.StdEncoding.DecodeString(strings.Join(swaggerSpec, ""))
+ encoded := strings.Join(swaggerSpec, "")
+ compressed, err := base64.StdEncoding.DecodeString(encoded)
if err != nil {
return nil, fmt.Errorf("error base64 decoding spec: %w", err)
}
- zr, err := gzip.NewReader(bytes.NewReader(zipped))
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
- }
+ zr := flate.NewReader(bytes.NewReader(compressed))
var buf bytes.Buffer
- _, err = buf.ReadFrom(zr)
- if err != nil {
- return nil, fmt.Errorf("error decompressing spec: %w", err)
+ if _, err := buf.ReadFrom(zr); err != nil {
+ return nil, fmt.Errorf("read flate: %w", err)
+ }
+ if err := zr.Close(); err != nil {
+ return nil, fmt.Errorf("close flate reader: %w", err)
}
return buf.Bytes(), nil
@@ -26,7 +28,7 @@ func decodeSpec() ([]byte, error) {
var rawSpec = decodeSpecCached()
-// a naive cached of a decoded swagger spec
+// a naive cache of the decoded OpenAPI spec
func decodeSpecCached() func() ([]byte, error) {
data, err := decodeSpec()
return func() ([]byte, error) {
@@ -40,26 +42,23 @@ func PathToRawSpec(pathToFile string) map[string]func() ([]byte, error) {
if len(pathToFile) > 0 {
res[pathToFile] = rawSpec
}
- {{ if .ImportMapping }}
- pathPrefix := path.Dir(pathToFile)
- {{ end }}
- {{ range $key, $value := .ImportMapping }}
- for rawPath, rawFunc := range {{ $value.Name }}.PathToRawSpec(path.Join(pathPrefix, "{{ $key }}")) {
+ {{ range $key, $value := .ImportMapping }}{{- if ne $value.Path "-"}}
+ for rawPath, rawFunc := range {{ $value.Name }}.PathToRawSpec(path.Join(path.Dir(pathToFile), "{{ $key }}")) {
if _, ok := res[rawPath]; ok {
// it is not possible to compare functions in golang, so always overwrite the old value
}
res[rawPath] = rawFunc
}
- {{- end }}
+ {{- end }}{{- end }}
return res
}
-// GetSwagger returns the Swagger specification corresponding to the generated code
-// in this file. The external references of Swagger specification are resolved.
-// The logic of resolving external references is tightly connected to "import-mapping" feature.
-// Externally referenced files must be embedded in the corresponding golang packages.
-// Urls can be supported but this task was out of the scope.
-func GetSwagger() (swagger *openapi3.T, err error) {
+// GetSpec returns the OpenAPI specification corresponding to the generated
+// code in this file. External references in the spec are resolved through
+// PathToRawSpec; externally-referenced files must be embedded in their
+// corresponding Go packages (via the import-mapping feature). URL-based
+// external refs are not supported.
+func GetSpec() (swagger *openapi3.T, err error) {
resolvePath := PathToRawSpec("")
loader := openapi3.NewLoader()
@@ -85,3 +84,22 @@ func GetSwagger() (swagger *openapi3.T, err error) {
}
return
}
+
+// GetSpecJSON returns the raw JSON bytes of the embedded OpenAPI
+// specification: decompressed but not unmarshaled. External references
+// are not resolved here; the bytes are the spec exactly as embedded by
+// codegen. The result is cached at package init time, so repeated calls
+// are cheap.
+func GetSpecJSON() ([]byte, error) {
+ return rawSpec()
+}
+
+// GetSwagger returns the OpenAPI specification corresponding to the
+// generated code in this file.
+//
+// Deprecated: GetSwagger predates kin-openapi renaming openapi3.Swagger
+// to openapi3.T. Use [GetSpec] instead. This wrapper is retained for
+// backwards compatibility.
+func GetSwagger() (*openapi3.T, error) {
+ return GetSpec()
+}
diff --git a/pkg/codegen/templates/iris/iris-handler.tmpl b/pkg/codegen/templates/iris/iris-handler.tmpl
index 3f1228faea..c0c5b23cc5 100644
--- a/pkg/codegen/templates/iris/iris-handler.tmpl
+++ b/pkg/codegen/templates/iris/iris-handler.tmpl
@@ -17,7 +17,7 @@ func RegisterHandlersWithOptions(router *iris.Application, si ServerInterface, o
Handler: si,
}
{{end}}
-{{range .}}router.{{.Method | lower | title}}(options.BaseURL + "{{.Path | swaggerUriToIrisUri}}", wrapper.{{.OperationId}})
+{{range .}}router.{{.Method | lower | title}}(options.BaseURL + "{{.Path | swaggerUriToIrisUri}}", wrapper.{{.HandlerName}})
{{end}}
router.Build()
}
diff --git a/pkg/codegen/templates/iris/iris-interface.tmpl b/pkg/codegen/templates/iris/iris-interface.tmpl
index fb53a124b9..78f401ec2c 100644
--- a/pkg/codegen/templates/iris/iris-interface.tmpl
+++ b/pkg/codegen/templates/iris/iris-interface.tmpl
@@ -1,7 +1,7 @@
// ServerInterface represents all server handlers.
type ServerInterface interface {
-{{range .}}{{.SummaryAsComment }}
+{{range .}}{{if not .IsAlias}}{{.SummaryAsComment }}
// ({{.Method}} {{.Path}})
{{.OperationId}}(ctx iris.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}})
-{{end}}
+{{end}}{{end}}
}
diff --git a/pkg/codegen/templates/iris/iris-middleware.tmpl b/pkg/codegen/templates/iris/iris-middleware.tmpl
index 6f0b949a47..769f2331bc 100644
--- a/pkg/codegen/templates/iris/iris-middleware.tmpl
+++ b/pkg/codegen/templates/iris/iris-middleware.tmpl
@@ -5,19 +5,20 @@ type ServerInterfaceWrapper struct {
type MiddlewareFunc iris.Handler
-{{range .}}{{$opid := .OperationId}}// {{$opid}} converts iris context to params.
+{{range .}}{{$opid := .OperationId}}{{if not .IsAlias}}// {{$opid}} converts iris context to params.
func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) {
{{if or .RequiresParamObject (gt (len .PathParams) 0) }}
var err error
+ _ = err
{{end}}
{{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" -------------
var {{$varName := .GoVariableName}}{{$varName}} {{.TypeDef}}
{{if .IsPassThrough}}
- {{$varName}} = ctx.URLParam("{{.ParamName}}")
+ {{$varName}} = ctx.Params().Get("{{.ParamName}}")
{{end}}
{{if .IsJson}}
- err = json.Unmarshal([]byte(ctx.URLParam("{{.ParamName}}")), &{{$varName}})
+ err = json.Unmarshal([]byte(ctx.Params().Get("{{.ParamName}}")), &{{$varName}})
if err != nil {
ctx.StatusCode(http.StatusBadRequest)
ctx.WriteString("Error unmarshaling parameter '{{.ParamName}}' as JSON")
@@ -25,7 +26,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) {
}
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationPath, ctx.Params().Get("{{.ParamName}}"), &{{$varName}})
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", ctx.Params().Get("{{.ParamName}}"), &{{$varName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
ctx.StatusCode(http.StatusBadRequest)
ctx.Writef("Invalid format for parameter {{.ParamName}}: %s", err)
@@ -35,7 +36,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) {
{{end}}
{{range .SecurityDefinitions}}
- ctx.Set({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}})
+ ctx.Set(string({{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes), {{toStringArray .Scopes}})
{{end}}
{{if .RequiresParamObject}}
@@ -46,16 +47,16 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) {
// ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
{{ end }}
{{if .IsStyled}}
- err = runtime.BindQueryParameter("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", ctx.Request().URL.Query(), ¶ms.{{.GoName}})
+ err = runtime.BindQueryParameterWithOptions("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", ctx.Request().URL.Query(), ¶ms.{{.GoName}}, runtime.BindQueryParameterOptions{Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
ctx.StatusCode(http.StatusBadRequest)
ctx.Writef("Invalid format for parameter {{.ParamName}}: %s", err)
return
}
{{else}}
- if paramValue := ctx.QueryParam("{{.ParamName}}"); paramValue != "" {
+ if paramValue := ctx.URLParam("{{.ParamName}}"); paramValue != "" {
{{if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}paramValue
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}paramValue
{{end}}
{{if .IsJson}}
var value {{.TypeDef}}
@@ -65,7 +66,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) {
ctx.WriteString("Error unmarshaling parameter '{{.ParamName}}' as JSON")
return
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
}{{if .Required}} else {
ctx.StatusCode(http.StatusBadRequest)
@@ -87,7 +88,7 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) {
return
}
{{if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}valueList[0]
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}valueList[0]
{{end}}
{{if .IsJson}}
err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}})
@@ -98,14 +99,14 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) {
}
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameterWithLocation("{{.Style}}",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationHeader, valueList[0], &{{.GoName}})
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", valueList[0], &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
ctx.StatusCode(http.StatusBadRequest)
ctx.Writef("Invalid format for parameter {{.ParamName}}: %s", err)
return
}
{{end}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}{{.GoName}}
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}{{.GoName}}
} {{if .Required}}else {
ctx.StatusCode(http.StatusBadRequest)
ctx.WriteString("Header {{.ParamName}} is required, but not found")
@@ -115,14 +116,14 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) {
{{end}}
{{range .CookieParams}}
- if cookie, err := ctx.Cookie("{{.ParamName}}"); err == nil {
+ if cookie := ctx.GetCookie("{{.ParamName}}"); cookie != "" {
{{if .IsPassThrough}}
- params.{{.GoName}} = {{if not .Required}}&{{end}}cookie.Value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}cookie
{{end}}
{{if .IsJson}}
var value {{.TypeDef}}
var decoded string
- decoded, err := url.QueryUnescape(cookie.Value)
+ decoded, err := url.QueryUnescape(cookie)
if err != nil {
ctx.StatusCode(http.StatusBadRequest)
ctx.WriteString("Error unescaping cookie parameter '{{.ParamName}}'")
@@ -134,17 +135,17 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) {
ctx.WriteString("Error unmarshaling parameter '{{.ParamName}}' as JSON")
return
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
{{if .IsStyled}}
var value {{.TypeDef}}
- err = runtime.BindStyledParameterWithLocation("simple",{{.Explode}}, "{{.ParamName}}", runtime.ParamLocationCookie, cookie.Value, &value)
+ err = runtime.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
if err != nil {
ctx.StatusCode(http.StatusBadRequest)
ctx.Writef("Invalid format for parameter {{.ParamName}}: %s", err)
return
}
- params.{{.GoName}} = {{if not .Required}}&{{end}}value
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
{{end}}
}{{if .Required}} else {
ctx.StatusCode(http.StatusBadRequest)
@@ -158,4 +159,4 @@ func (w *ServerInterfaceWrapper) {{.OperationId}} (ctx iris.Context) {
// Invoke the callback with all the unmarshaled arguments
w.Handler.{{.OperationId}}(ctx{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
}
-{{end}}
+{{end}}{{end}}
diff --git a/pkg/codegen/templates/server-urls.tmpl b/pkg/codegen/templates/server-urls.tmpl
new file mode 100644
index 0000000000..b0cf2a86a5
--- /dev/null
+++ b/pkg/codegen/templates/server-urls.tmpl
@@ -0,0 +1,86 @@
+{{ range . }}
+{{ $usedVars := .UsedVariables }}
+{{ $undeclared := .UndeclaredPlaceholders }}
+{{ if and (eq 0 (len $usedVars)) (eq 0 (len $undeclared)) }}
+{{/* URLs without variables (declared or used) are straightforward, so we'll create them a constant */}}
+// {{ .GoName }} defines the Server URL for {{ if len .OAPISchema.Description }}{{ stripNewLines .OAPISchema.Description }}{{ else }}{{ stripNewLines .OAPISchema.URL }}{{ end }}
+const {{ .GoName}} = {{ .OAPISchema.URL | toGoString }}
+{{ else }}
+{{/* URLs with variables are not straightforward, as we may need multiple types, and so will model them as a function */}}
+
+{{ $goName := .GoName }}
+
+{{/*
+ For each USED variable, emit any inline declarations server-urls.tmpl
+ is still responsible for. Variables declared but not referenced by
+ a `{name}` placeholder in the URL are filtered out earlier
+ (https://github.com/oapi-codegen/oapi-codegen/issues/2004) so we
+ don't generate types/consts/params that the function would never
+ use.
+
+ * Variables with `enum` get their `type` declaration and `const`
+ block (and a `Valid()` method) from typedef.tmpl + constants.tmpl
+ via GenerateEnums; here we only emit the optional default-pointer
+ constant — and we name it `…VariableDefaultValue` so it can never
+ collide with an enum value whose Go identifier is `Default` (e.g.
+ OpenAPI `enum: [default]`).
+
+ * Variables without `enum` need their `type Foo string` and any
+ `const FooDefault = "…"` emitted here, since the generic enum
+ path has nothing to contribute for a non-enum string.
+*/}}
+{{ range $k, $v := $usedVars }}
+ {{ $prefix := printf "%s%sVariable" $goName ($k | ucFirst) }}
+ {{ if eq (len $v.Enum) 0 }}
+ // {{ $prefix }} is the `{{ $k }}` variable for {{ $goName }}
+ type {{ $prefix }} string
+ {{ if $v.Default }}
+ // {{ $prefix }}Default is the default value for the `{{ $k }}` variable for {{ $goName }}
+ const {{ $prefix }}Default = {{ $v.Default | toGoString }}
+ {{ end }}
+ {{ end }}
+{{ end }}
+
+{{/*
+ Enum-typed default-pointer constants. Their identifier names are
+ pre-computed in Go (ServerObjectDefinition.EnumDefaultPointers) so
+ that the pointer's reference to the enum-value constant always
+ matches the post-dedup name actually emitted by constants.tmpl,
+ and the pointer itself is renamed `…DefaultValue` only for specs
+ that would have collided under the old codegen anyway.
+*/}}
+{{ range .EnumDefaultPointers }}
+ // {{ .PointerName }} is the default choice, for the accepted values for the `{{ .VariableName }}` variable
+ const {{ .PointerName }} {{ .TypeName }} = {{ .TargetName }}
+{{ end }}
+
+
+// New{{ .GoName }} constructs the Server URL for {{ stripNewLines .OAPISchema.Description }}, with the provided variables.
+func New{{ .GoName }}({{ .NewServerFunctionParams }}) (string, error) {
+ {{ range $k, $v := $usedVars }}
+ {{- if gt (len $v.Enum) 0 -}}
+ if !{{ $k }}.Valid() {
+ return "", fmt.Errorf("`%v` is not one of the accepted values for the `{{ $k }}` variable", {{ $k }})
+ }
+ {{ end -}}
+ {{ end }}
+ u := {{ .OAPISchema.URL | toGoString }}
+
+ {{ range $k, $v := $usedVars }}
+ {{- $placeholder := printf "{%s}" $k -}}
+ u = strings.ReplaceAll(u, "{{ $placeholder }}", string({{ $k }}))
+ {{ end }}
+ {{ range $k := $undeclared }}
+ {{- $placeholder := printf "{%s}" $k -}}
+ u = strings.ReplaceAll(u, "{{ $placeholder }}", {{ $k }})
+ {{ end }}
+
+ if strings.Contains(u, "{") || strings.Contains(u, "}") {
+ return "", fmt.Errorf("after mapping variables, there were still `{` or `}` characters in the string: %#v", u)
+ }
+
+ return u, nil
+}
+
+{{ end }}
+{{ end }}
diff --git a/pkg/codegen/templates/stdhttp/std-http-handler.tmpl b/pkg/codegen/templates/stdhttp/std-http-handler.tmpl
new file mode 100644
index 0000000000..63fccd2445
--- /dev/null
+++ b/pkg/codegen/templates/stdhttp/std-http-handler.tmpl
@@ -0,0 +1,55 @@
+// Handler creates http.Handler with routing matching OpenAPI spec.
+func Handler(si ServerInterface) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions{})
+}
+
+// ServeMux is an abstraction of [http.ServeMux].
+type ServeMux interface {
+ HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
+ http.Handler
+}
+
+type StdHTTPServerOptions struct {
+ BaseURL string
+ BaseRouter ServeMux
+ Middlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+// HandlerFromMux creates http.Handler with routing matching OpenAPI spec based on the provided mux.
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions {
+ BaseRouter: m,
+ })
+}
+
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
+ return HandlerWithOptions(si, StdHTTPServerOptions {
+ BaseURL: baseURL,
+ BaseRouter: m,
+ })
+}
+
+// HandlerWithOptions creates http.Handler with additional options
+func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.Handler {
+ m := options.BaseRouter
+
+ if m == nil {
+ m = http.NewServeMux()
+ }
+ if options.ErrorHandlerFunc == nil {
+ options.ErrorHandlerFunc = func(w http.ResponseWriter, r *http.Request, err error) {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ }
+ }
+{{if .}}
+ wrapper := ServerInterfaceWrapper{
+ Handler: si,
+ HandlerMiddlewares: options.Middlewares,
+ ErrorHandlerFunc: options.ErrorHandlerFunc,
+ }
+{{end}}
+{{range .}}m.HandleFunc({{.Method | httpMethodConstant}}+" "+options.BaseURL+"{{.Path | swaggerUriToStdHttpUri}}", wrapper.{{.HandlerName}})
+{{end}}
+ return m
+}
diff --git a/pkg/codegen/templates/stdhttp/std-http-interface.tmpl b/pkg/codegen/templates/stdhttp/std-http-interface.tmpl
new file mode 100644
index 0000000000..04baa51e39
--- /dev/null
+++ b/pkg/codegen/templates/stdhttp/std-http-interface.tmpl
@@ -0,0 +1,7 @@
+// ServerInterface represents all server handlers.
+type ServerInterface interface {
+{{range .}}{{if not .IsAlias}}{{.SummaryAsComment }}
+// ({{.Method}} {{.Path}})
+{{.OperationId}}(w http.ResponseWriter, r *http.Request{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}})
+{{end}}{{end}}
+}
diff --git a/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl b/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl
new file mode 100644
index 0000000000..8058ed1714
--- /dev/null
+++ b/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl
@@ -0,0 +1,272 @@
+// ServerInterfaceWrapper converts contexts to parameters.
+type ServerInterfaceWrapper struct {
+ Handler ServerInterface
+ HandlerMiddlewares []MiddlewareFunc
+ ErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
+}
+
+type MiddlewareFunc func(http.Handler) http.Handler
+
+{{range .}}{{$opid := .OperationId}}
+{{if not .IsAlias}}
+// {{$opid}} operation middleware
+func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Request) {
+ {{if or .RequiresParamObject (gt (len .PathParams) 0) }}
+ var err error
+ _ = err
+ {{end}}
+
+ {{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" -------------
+ var {{$varName := .GoVariableName}}{{$varName}} {{.TypeDef}}
+
+ {{if .IsPassThrough}}
+ {{$varName}} = r.PathValue("{{.SanitizedParamName}}")
+ {{end}}
+ {{if .IsJson}}
+ err = json.Unmarshal([]byte(r.PathValue("{{.SanitizedParamName}}")), &{{$varName}})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
+ return
+ }
+ {{end}}
+ {{if .IsStyled}}
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", r.PathValue("{{.SanitizedParamName}}"), &{{$varName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
+ return
+ }
+ {{end}}
+
+ {{end}}
+
+ {{if .SecurityDefinitions -}}
+ ctx := r.Context()
+{{range .SecurityDefinitions}}
+ ctx = context.WithValue(ctx, {{.ProviderName | sanitizeGoIdentity | ucFirst}}Scopes, {{toStringArray .Scopes}})
+{{end}}
+ r = r.WithContext(ctx)
+ {{end}}
+
+ {{if .RequiresParamObject}}
+ // Parameter object where we will unmarshal all parameters from the context
+ var params {{.OperationId}}Params
+
+ {{range $paramIdx, $param := .QueryParams}}
+ {{- if (or (or .Required .IsPassThrough) (or .IsJson .IsStyled)) -}}
+ // ------------- {{if .Required}}Required{{else}}Optional{{end}} query parameter "{{.ParamName}}" -------------
+ {{ end }}
+ {{ if (or .IsPassThrough .IsJson) }}
+ if paramValue := r.URL.Query().Get("{{.ParamName}}"); paramValue != "" {
+
+ {{if .IsPassThrough}}
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}paramValue
+ {{end}}
+
+ {{if .IsJson}}
+ var value {{.TypeDef}}
+ err = json.Unmarshal([]byte(paramValue), &value)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
+ return
+ }
+
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
+ {{end}}
+ }{{if .Required}} else {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"})
+ return
+ }{{end}}
+ {{end}}
+ {{if .IsStyled}}
+ err = runtime.BindQueryParameterWithOptions("{{.Style}}", {{.Explode}}, {{.Required}}, "{{.ParamName}}", r.URL.Query(), ¶ms.{{.GoName}}, runtime.BindQueryParameterOptions{Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
+ if err != nil {
+ var requiredError *runtime.RequiredParameterError
+ if errors.As(err, &requiredError) {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"})
+ } else {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
+ }
+ return
+ }
+ {{end}}
+ {{end}}
+
+ {{if .HeaderParams}}
+ headers := r.Header
+
+ {{range .HeaderParams}}// ------------- {{if .Required}}Required{{else}}Optional{{end}} header parameter "{{.ParamName}}" -------------
+ if valueList, found := headers[http.CanonicalHeaderKey("{{.ParamName}}")]; found {
+ var {{.GoName}} {{.TypeDef}}
+ n := len(valueList)
+ if n != 1 {
+ siw.ErrorHandlerFunc(w, r, &TooManyValuesForParamError{ParamName: "{{.ParamName}}", Count: n})
+ return
+ }
+
+ {{if .IsPassThrough}}
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}valueList[0]
+ {{end}}
+
+ {{if .IsJson}}
+ err = json.Unmarshal([]byte(valueList[0]), &{{.GoName}})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
+ return
+ }
+ {{end}}
+
+ {{if .IsStyled}}
+ err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", valueList[0], &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
+ return
+ }
+ {{end}}
+
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}{{.GoName}}
+
+ } {{if .Required}}else {
+ err := fmt.Errorf("Header parameter {{.ParamName}} is required, but not found")
+ siw.ErrorHandlerFunc(w, r, &RequiredHeaderError{ParamName: "{{.ParamName}}", Err: err})
+ return
+ }{{end}}
+
+ {{end}}
+ {{end}}
+
+ {{range .CookieParams}}
+ {
+ var cookie *http.Cookie
+
+ if cookie, err = r.Cookie("{{.ParamName}}"); err == nil {
+
+ {{- if .IsPassThrough}}
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}cookie.Value
+ {{end}}
+
+ {{- if .IsJson}}
+ var value {{.TypeDef}}
+ var decoded string
+ decoded, err := url.QueryUnescape(cookie.Value)
+ if err != nil {
+ err = fmt.Errorf("Error unescaping cookie parameter '{{.ParamName}}'")
+ siw.ErrorHandlerFunc(w, r, &UnescapedCookieParamError{ParamName: "{{.ParamName}}", Err: err})
+ return
+ }
+
+ err = json.Unmarshal([]byte(decoded), &value)
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &UnmarshalingParamError{ParamName: "{{.ParamName}}", Err: err})
+ return
+ }
+
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
+ {{end}}
+
+ {{- if .IsStyled}}
+ var value {{.TypeDef}}
+ err = runtime.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: {{.Explode}}, Required: {{.Required}}, Type: "{{.SchemaType}}", Format: "{{.SchemaFormat}}"})
+ if err != nil {
+ siw.ErrorHandlerFunc(w, r, &InvalidParamFormatError{ParamName: "{{.ParamName}}", Err: err})
+ return
+ }
+ params.{{.GoName}} = {{if .HasOptionalPointer}}&{{end}}value
+ {{end}}
+
+ }
+
+ {{- if .Required}} else {
+ siw.ErrorHandlerFunc(w, r, &RequiredParamError{ParamName: "{{.ParamName}}"})
+ return
+ }
+ {{- end}}
+ }
+ {{end}}
+ {{end}}
+
+ handler := http.Handler(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ siw.Handler.{{.OperationId}}(w, r{{genParamNames .PathParams}}{{if .RequiresParamObject}}, params{{end}})
+ }))
+
+ {{if opts.Compatibility.ApplyChiMiddlewareFirstToLast}}
+ for i := len(siw.HandlerMiddlewares) -1; i >= 0; i-- {
+ handler = siw.HandlerMiddlewares[i](handler)
+ }
+ {{else}}
+ for _, middleware := range siw.HandlerMiddlewares {
+ handler = middleware(handler)
+ }
+ {{end}}
+
+ handler.ServeHTTP(w, r)
+}
+{{end}}{{end}}
+
+type UnescapedCookieParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnescapedCookieParamError) Error() string {
+ return fmt.Sprintf("error unescaping cookie parameter '%s'", e.ParamName)
+}
+
+func (e *UnescapedCookieParamError) Unwrap() error {
+ return e.Err
+}
+
+type UnmarshalingParamError struct {
+ ParamName string
+ Err error
+}
+
+func (e *UnmarshalingParamError) Error() string {
+ return fmt.Sprintf("Error unmarshaling parameter %s as JSON: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *UnmarshalingParamError) Unwrap() error {
+ return e.Err
+}
+
+type RequiredParamError struct {
+ ParamName string
+}
+
+func (e *RequiredParamError) Error() string {
+ return fmt.Sprintf("Query argument %s is required, but not found", e.ParamName)
+}
+
+type RequiredHeaderError struct {
+ ParamName string
+ Err error
+}
+
+func (e *RequiredHeaderError) Error() string {
+ return fmt.Sprintf("Header parameter %s is required, but not found", e.ParamName)
+}
+
+func (e *RequiredHeaderError) Unwrap() error {
+ return e.Err
+}
+
+type InvalidParamFormatError struct {
+ ParamName string
+ Err error
+}
+
+func (e *InvalidParamFormatError) Error() string {
+ return fmt.Sprintf("Invalid format for parameter %s: %s", e.ParamName, e.Err.Error())
+}
+
+func (e *InvalidParamFormatError) Unwrap() error {
+ return e.Err
+}
+
+type TooManyValuesForParamError struct {
+ ParamName string
+ Count int
+}
+
+func (e *TooManyValuesForParamError) Error() string {
+ return fmt.Sprintf("Expected one value for %s, got %d", e.ParamName, e.Count)
+}
diff --git a/pkg/codegen/templates/strict/strict-echo.tmpl b/pkg/codegen/templates/strict/strict-echo.tmpl
index 0955fabf7e..0683c15e30 100644
--- a/pkg/codegen/templates/strict/strict-echo.tmpl
+++ b/pkg/codegen/templates/strict/strict-echo.tmpl
@@ -1,5 +1,5 @@
-type StrictHandlerFunc = strictecho.StrictEchoHandlerFunc
-type StrictMiddlewareFunc = strictecho.StrictEchoMiddlewareFunc
+type StrictHandlerFunc func(ctx echo.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
return &strictHandler{ssi: ssi, middlewares: middlewares}
@@ -12,6 +12,7 @@ type strictHandler struct {
{{range .}}
{{$opid := .OperationId}}
+ {{if not .IsAlias}}
// {{$opid}} operation middleware
func (sh *strictHandler) {{.OperationId}}(ctx echo.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) error {
var request {{$opid | ucFirst}}RequestObject
@@ -30,13 +31,20 @@ type strictHandler struct {
{{$multipleBodies := gt (len .Bodies) 1 -}}
{{range .Bodies -}}
- {{if $multipleBodies}}if strings.HasPrefix(ctx.Request().Header.Get("Content-Type"), "{{.ContentType}}") { {{end}}
+ {{if $multipleBodies}}if strings.HasPrefix(ctx.Request().Header.Get("Content-Type"), {{.ContentType | toGoString}}) { {{end}}
{{if .IsJSON -}}
var body {{$opid}}{{.NameTag}}RequestBody
if err := ctx.Bind(&body); err != nil {
+ {{if not .Required -}}
+ if !errors.Is(err, io.EOF) {
+ return err
+ }
+ {{else -}}
return err
- }
+ {{end -}}
+ } {{if not .Required -}} else { {{end}}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{if not .Required -}} } {{end}}
{{else if eq .NameTag "Formdata" -}}
if form, err := ctx.FormParams(); err == nil {
var body {{$opid}}{{.NameTag}}RequestBody
@@ -48,18 +56,34 @@ type strictHandler struct {
return err
}
{{else if eq .NameTag "Multipart" -}}
+ {{if eq .ContentType "multipart/form-data" -}}
if reader, err := ctx.Request().MultipartReader(); err != nil {
return err
} else {
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = reader
}
+ {{else -}}
+ if _, params, err := mime.ParseMediaType(ctx.Request().Header.Get("Content-Type")); err != nil {
+ return err
+ } else if boundary := params["boundary"]; boundary == "" {
+ return http.ErrMissingBoundary
+ } else {
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = multipart.NewReader(ctx.Request().Body, boundary)
+ }
+ {{end -}}
{{else if eq .NameTag "Text" -}}
data, err := io.ReadAll(ctx.Request().Body)
if err != nil {
return err
}
+ {{if not .Required -}}
+ if len(data) > 0 {
+ {{end -}}
body := {{$opid}}{{.NameTag}}RequestBody(data)
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{if not .Required -}}
+ }
+ {{end -}}
{{else -}}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = ctx.Request().Body
{{end}}{{/* if eq .NameTag "JSON" */ -}}
@@ -84,4 +108,5 @@ type strictHandler struct {
}
return nil
}
+ {{end}}
{{end}}
diff --git a/pkg/codegen/templates/strict/strict-echo5.tmpl b/pkg/codegen/templates/strict/strict-echo5.tmpl
new file mode 100644
index 0000000000..687dd57a8b
--- /dev/null
+++ b/pkg/codegen/templates/strict/strict-echo5.tmpl
@@ -0,0 +1,99 @@
+type StrictHandlerFunc func(ctx *echo.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
+ return &strictHandler{ssi: ssi, middlewares: middlewares}
+}
+
+type strictHandler struct {
+ ssi StrictServerInterface
+ middlewares []StrictMiddlewareFunc
+}
+
+{{range .}}
+ {{$opid := .OperationId}}
+ {{if not .IsAlias}}
+ // {{$opid}} operation middleware
+ func (sh *strictHandler) {{.OperationId}}(ctx *echo.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) error {
+ var request {{$opid | ucFirst}}RequestObject
+
+ {{range .PathParams -}}
+ request.{{.GoName}} = {{.GoVariableName}}
+ {{end -}}
+
+ {{if .RequiresParamObject -}}
+ request.Params = params
+ {{end -}}
+
+ {{ if .HasMaskedRequestContentTypes -}}
+ request.ContentType = ctx.Request().Header.Get("Content-Type")
+ {{end -}}
+
+ {{$multipleBodies := gt (len .Bodies) 1 -}}
+ {{range .Bodies -}}
+ {{if $multipleBodies}}if strings.HasPrefix(ctx.Request().Header.Get("Content-Type"), {{.ContentType | toGoString}}) { {{end}}
+ {{if .IsJSON -}}
+ var body {{$opid}}{{.NameTag}}RequestBody
+ if err := ctx.Bind(&body); err != nil {
+ return err
+ }
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{else if eq .NameTag "Formdata" -}}
+ if form, err := ctx.FormValues(); err == nil {
+ var body {{$opid}}{{.NameTag}}RequestBody
+ if err := runtime.BindForm(&body, form, nil, nil); err != nil {
+ return err
+ }
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ } else {
+ return err
+ }
+ {{else if eq .NameTag "Multipart" -}}
+ {{if eq .ContentType "multipart/form-data" -}}
+ if reader, err := ctx.Request().MultipartReader(); err != nil {
+ return err
+ } else {
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = reader
+ }
+ {{else -}}
+ if _, params, err := mime.ParseMediaType(ctx.Request().Header.Get("Content-Type")); err != nil {
+ return err
+ } else if boundary := params["boundary"]; boundary == "" {
+ return http.ErrMissingBoundary
+ } else {
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = multipart.NewReader(ctx.Request().Body, boundary)
+ }
+ {{end -}}
+ {{else if eq .NameTag "Text" -}}
+ data, err := io.ReadAll(ctx.Request().Body)
+ if err != nil {
+ return err
+ }
+ body := {{$opid}}{{.NameTag}}RequestBody(data)
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{else -}}
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = ctx.Request().Body
+ {{end}}{{/* if eq .NameTag "JSON" */ -}}
+ {{if $multipleBodies}}}{{end}}
+ {{end}}{{/* range .Bodies */}}
+
+ handler := func(ctx *echo.Context, request interface{}) (interface{}, error){
+ return sh.ssi.{{.OperationId}}(ctx.Request().Context(), request.({{$opid | ucFirst}}RequestObject))
+ }
+ for _, middleware := range sh.middlewares {
+ handler = middleware(handler, "{{.OperationId}}")
+ }
+
+ response, err := handler(ctx, request)
+
+ if err != nil {
+ return err
+ } else if validResponse, ok := response.({{$opid | ucFirst}}ResponseObject); ok {
+ return validResponse.Visit{{$opid}}Response(ctx.Response())
+ } else if response != nil {
+ return fmt.Errorf("unexpected response type: %T", response)
+ }
+ return nil
+ }
+ {{end}}
+{{end}}
diff --git a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl
index adeda659a8..a88607a88b 100644
--- a/pkg/codegen/templates/strict/strict-fiber-interface.tmpl
+++ b/pkg/codegen/templates/strict/strict-fiber-interface.tmpl
@@ -1,4 +1,4 @@
-{{range .}}
+{{range .}}{{if not .IsAlias}}
{{$opid := .OperationId -}}
type {{$opid | ucFirst}}RequestObject struct {
{{range .PathParams -}}
@@ -26,13 +26,13 @@
{{$fixedStatusCode := .HasFixedStatusCode -}}
{{$isRef := .IsRef -}}
{{$isExternalRef := .IsExternalRef -}}
- {{$ref := .Ref | ucFirst -}}
+ {{$ref := .Ref | ucFirstWithPkgName -}}
{{$headers := .Headers -}}
{{if (and $hasHeaders (not $isRef)) -}}
type {{$opid}}{{$statusCode}}ResponseHeaders struct {
{{range .Headers -}}
- {{.GoName}} {{.Schema.TypeDecl}}
+ {{.GoName}} {{.GoTypeDef}}
{{end -}}
}
{{end}}
@@ -40,13 +40,23 @@
{{range .Contents}}
{{$receiverTypeName := printf "%s%s%s%s" $opid $statusCode .NameTagOrContentType "Response"}}
{{if and $fixedStatusCode $isRef -}}
- {{ if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) (eq .NameTag "Multipart") -}}
+ {{ if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) (or (eq .NameTag "Multipart") (eq .NameTag "Text")) -}}
type {{$receiverTypeName}} {{$ref}}{{.NameTagOrContentType}}Response
{{else -}}
type {{$receiverTypeName}} struct{ {{$ref}}{{.NameTagOrContentType}}Response }
{{end}}
{{else if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) -}}
- type {{$receiverTypeName}} {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{if .Schema.IsRef}}={{end}} {{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
+ type {{$receiverTypeName}} {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{if and .Schema.IsRef (not .Schema.IsExternalRef)}}={{end}} {{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
+ {{- if and .IsJSON .Schema.HasCustomMarshalJSON}}
+
+ func (t {{$receiverTypeName}}) MarshalJSON() ([]byte, error) {
+ return {{.Schema.TypeDecl}}(t).MarshalJSON()
+ }
+
+ func (t *{{$receiverTypeName}}) UnmarshalJSON(b []byte) error {
+ return (*{{.Schema.TypeDecl}})(t).UnmarshalJSON(b)
+ }
+ {{- end}}
{{else -}}
type {{$receiverTypeName}} struct {
Body {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
@@ -70,12 +80,22 @@
func (response {{$receiverTypeName}}) Visit{{$opid}}Response(ctx *fiber.Ctx) error {
{{range $headers -}}
- ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{if .IsNullable -}}
+ if response.Headers.{{.GoName}}.IsSpecified() {
+ ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}.MustGet()))
+ }
+ {{else if .IsOptional -}}
+ if response.Headers.{{.GoName}} != nil {
+ ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(*response.Headers.{{.GoName}}))
+ }
+ {{else -}}
+ ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{end -}}
{{end -}}
{{if eq .NameTag "Multipart" -}}
writer := multipart.NewWriter(ctx.Response().BodyWriter())
{{end -}}
- ctx.Response().Header.Set("Content-Type", {{if eq .NameTag "Multipart"}}writer.FormDataContentType(){{else if .HasFixedContentType }}"{{.ContentType}}"{{else}}response.ContentType{{end}})
+ ctx.Response().Header.Set("Content-Type", {{if eq .NameTag "Multipart"}}{{if eq .ContentType "multipart/form-data"}}writer.FormDataContentType(){{else}}mime.FormatMediaType({{.ContentType | toGoString}}, map[string]string{"boundary": writer.Boundary()}){{end}}{{else if .HasFixedContentType }}{{.ContentType | toGoString}}{{else}}response.ContentType{{end}})
{{if not .IsSupported -}}
if response.ContentLength != 0 {
ctx.Response().Header.Set("Content-Length", fmt.Sprint(response.ContentLength))
@@ -85,7 +105,7 @@
{{$hasBodyVar := or ($hasHeaders) (not $fixedStatusCode) (not .IsSupported)}}
{{if .IsJSON }}
{{$hasUnionElements := ne 0 (len .Schema.UnionElements)}}
- return ctx.JSON(&{{if $hasBodyVar}}response.Body{{else}}response{{end}}{{if $hasUnionElements}}.union{{end}})
+ return ctx.JSON(&{{if $hasBodyVar}}response.Body{{else}}response{{end}}{{if and $hasUnionElements (not .Schema.IsExternalRef)}}.union{{end}})
{{else if eq .NameTag "Text" -}}
_, err := ctx.WriteString(string({{if $hasBodyVar}}response.Body{{else}}response{{end}}))
return err
@@ -100,11 +120,38 @@
defer writer.Close()
return {{if $hasBodyVar}}response.Body{{else}}response{{end}}(writer);
{{else -}}
- if closer, ok := response.Body.(io.ReadCloser); ok {
- defer closer.Close()
- }
- _, err := io.Copy(ctx.Response().BodyWriter(), response.Body)
- return err
+ {{if .IsStreamingContentType -}}
+ // Fiber/fasthttp streams through a callback: fasthttp emits
+ // a chunk each time we call w.Flush(), so clients see
+ // streaming data immediately instead of waiting on buffering.
+ ctx.Response().SetBodyStreamWriter(func(w *bufio.Writer) {
+ if closer, ok := response.Body.(io.ReadCloser); ok {
+ defer closer.Close()
+ }
+ buf := make([]byte, 4096)
+ for {
+ n, err := response.Body.Read(buf)
+ if n > 0 {
+ if _, writeErr := w.Write(buf[:n]); writeErr != nil {
+ return
+ }
+ if flushErr := w.Flush(); flushErr != nil {
+ return
+ }
+ }
+ if err != nil {
+ return
+ }
+ }
+ })
+ return nil
+ {{else -}}
+ if closer, ok := response.Body.(io.ReadCloser); ok {
+ defer closer.Close()
+ }
+ _, err := io.Copy(ctx.Response().BodyWriter(), response.Body)
+ return err
+ {{end}}{{/* if .IsStreamingContentType */ -}}
{{end}}{{/* if eq .NameTag "JSON" */ -}}
}
{{end}}
@@ -124,20 +171,30 @@
{{end -}}
func (response {{$opid}}{{$statusCode}}Response) Visit{{$opid}}Response(ctx *fiber.Ctx) error {
{{range $headers -}}
- ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{if .IsNullable -}}
+ if response.Headers.{{.GoName}}.IsSpecified() {
+ ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}.MustGet()))
+ }
+ {{else if .IsOptional -}}
+ if response.Headers.{{.GoName}} != nil {
+ ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(*response.Headers.{{.GoName}}))
+ }
+ {{else -}}
+ ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{end -}}
{{end -}}
ctx.Status({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}})
return nil
}
{{end}}
{{end}}
-{{end}}
+{{end}}{{end}}
// StrictServerInterface represents all server handlers.
type StrictServerInterface interface {
-{{range .}}{{.SummaryAsComment }}
+{{range .}}{{if not .IsAlias}}{{.SummaryAsComment }}
// ({{.Method}} {{.Path}})
{{$opid := .OperationId -}}
{{$opid}}(ctx context.Context, request {{$opid | ucFirst}}RequestObject) ({{$opid | ucFirst}}ResponseObject, error)
-{{end}}{{/* range . */ -}}
+{{end}}{{end}}{{/* range . */ -}}
}
diff --git a/pkg/codegen/templates/strict/strict-fiber.tmpl b/pkg/codegen/templates/strict/strict-fiber.tmpl
index a36a8d7ca4..0bdc9af82d 100644
--- a/pkg/codegen/templates/strict/strict-fiber.tmpl
+++ b/pkg/codegen/templates/strict/strict-fiber.tmpl
@@ -1,5 +1,4 @@
-type StrictHandlerFunc func(ctx *fiber.Ctx, args interface{}) (interface{}, error)
-
+type StrictHandlerFunc func(ctx *fiber.Ctx, args any) (any, error)
type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
@@ -13,6 +12,7 @@ type strictHandler struct {
{{range .}}
{{$opid := .OperationId}}
+ {{if not .IsAlias}}
// {{$opid}} operation middleware
func (sh *strictHandler) {{.OperationId}}(ctx *fiber.Ctx{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) error {
var request {{$opid | ucFirst}}RequestObject
@@ -32,13 +32,20 @@ type strictHandler struct {
{{$multipleBodies := gt (len .Bodies) 1 -}}
{{range .Bodies -}}
- {{if $multipleBodies}}if strings.HasPrefix(string(ctx.Request().Header.ContentType()), "{{.ContentType}}") { {{end}}
+ {{if $multipleBodies}}if strings.HasPrefix(string(ctx.Request().Header.ContentType()), {{.ContentType | toGoString}}) { {{end}}
{{if .IsJSON }}
var body {{$opid}}{{.NameTag}}RequestBody
if err := ctx.BodyParser(&body); err != nil {
+ {{if not .Required -}}
+ if !errors.Is(err, io.EOF) {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ }
+ {{else -}}
return fiber.NewError(fiber.StatusBadRequest, err.Error())
- }
+ {{end -}}
+ } {{if not .Required -}} else { {{end}}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{if not .Required -}} } {{end}}
{{else if eq .NameTag "Formdata" -}}
var body {{$opid}}{{.NameTag}}RequestBody
if err := ctx.BodyParser(&body); err != nil {
@@ -46,11 +53,27 @@ type strictHandler struct {
}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
{{else if eq .NameTag "Multipart" -}}
+ {{if eq .ContentType "multipart/form-data" -}}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = multipart.NewReader(bytes.NewReader(ctx.Request().Body()), string(ctx.Request().Header.MultipartFormBoundary()))
+ {{else -}}
+ if _, params, err := mime.ParseMediaType(string(ctx.Request().Header.ContentType())); err != nil {
+ return fiber.NewError(fiber.StatusBadRequest, err.Error())
+ } else if boundary := params["boundary"]; boundary == "" {
+ return fiber.NewError(fiber.StatusBadRequest, http.ErrMissingBoundary.Error())
+ } else {
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = multipart.NewReader(bytes.NewReader(ctx.Request().Body()), boundary)
+ }
+ {{end -}}
{{else if eq .NameTag "Text" -}}
data := ctx.Request().Body()
+ {{if not .Required -}}
+ if len(data) > 0 {
+ {{end -}}
body := {{$opid}}{{.NameTag}}RequestBody(data)
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{if not .Required -}}
+ }
+ {{end -}}
{{else -}}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = bytes.NewReader(ctx.Request().Body())
{{end}}{{/* if eq .NameTag "JSON" */ -}}
@@ -77,4 +100,5 @@ type strictHandler struct {
}
return nil
}
+ {{end}}
{{end}}
diff --git a/pkg/codegen/templates/strict/strict-gin.tmpl b/pkg/codegen/templates/strict/strict-gin.tmpl
index 4a19170c17..ed2e561a51 100644
--- a/pkg/codegen/templates/strict/strict-gin.tmpl
+++ b/pkg/codegen/templates/strict/strict-gin.tmpl
@@ -1,17 +1,63 @@
-type StrictHandlerFunc = strictgin.StrictGinHandlerFunc
-type StrictMiddlewareFunc = strictgin.StrictGinMiddlewareFunc
+type StrictHandlerFunc func(ctx *gin.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
+
+type StrictGinServerOptions struct {
+ // RequestErrorHandlerFunc is called when a request cannot be parsed or
+ // decoded. It is invoked for JSON bind failures, form parse/bind errors,
+ // multipart reader errors, media type parse errors, missing multipart
+ // boundaries, and request body read errors. The default returns 400.
+ RequestErrorHandlerFunc func(ctx *gin.Context, err error)
+ // HandlerErrorFunc is called when the application handler (or any
+ // middleware wrapping it) returns a non-nil error. The default returns 500.
+ HandlerErrorFunc func(ctx *gin.Context, err error)
+ // ResponseErrorHandlerFunc is called when the response object fails to
+ // serialize (Visit*Response returns an error) or when the handler returns
+ // an unexpected response type. The default returns 500.
+ ResponseErrorHandlerFunc func(ctx *gin.Context, err error)
+}
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
- return &strictHandler{ssi: ssi, middlewares: middlewares}
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: StrictGinServerOptions {
+ RequestErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ },
+ HandlerErrorFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ ResponseErrorHandlerFunc: func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ },
+ }}
+}
+
+func NewStrictHandlerWithOptions(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc, options StrictGinServerOptions) ServerInterface {
+ if options.RequestErrorHandlerFunc == nil {
+ options.RequestErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusBadRequest, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.HandlerErrorFunc == nil {
+ options.HandlerErrorFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ if options.ResponseErrorHandlerFunc == nil {
+ options.ResponseErrorHandlerFunc = func(ctx *gin.Context, err error) {
+ ctx.JSON(http.StatusInternalServerError, gin.H{"msg": err.Error()})
+ }
+ }
+ return &strictHandler{ssi: ssi, middlewares: middlewares, options: options}
}
type strictHandler struct {
ssi StrictServerInterface
middlewares []StrictMiddlewareFunc
+ options StrictGinServerOptions
}
{{range .}}
{{$opid := .OperationId}}
+ {{if not .IsAlias}}
// {{$opid}} operation middleware
func (sh *strictHandler) {{.OperationId}}(ctx *gin.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) {
var request {{$opid | ucFirst}}RequestObject
@@ -30,41 +76,66 @@ type strictHandler struct {
{{$multipleBodies := gt (len .Bodies) 1 -}}
{{range .Bodies -}}
- {{if $multipleBodies}}if strings.HasPrefix(ctx.GetHeader("Content-Type"), "{{.ContentType}}") { {{end}}
+ {{if $multipleBodies}}if strings.HasPrefix(ctx.GetHeader("Content-Type"), {{.ContentType | toGoString}}) { {{end}}
{{if .IsJSON }}
var body {{$opid}}{{.NameTag}}RequestBody
- if err := ctx.ShouldBind(&body); err != nil {
- ctx.Status(http.StatusBadRequest)
- ctx.Error(err)
+ if err := ctx.ShouldBindJSON(&body); err != nil {
+ {{if not .Required -}}
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
+ }
+ {{else -}}
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
- }
+ {{end -}}
+ } {{if not .Required -}} else { {{end}}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{if not .Required -}} } {{end}}
{{else if eq .NameTag "Formdata" -}}
if err := ctx.Request.ParseForm(); err != nil {
- ctx.Error(err)
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
}
var body {{$opid}}{{.NameTag}}RequestBody
if err := runtime.BindForm(&body, ctx.Request.Form, nil, nil); err != nil {
- ctx.Error(err)
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
{{else if eq .NameTag "Multipart" -}}
- if reader, err := ctx.Request.MultipartReader(); err == nil {
- request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = reader
+ {{if eq .ContentType "multipart/form-data" -}}
+ if reader, err := ctx.Request.MultipartReader(); err != nil {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
} else {
- ctx.Error(err)
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = reader
+ }
+ {{else -}}
+ if _, params, err := mime.ParseMediaType(ctx.Request.Header.Get("Content-Type")); err != nil {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
+ return
+ } else if boundary := params["boundary"]; boundary == "" {
+ sh.options.RequestErrorHandlerFunc(ctx, http.ErrMissingBoundary)
return
+ } else {
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = multipart.NewReader(ctx.Request.Body, boundary)
}
+ {{end -}}
{{else if eq .NameTag "Text" -}}
data, err := io.ReadAll(ctx.Request.Body)
if err != nil {
- ctx.Error(err)
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
}
+ {{if not .Required -}}
+ if len(data) > 0 {
+ {{end -}}
body := {{$opid}}{{.NameTag}}RequestBody(data)
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{if not .Required -}}
+ }
+ {{end -}}
{{else -}}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = ctx.Request.Body
{{end}}{{/* if eq .NameTag "JSON" */ -}}
@@ -81,14 +152,14 @@ type strictHandler struct {
response, err := handler(ctx, request)
if err != nil {
- ctx.Error(err)
- ctx.Status(http.StatusInternalServerError)
+ sh.options.HandlerErrorFunc(ctx, err)
} else if validResponse, ok := response.({{$opid | ucFirst}}ResponseObject); ok {
if err := validResponse.Visit{{$opid}}Response(ctx.Writer); err != nil {
- ctx.Error(err)
+ sh.options.ResponseErrorHandlerFunc(ctx, err)
}
} else if response != nil {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
+ {{end}}
{{end}}
diff --git a/pkg/codegen/templates/strict/strict-http.tmpl b/pkg/codegen/templates/strict/strict-http.tmpl
index 05272af266..062e5459e4 100644
--- a/pkg/codegen/templates/strict/strict-http.tmpl
+++ b/pkg/codegen/templates/strict/strict-http.tmpl
@@ -1,5 +1,5 @@
-type StrictHandlerFunc = strictnethttp.StrictHttpHandlerFunc
-type StrictMiddlewareFunc = strictnethttp.StrictHttpMiddlewareFunc
+type StrictHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
type StrictHTTPServerOptions struct {
RequestErrorHandlerFunc func(w http.ResponseWriter, r *http.Request, err error)
@@ -29,6 +29,7 @@ type strictHandler struct {
{{range .}}
{{$opid := .OperationId}}
+ {{if not .IsAlias}}
// {{$opid}} operation middleware
func (sh *strictHandler) {{.OperationId}}(w http.ResponseWriter, r *http.Request{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) {
var request {{$opid | ucFirst}}RequestObject
@@ -47,14 +48,22 @@ type strictHandler struct {
{{$multipleBodies := gt (len .Bodies) 1 -}}
{{range .Bodies -}}
- {{if $multipleBodies}}if strings.HasPrefix(r.Header.Get("Content-Type"), "{{.ContentType}}") { {{end}}
+ {{if $multipleBodies}}if strings.HasPrefix(r.Header.Get("Content-Type"), {{.ContentType | toGoString}}) { {{end}}
{{if .IsJSON }}
var body {{$opid}}{{.NameTag}}RequestBody
if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ {{if not .Required -}}
+ if !errors.Is(err, io.EOF) {
+ sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
+ return
+ }
+ {{else -}}
sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode JSON body: %w", err))
return
- }
+ {{end -}}
+ } {{if not .Required -}} else { {{end}}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{if not .Required -}} } {{end}}
{{else if eq .NameTag "Formdata" -}}
if err := r.ParseForm(); err != nil {
sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode formdata: %w", err))
@@ -67,20 +76,38 @@ type strictHandler struct {
}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
{{else if eq .NameTag "Multipart" -}}
+ {{if eq .ContentType "multipart/form-data" -}}
if reader, err := r.MultipartReader(); err != nil {
sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't decode multipart body: %w", err))
return
} else {
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = reader
}
+ {{else -}}
+ if _, params, err := mime.ParseMediaType(r.Header.Get("Content-Type")); err != nil {
+ sh.options.RequestErrorHandlerFunc(w, r, err)
+ return
+ } else if boundary := params["boundary"]; boundary == "" {
+ sh.options.RequestErrorHandlerFunc(w, r, http.ErrMissingBoundary)
+ return
+ } else {
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = multipart.NewReader(r.Body, boundary)
+ }
+ {{end -}}
{{else if eq .NameTag "Text" -}}
data, err := io.ReadAll(r.Body)
if err != nil {
sh.options.RequestErrorHandlerFunc(w, r, fmt.Errorf("can't read body: %w", err))
return
}
+ {{if not .Required -}}
+ if len(data) > 0 {
+ {{end -}}
body := {{$opid}}{{.NameTag}}RequestBody(data)
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{if not .Required -}}
+ }
+ {{end -}}
{{else -}}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = r.Body
{{end}}{{/* if eq .NameTag "JSON" */ -}}
@@ -106,4 +133,5 @@ type strictHandler struct {
sh.options.ResponseErrorHandlerFunc(w, r, fmt.Errorf("unexpected response type: %T", response))
}
}
+ {{end}}
{{end}}
diff --git a/pkg/codegen/templates/strict/strict-interface.tmpl b/pkg/codegen/templates/strict/strict-interface.tmpl
index 8c6bcfba4b..206cc88bd1 100644
--- a/pkg/codegen/templates/strict/strict-interface.tmpl
+++ b/pkg/codegen/templates/strict/strict-interface.tmpl
@@ -1,4 +1,4 @@
-{{range .}}
+{{range .}}{{if not .IsAlias}}
{{$opid := .OperationId -}}
type {{$opid | ucFirst}}RequestObject struct {
{{range .PathParams -}}
@@ -32,23 +32,31 @@
{{if (and $hasHeaders (not $isRef)) -}}
type {{$opid}}{{$statusCode}}ResponseHeaders struct {
{{range .Headers -}}
- {{.GoName}} {{.Schema.TypeDecl}}
+ {{.GoName}} {{.GoTypeDef}}
{{end -}}
}
{{end}}
{{range .Contents}}
{{$receiverTypeName := printf "%s%s%s%s" $opid $statusCode .NameTagOrContentType "Response"}}
- {{if eq .NameTag "Text" -}}
- type {{$receiverTypeName}} string
- {{else if and $fixedStatusCode $isRef -}}
- {{ if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) (eq .NameTag "Multipart") -}}
+ {{if and $fixedStatusCode $isRef -}}
+ {{ if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) (or (eq .NameTag "Multipart") (eq .NameTag "Text")) -}}
type {{$receiverTypeName}} {{$ref}}{{.NameTagOrContentType}}Response
{{else -}}
type {{$receiverTypeName}} struct{ {{$ref}}{{.NameTagOrContentType}}Response }
{{end}}
{{else if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) -}}
- type {{$receiverTypeName}} {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{if .Schema.IsRef}}={{end}} {{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
+ type {{$receiverTypeName}} {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{if and .Schema.IsRef (not .Schema.IsExternalRef)}}={{end}} {{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
+ {{- if and .IsJSON .Schema.HasCustomMarshalJSON}}
+
+ func (t {{$receiverTypeName}}) MarshalJSON() ([]byte, error) {
+ return {{.Schema.TypeDecl}}(t).MarshalJSON()
+ }
+
+ func (t *{{$receiverTypeName}}) UnmarshalJSON(b []byte) error {
+ return (*{{.Schema.TypeDecl}})(t).UnmarshalJSON(b)
+ }
+ {{- end}}
{{else -}}
type {{$receiverTypeName}} struct {
Body {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
@@ -74,40 +82,116 @@
{{if eq .NameTag "Multipart" -}}
writer := multipart.NewWriter(w)
{{end -}}
- w.Header().Set("Content-Type", {{if eq .NameTag "Multipart"}}writer.FormDataContentType(){{else if .HasFixedContentType }}"{{.ContentType}}"{{else}}response.ContentType{{end}})
- {{if not .IsSupported -}}
- if response.ContentLength != 0 {
- w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
- }
- {{end -}}
- {{range $headers -}}
- w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
- {{end -}}
- w.WriteHeader({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}})
{{$hasBodyVar := or ($hasHeaders) (not $fixedStatusCode) (not .IsSupported)}}
{{if .IsJSON -}}
- {{$hasUnionElements := ne 0 (len .Schema.UnionElements)}}
- return json.NewEncoder(w).Encode(response{{if $hasBodyVar}}.Body{{end}}{{if $hasUnionElements}}.union{{end}})
- {{else if eq .NameTag "Text" -}}
- _, err := w.Write([]byte({{if $hasBodyVar}}response.Body{{else}}response{{end}}))
+ {{$hasUnionElements := ne 0 (len .Schema.UnionElements) -}}
+ var buf bytes.Buffer
+ if err := json.NewEncoder(&buf).Encode(response{{if $hasBodyVar}}.Body{{end}}{{if and $hasUnionElements (not .Schema.IsExternalRef)}}.union{{end}}); err != nil {
+ return err
+ }
+ w.Header().Set("Content-Type", {{if .HasFixedContentType }}{{.ContentType | toGoString}}{{else}}response.ContentType{{end}})
+ {{range $headers -}}
+ {{if .IsNullable -}}
+ if response.Headers.{{.GoName}}.IsSpecified() {
+ w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}.MustGet()))
+ }
+ {{else if .IsOptional -}}
+ if response.Headers.{{.GoName}} != nil {
+ w.Header().Set("{{.Name}}", fmt.Sprint(*response.Headers.{{.GoName}}))
+ }
+ {{else -}}
+ w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{end -}}
+ {{end -}}
+ w.WriteHeader({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}})
+ _, err := buf.WriteTo(w)
return err
{{else if eq .NameTag "Formdata" -}}
- if form, err := runtime.MarshalForm({{if $hasBodyVar}}response.Body{{else}}response{{end}}, nil); err != nil {
- return err
- } else {
- _, err := w.Write([]byte(form.Encode()))
+ form, err := runtime.MarshalForm({{if $hasBodyVar}}response.Body{{else}}response{{end}}, nil)
+ if err != nil {
return err
}
- {{else if eq .NameTag "Multipart" -}}
- defer writer.Close()
- return {{if $hasBodyVar}}response.Body{{else}}response{{end}}(writer);
- {{else -}}
- if closer, ok := response.Body.(io.ReadCloser); ok {
- defer closer.Close()
- }
- _, err := io.Copy(w, response.Body)
+ w.Header().Set("Content-Type", {{if .HasFixedContentType }}{{.ContentType | toGoString}}{{else}}response.ContentType{{end}})
+ {{range $headers -}}
+ {{if .IsNullable -}}
+ if response.Headers.{{.GoName}}.IsSpecified() {
+ w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}.MustGet()))
+ }
+ {{else if .IsOptional -}}
+ if response.Headers.{{.GoName}} != nil {
+ w.Header().Set("{{.Name}}", fmt.Sprint(*response.Headers.{{.GoName}}))
+ }
+ {{else -}}
+ w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{end -}}
+ {{end -}}
+ w.WriteHeader({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}})
+ _, err = w.Write([]byte(form.Encode()))
return err
- {{end}}{{/* if eq .NameTag "JSON" */ -}}
+ {{else -}}
+ w.Header().Set("Content-Type", {{if eq .NameTag "Multipart"}}{{if eq .ContentType "multipart/form-data"}}writer.FormDataContentType(){{else}}mime.FormatMediaType({{.ContentType | toGoString}}, map[string]string{"boundary": writer.Boundary()}){{end}}{{else if .HasFixedContentType }}{{.ContentType | toGoString}}{{else}}response.ContentType{{end}})
+ {{if not .IsSupported -}}
+ if response.ContentLength != 0 {
+ w.Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
+ }
+ {{end -}}
+ {{range $headers -}}
+ {{if .IsNullable -}}
+ if response.Headers.{{.GoName}}.IsSpecified() {
+ w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}.MustGet()))
+ }
+ {{else if .IsOptional -}}
+ if response.Headers.{{.GoName}} != nil {
+ w.Header().Set("{{.Name}}", fmt.Sprint(*response.Headers.{{.GoName}}))
+ }
+ {{else -}}
+ w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{end -}}
+ {{end -}}
+ w.WriteHeader({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}})
+
+ {{if eq .NameTag "Text" -}}
+ _, err := w.Write([]byte({{if $hasBodyVar}}response.Body{{else}}response{{end}}))
+ return err
+ {{else if eq .NameTag "Multipart" -}}
+ defer writer.Close()
+ return {{if $hasBodyVar}}response.Body{{else}}response{{end}}(writer);
+ {{else -}}
+ if closer, ok := response.Body.(io.ReadCloser); ok {
+ defer closer.Close()
+ }
+ {{if .IsStreamingContentType -}}
+ flusher, ok := w.(http.Flusher)
+ if !ok {
+ // If w doesn't support flushing, fall back to io.Copy.
+ _, err := io.Copy(w, response.Body)
+ return err
+ }
+ // text/event-stream messages are typically small; use a
+ // modest buffer and flush after each chunk so clients see
+ // events immediately instead of waiting on OS buffering.
+ buf := make([]byte, 4096)
+ for {
+ n, err := response.Body.Read(buf)
+ if n > 0 {
+ if _, writeErr := w.Write(buf[:n]); writeErr != nil {
+ return writeErr
+ }
+ flusher.Flush()
+ }
+ if err != nil {
+ if err == io.EOF {
+ return nil
+ }
+ return err
+ }
+ }
+ {{else -}}
+ _, err := io.Copy(w, response.Body)
+ return err
+ {{end}}{{/* if .IsStreamingContentType */ -}}
+ {{end}}{{/* if eq .NameTag "Text" */ -}}
+ {{end}}{{/* if .IsJSON */ -}}
}
{{end}}
@@ -126,20 +210,30 @@
{{end -}}
func (response {{$opid}}{{$statusCode}}Response) Visit{{$opid}}Response(w http.ResponseWriter) error {
{{range $headers -}}
- w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{if .IsNullable -}}
+ if response.Headers.{{.GoName}}.IsSpecified() {
+ w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}.MustGet()))
+ }
+ {{else if .IsOptional -}}
+ if response.Headers.{{.GoName}} != nil {
+ w.Header().Set("{{.Name}}", fmt.Sprint(*response.Headers.{{.GoName}}))
+ }
+ {{else -}}
+ w.Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{end -}}
{{end -}}
w.WriteHeader({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}})
return nil
}
{{end}}
{{end}}
-{{end}}
+{{end}}{{end}}
// StrictServerInterface represents all server handlers.
type StrictServerInterface interface {
-{{range .}}{{.SummaryAsComment }}
+{{range .}}{{if not .IsAlias}}{{.SummaryAsComment }}
// ({{.Method}} {{.Path}})
{{$opid := .OperationId -}}
{{$opid}}(ctx context.Context, request {{$opid | ucFirst}}RequestObject) ({{$opid | ucFirst}}ResponseObject, error)
-{{end}}{{/* range . */ -}}
+{{end}}{{end}}{{/* range . */ -}}
}
diff --git a/pkg/codegen/templates/strict/strict-iris-interface.tmpl b/pkg/codegen/templates/strict/strict-iris-interface.tmpl
index 3a51056015..e48d7ab6d3 100644
--- a/pkg/codegen/templates/strict/strict-iris-interface.tmpl
+++ b/pkg/codegen/templates/strict/strict-iris-interface.tmpl
@@ -1,4 +1,4 @@
-{{range .}}
+{{range .}}{{if not .IsAlias}}
{{$opid := .OperationId -}}
type {{$opid | ucFirst}}RequestObject struct {
{{range .PathParams -}}
@@ -32,23 +32,31 @@
{{if (and $hasHeaders (not $isRef)) -}}
type {{$opid}}{{$statusCode}}ResponseHeaders struct {
{{range .Headers -}}
- {{.GoName}} {{.Schema.TypeDecl}}
+ {{.GoName}} {{.GoTypeDef}}
{{end -}}
}
{{end}}
{{range .Contents}}
{{$receiverTypeName := printf "%s%s%s%s" $opid $statusCode .NameTagOrContentType "Response"}}
- {{if eq .NameTag "Text" -}}
- type {{$receiverTypeName}} string
- {{else if and $fixedStatusCode $isRef -}}
- {{ if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) (eq .NameTag "Multipart") -}}
+ {{if and $fixedStatusCode $isRef -}}
+ {{ if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) (or (eq .NameTag "Multipart") (eq .NameTag "Text")) -}}
type {{$receiverTypeName}} {{$ref}}{{.NameTagOrContentType}}Response
{{else -}}
type {{$receiverTypeName}} struct{ {{$ref}}{{.NameTagOrContentType}}Response }
{{end}}
{{else if and (not $hasHeaders) ($fixedStatusCode) (.IsSupported) -}}
- type {{$receiverTypeName}} {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{if .Schema.IsRef}}={{end}} {{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
+ type {{$receiverTypeName}} {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{if and .Schema.IsRef (not .Schema.IsExternalRef)}}={{end}} {{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
+ {{- if and .IsJSON .Schema.HasCustomMarshalJSON}}
+
+ func (t {{$receiverTypeName}}) MarshalJSON() ([]byte, error) {
+ return {{.Schema.TypeDecl}}(t).MarshalJSON()
+ }
+
+ func (t *{{$receiverTypeName}}) UnmarshalJSON(b []byte) error {
+ return (*{{.Schema.TypeDecl}})(t).UnmarshalJSON(b)
+ }
+ {{- end}}
{{else -}}
type {{$receiverTypeName}} struct {
Body {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
@@ -72,12 +80,22 @@
func (response {{$receiverTypeName}}) Visit{{$opid}}Response(ctx iris.Context) error {
{{range $headers -}}
- ctx.ResponseWriter().Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{if .IsNullable -}}
+ if response.Headers.{{.GoName}}.IsSpecified() {
+ ctx.ResponseWriter().Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}.MustGet()))
+ }
+ {{else if .IsOptional -}}
+ if response.Headers.{{.GoName}} != nil {
+ ctx.ResponseWriter().Header().Set("{{.Name}}", fmt.Sprint(*response.Headers.{{.GoName}}))
+ }
+ {{else -}}
+ ctx.ResponseWriter().Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{end -}}
{{end -}}
{{if eq .NameTag "Multipart" -}}
writer := multipart.NewWriter(ctx.ResponseWriter())
{{end -}}
- ctx.ResponseWriter().Header().Set("Content-Type", {{if eq .NameTag "Multipart"}}writer.FormDataContentType(){{else if .HasFixedContentType }}"{{.ContentType}}"{{else}}response.ContentType{{end}})
+ ctx.ResponseWriter().Header().Set("Content-Type", {{if eq .NameTag "Multipart"}}{{if eq .ContentType "multipart/form-data"}}writer.FormDataContentType(){{else}}mime.FormatMediaType({{.ContentType | toGoString}}, map[string]string{"boundary": writer.Boundary()}){{end}}{{else if .HasFixedContentType }}{{.ContentType | toGoString}}{{else}}response.ContentType{{end}})
{{if not .IsSupported -}}
if response.ContentLength != 0 {
ctx.ResponseWriter().Header().Set("Content-Length", fmt.Sprint(response.ContentLength))
@@ -87,7 +105,7 @@
{{$hasBodyVar := or ($hasHeaders) (not $fixedStatusCode) (not .IsSupported)}}
{{if .IsJSON -}}
{{$hasUnionElements := ne 0 (len .Schema.UnionElements)}}
- return ctx.JSON(&{{if $hasBodyVar}}response.Body{{else}}response{{end}}{{if $hasUnionElements}}.union{{end}})
+ return ctx.JSON(&{{if $hasBodyVar}}response.Body{{else}}response{{end}}{{if and $hasUnionElements (not .Schema.IsExternalRef)}}.union{{end}})
{{else if eq .NameTag "Text" -}}
_, err := ctx.WriteString(string({{if $hasBodyVar}}response.Body{{else}}response{{end}}))
return err
@@ -105,8 +123,36 @@
if closer, ok := response.Body.(io.ReadCloser); ok {
defer closer.Close()
}
- _, err := io.Copy(ctx.ResponseWriter(), response.Body)
- return err
+ {{if .IsStreamingContentType -}}
+ flusher, ok := ctx.ResponseWriter().(http.Flusher)
+ if !ok {
+ // Fall back to buffered copy when the response writer
+ // doesn't support flushing.
+ _, err := io.Copy(ctx.ResponseWriter(), response.Body)
+ return err
+ }
+ // Flush after each chunk so streaming clients see data
+ // immediately instead of waiting on buffering.
+ buf := make([]byte, 4096)
+ for {
+ n, err := response.Body.Read(buf)
+ if n > 0 {
+ if _, writeErr := ctx.ResponseWriter().Write(buf[:n]); writeErr != nil {
+ return writeErr
+ }
+ flusher.Flush()
+ }
+ if err != nil {
+ if err == io.EOF {
+ return nil
+ }
+ return err
+ }
+ }
+ {{else -}}
+ _, err := io.Copy(ctx.ResponseWriter(), response.Body)
+ return err
+ {{end}}{{/* if .IsStreamingContentType */ -}}
{{end}}{{/* if eq .NameTag "JSON" */ -}}
}
{{end}}
@@ -126,20 +172,30 @@
{{end -}}
func (response {{$opid}}{{$statusCode}}Response) Visit{{$opid}}Response(ctx iris.Context) error {
{{range $headers -}}
- ctx.Response().Header.Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{if .IsNullable -}}
+ if response.Headers.{{.GoName}}.IsSpecified() {
+ ctx.ResponseWriter().Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}.MustGet()))
+ }
+ {{else if .IsOptional -}}
+ if response.Headers.{{.GoName}} != nil {
+ ctx.ResponseWriter().Header().Set("{{.Name}}", fmt.Sprint(*response.Headers.{{.GoName}}))
+ }
+ {{else -}}
+ ctx.ResponseWriter().Header().Set("{{.Name}}", fmt.Sprint(response.Headers.{{.GoName}}))
+ {{end -}}
{{end -}}
ctx.StatusCode({{if $fixedStatusCode}}{{$statusCode}}{{else}}response.StatusCode{{end}})
return nil
}
{{end}}
{{end}}
-{{end}}
+{{end}}{{end}}
// StrictServerInterface represents all server handlers.
type StrictServerInterface interface {
-{{range .}}{{.SummaryAsComment }}
+{{range .}}{{if not .IsAlias}}{{.SummaryAsComment }}
// ({{.Method}} {{.Path}})
{{$opid := .OperationId -}}
{{$opid}}(ctx context.Context, request {{$opid | ucFirst}}RequestObject) ({{$opid | ucFirst}}ResponseObject, error)
-{{end}}{{/* range . */ -}}
+{{end}}{{end}}{{/* range . */ -}}
}
diff --git a/pkg/codegen/templates/strict/strict-iris.tmpl b/pkg/codegen/templates/strict/strict-iris.tmpl
index d18bda74cc..5195c251b0 100644
--- a/pkg/codegen/templates/strict/strict-iris.tmpl
+++ b/pkg/codegen/templates/strict/strict-iris.tmpl
@@ -1,5 +1,5 @@
-type StrictHandlerFunc = strictiris.StrictIrisHandlerFunc
-type StrictMiddlewareFunc = strictiris.StrictIrisMiddlewareFunc
+type StrictHandlerFunc func(ctx iris.Context, request any) (any, error)
+type StrictMiddlewareFunc func(f StrictHandlerFunc, operationID string) StrictHandlerFunc
func NewStrictHandler(ssi StrictServerInterface, middlewares []StrictMiddlewareFunc) ServerInterface {
return &strictHandler{ssi: ssi, middlewares: middlewares}
@@ -12,6 +12,7 @@ type strictHandler struct {
{{range .}}
{{$opid := .OperationId}}
+ {{if not .IsAlias}}
// {{$opid}} operation middleware
func (sh *strictHandler) {{.OperationId}}(ctx iris.Context{{genParamArgs .PathParams}}{{if .RequiresParamObject}}, params {{.OperationId}}Params{{end}}) {
var request {{$opid | ucFirst}}RequestObject
@@ -30,14 +31,22 @@ type strictHandler struct {
{{$multipleBodies := gt (len .Bodies) 1 -}}
{{range .Bodies -}}
- {{if $multipleBodies}}if strings.HasPrefix(ctx.GetHeader("Content-Type"), "{{.ContentType}}") { {{end}}
+ {{if $multipleBodies}}if strings.HasPrefix(ctx.GetHeader("Content-Type"), {{.ContentType | toGoString}}) { {{end}}
{{if .IsJSON }}
var body {{$opid}}{{.NameTag}}RequestBody
if err := ctx.ReadJSON(&body); err != nil {
+ {{if not .Required -}}
+ if !errors.Is(err, io.EOF) {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ }
+ {{else -}}
ctx.StopWithError(http.StatusBadRequest, err)
return
- }
+ {{end -}}
+ } {{if not .Required -}} else { {{end}}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{if not .Required -}} } {{end}}
{{else if eq .NameTag "Formdata" -}}
if err := ctx.Request().ParseForm(); err != nil {
ctx.StopWithError(http.StatusBadRequest, err)
@@ -50,20 +59,38 @@ type strictHandler struct {
}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
{{else if eq .NameTag "Multipart" -}}
+ {{if eq .ContentType "multipart/form-data" -}}
if reader, err := ctx.Request().MultipartReader(); err == nil {
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = reader
} else {
ctx.StopWithError(http.StatusBadRequest, err)
return
}
+ {{else -}}
+ if _, params, err := mime.ParseMediaType(ctx.Request().Header.Get("Content-Type")); err != nil {
+ ctx.StopWithError(http.StatusBadRequest, err)
+ return
+ } else if boundary := params["boundary"]; boundary == "" {
+ ctx.StopWithError(http.StatusBadRequest, http.ErrMissingBoundary)
+ return
+ } else {
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = multipart.NewReader(ctx.Request().Body, boundary)
+ }
+ {{end -}}
{{else if eq .NameTag "Text" -}}
data, err := io.ReadAll(ctx.Request().Body)
if err != nil {
ctx.StopWithError(http.StatusBadRequest, err)
return
}
+ {{if not .Required -}}
+ if len(data) > 0 {
+ {{end -}}
body := {{$opid}}{{.NameTag}}RequestBody(data)
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = &body
+ {{if not .Required -}}
+ }
+ {{end -}}
{{else -}}
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = ctx.Request().Body
{{end}}{{/* if eq .NameTag "JSON" */ -}}
@@ -92,4 +119,5 @@ type strictHandler struct {
return
}
}
+ {{end}}
{{end}}
diff --git a/pkg/codegen/templates/strict/strict-responses.tmpl b/pkg/codegen/templates/strict/strict-responses.tmpl
index d04cbd7d6c..5b4ee68c8d 100644
--- a/pkg/codegen/templates/strict/strict-responses.tmpl
+++ b/pkg/codegen/templates/strict/strict-responses.tmpl
@@ -4,7 +4,7 @@
{{if $hasHeaders -}}
type {{$name}}ResponseHeaders struct {
{{range .Headers -}}
- {{.GoName}} {{.Schema.TypeDecl}}
+ {{.GoName}} {{.GoTypeDef}}
{{end -}}
}
{{end -}}
@@ -12,6 +12,16 @@
{{range .Contents -}}
{{if and (not $hasHeaders) (.IsSupported) -}}
type {{$name}}{{.NameTagOrContentType}}Response {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{if .Schema.IsRef}}={{end}} {{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
+ {{- if and .IsJSON .Schema.HasCustomMarshalJSON}}
+
+ func (t {{$name}}{{.NameTagOrContentType}}Response) MarshalJSON() ([]byte, error) {
+ return {{.Schema.TypeDecl}}(t).MarshalJSON()
+ }
+
+ func (t *{{$name}}{{.NameTagOrContentType}}Response) UnmarshalJSON(b []byte) error {
+ return (*{{.Schema.TypeDecl}})(t).UnmarshalJSON(b)
+ }
+ {{- end}}
{{else -}}
type {{$name}}{{.NameTagOrContentType}}Response struct {
Body {{if eq .NameTag "Multipart"}}func(writer *multipart.Writer)error{{else if .IsSupported}}{{.Schema.TypeDecl}}{{else}}io.Reader{{end}}
diff --git a/pkg/codegen/templates/union-and-additional-properties.tmpl b/pkg/codegen/templates/union-and-additional-properties.tmpl
index 79b4c67b2e..6ec69f5e85 100644
--- a/pkg/codegen/templates/union-and-additional-properties.tmpl
+++ b/pkg/codegen/templates/union-and-additional-properties.tmpl
@@ -54,12 +54,12 @@ func (a {{.TypeName}}) MarshalJSON() ([]byte, error) {
}
}
{{range .Schema.Properties}}
-{{if not .Required}}if a.{{.GoFieldName}} != nil { {{end}}
+{{if .RequiresNilCheck}}if a.{{.GoFieldName}} != nil { {{end}}
object["{{.JsonFieldName}}"], err = json.Marshal(a.{{.GoFieldName}})
if err != nil {
return nil, fmt.Errorf("error marshaling '{{.JsonFieldName}}': %w", err)
}
-{{if not .Required}} }{{end}}
+{{if .RequiresNilCheck}} }{{end}}
{{end}}
for fieldName, field := range a.AdditionalProperties {
object[fieldName], err = json.Marshal(field)
diff --git a/pkg/codegen/templates/union.tmpl b/pkg/codegen/templates/union.tmpl
index 8bb34a2562..61c2bf37fd 100644
--- a/pkg/codegen/templates/union.tmpl
+++ b/pkg/codegen/templates/union.tmpl
@@ -2,6 +2,7 @@
{{$typeName := .TypeName -}}
{{$discriminator := .Schema.Discriminator}}
{{$properties := .Schema.Properties -}}
+ {{$numberOfUnionTypes := len .Schema.UnionElements -}}
{{range .Schema.UnionElements}}
{{$element := . -}}
// As{{ .Method }} returns the union data inside the {{$typeName}} as a {{.}}
@@ -14,16 +15,18 @@
// From{{ .Method }} overwrites any union data inside the {{$typeName}} as the provided {{.}}
func (t *{{$typeName}}) From{{ .Method }} (v {{.}}) error {
{{if $discriminator -}}
- {{range $value, $type := $discriminator.Mapping -}}
- {{if eq $type $element -}}
- {{$hasProperty := false -}}
- {{range $properties -}}
- {{if eq .GoFieldName $discriminator.PropertyName -}}
- t.{{$discriminator.PropertyName}} = "{{$value}}"
- {{$hasProperty = true -}}
+ {{if eq $numberOfUnionTypes (len $discriminator.Mapping) -}}
+ {{range $value, $type := $discriminator.Mapping -}}
+ {{if eq $type $element -}}
+ {{$hasProperty := false -}}
+ {{range $properties -}}
+ {{if eq .GoFieldName $discriminator.PropertyName -}}
+ t.{{$discriminator.PropertyName}} = "{{$value}}"
+ {{$hasProperty = true -}}
+ {{end -}}
{{end -}}
+ {{if not $hasProperty}}v.{{$discriminator.PropertyName}} = "{{$value}}"{{end}}
{{end -}}
- {{if not $hasProperty}}v.{{$discriminator.PropertyName}} = "{{$value}}"{{end}}
{{end -}}
{{end -}}
{{end -}}
@@ -35,16 +38,18 @@
// Merge{{ .Method }} performs a merge with any union data inside the {{$typeName}}, using the provided {{.}}
func (t *{{$typeName}}) Merge{{ .Method }} (v {{.}}) error {
{{if $discriminator -}}
- {{range $value, $type := $discriminator.Mapping -}}
- {{if eq $type $element -}}
- {{$hasProperty := false -}}
- {{range $properties -}}
- {{if eq .GoFieldName $discriminator.PropertyName -}}
- t.{{$discriminator.PropertyName}} = "{{$value}}"
- {{$hasProperty = true -}}
+ {{if eq $numberOfUnionTypes (len $discriminator.Mapping) -}}
+ {{range $value, $type := $discriminator.Mapping -}}
+ {{if eq $type $element -}}
+ {{$hasProperty := false -}}
+ {{range $properties -}}
+ {{if eq .GoFieldName $discriminator.PropertyName -}}
+ t.{{$discriminator.PropertyName}} = "{{$value}}"
+ {{$hasProperty = true -}}
+ {{end -}}
{{end -}}
+ {{if not $hasProperty}}v.{{$discriminator.PropertyName}} = "{{$value}}"{{end}}
{{end -}}
- {{if not $hasProperty}}v.{{$discriminator.PropertyName}} = "{{$value}}"{{end}}
{{end -}}
{{end -}}
{{end -}}
@@ -53,7 +58,7 @@
return err
}
- merged, err := runtime.JsonMerge(t.union, b)
+ merged, err := runtime.JSONMerge(t.union, b)
t.union = merged
return err
}
@@ -102,12 +107,12 @@
}
}
{{range .Schema.Properties}}
- {{if not .Required}}if t.{{.GoFieldName}} != nil { {{end}}
+ {{if .RequiresNilCheck}}if t.{{.GoFieldName}} != nil { {{end}}
object["{{.JsonFieldName}}"], err = json.Marshal(t.{{.GoFieldName}})
if err != nil {
return nil, fmt.Errorf("error marshaling '{{.JsonFieldName}}': %w", err)
}
- {{if not .Required}} }{{end}}
+ {{if .RequiresNilCheck}} }{{end}}
{{end -}}
b, err = json.Marshal(object)
{{end -}}
diff --git a/pkg/codegen/test_spec.yaml b/pkg/codegen/test_spec.yaml
index b50f7491c5..f20cbecdca 100644
--- a/pkg/codegen/test_spec.yaml
+++ b/pkg/codegen/test_spec.yaml
@@ -164,15 +164,45 @@ components:
format: date-time
CatDead:
+ required:
+ - sliced_birds
+ - very_dead_since
+ - very_memorable_birds
properties:
name:
type: string
+ favourite_birds:
+ type: array
+ items:
+ type: string
+ nullable: true
+ detested_birds:
+ type: array
+ items:
+ type: string
+ sliced_birds:
+ type: array
+ items:
+ type: string
+ forgettable_birds:
+ additionalProperties:
+ type: string
+ nullable: true
+ memorable_birds:
+ additionalProperties:
+ type: string
+ very_memorable_birds:
+ additionalProperties:
+ type: string
dead_since:
type: string
format: date-time
x-oapi-codegen-extra-tags:
tag1: value1
tag2: value2
+ very_dead_since:
+ type: string
+ format: date-time
cause:
type: string
enum: [ car, dog, oldage ]
diff --git a/pkg/codegen/test_specs/remote-external-reference.yaml b/pkg/codegen/test_specs/remote-external-reference.yaml
index b966df199f..1b425cd134 100644
--- a/pkg/codegen/test_specs/remote-external-reference.yaml
+++ b/pkg/codegen/test_specs/remote-external-reference.yaml
@@ -21,6 +21,6 @@ components:
item:
type: object
oneOf:
- - $ref: 'https://raw.githubusercontent.com/deepmap/oapi-codegen/master/examples/petstore-expanded/petstore-expanded.yaml#/components/schemas/NewPet'
+ - $ref: 'https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/master/examples/petstore-expanded/petstore-expanded.yaml#/components/schemas/NewPet'
required:
- item
diff --git a/pkg/codegen/test_specs/x-go-type-pet-allof.yaml b/pkg/codegen/test_specs/x-go-type-pet-allof.yaml
new file mode 100644
index 0000000000..c2f65b90ba
--- /dev/null
+++ b/pkg/codegen/test_specs/x-go-type-pet-allof.yaml
@@ -0,0 +1,56 @@
+paths:
+ /pets:
+ patch:
+ requestBody:
+ content:
+ application/json:
+ schema:
+ oneOf:
+ - $ref: '#/components/schemas/Cat'
+ - $ref: '#/components/schemas/Dog'
+ discriminator:
+ propertyName: pet_type
+ responses:
+ '200':
+ description: Updated
+components:
+ schemas:
+ Pet:
+ x-go-type: pet.Pet
+ x-go-type-import:
+ path: github.com/somepetproject/pkg/pet
+ type: object
+ required:
+ - pet_type
+ properties:
+ pet_type:
+ type: string
+ discriminator:
+ propertyName: pet_type
+ Dog: # "Dog" is a value for the pet_type property (the discriminator value)
+ x-go-type: dog.Dog
+ x-go-type-import:
+ path: github.com/somepetproject/pkg/dog
+ allOf: # Combines the main `Pet` schema with `Dog`-specific properties
+ - $ref: '#/components/schemas/Pet'
+ - type: object
+ # all other properties specific to a `Dog`
+ properties:
+ bark:
+ type: boolean
+ breed:
+ type: string
+ enum: [Dingo, Husky, Retriever, Shepherd]
+ Cat: # "Cat" is a value for the pet_type property (the discriminator value)
+ x-go-type: cat.Cat
+ x-go-type-import:
+ path: github.com/somepetproject/pkg/cat
+ allOf: # Combines the main `Pet` schema with `Cat`-specific properties
+ - $ref: '#/components/schemas/Pet'
+ - type: object
+ # all other properties specific to a `Cat`
+ properties:
+ hunts:
+ type: boolean
+ age:
+ type: integer
diff --git a/pkg/codegen/typemapping.go b/pkg/codegen/typemapping.go
new file mode 100644
index 0000000000..2a54695f68
--- /dev/null
+++ b/pkg/codegen/typemapping.go
@@ -0,0 +1,107 @@
+package codegen
+
+import "maps"
+
+// SimpleTypeSpec defines the Go type for an OpenAPI type/format combination,
+// along with any import required to use it.
+type SimpleTypeSpec struct {
+ Type string `yaml:"type" json:"type"`
+ Import string `yaml:"import,omitempty" json:"import,omitempty"`
+}
+
+// FormatMapping defines the default Go type and format-specific overrides
+// for an OpenAPI type.
+type FormatMapping struct {
+ Default SimpleTypeSpec `yaml:"default" json:"default"`
+ Formats map[string]SimpleTypeSpec `yaml:"formats,omitempty" json:"formats,omitempty"`
+}
+
+// TypeMapping defines the mapping from OpenAPI types to Go types.
+type TypeMapping struct {
+ Integer FormatMapping `yaml:"integer,omitempty" json:"integer"`
+ Number FormatMapping `yaml:"number,omitempty" json:"number"`
+ Boolean FormatMapping `yaml:"boolean,omitempty" json:"boolean"`
+ String FormatMapping `yaml:"string,omitempty" json:"string"`
+}
+
+// Merge returns a new TypeMapping with user overrides applied on top of base.
+func (base TypeMapping) Merge(user TypeMapping) TypeMapping {
+ return TypeMapping{
+ Integer: base.Integer.merge(user.Integer),
+ Number: base.Number.merge(user.Number),
+ Boolean: base.Boolean.merge(user.Boolean),
+ String: base.String.merge(user.String),
+ }
+}
+
+func (base FormatMapping) merge(user FormatMapping) FormatMapping {
+ result := FormatMapping{
+ Default: base.Default,
+ Formats: make(map[string]SimpleTypeSpec),
+ }
+
+ // Copy base formats
+ maps.Copy(result.Formats, base.Formats)
+
+ // Override with user default if specified
+ if user.Default.Type != "" {
+ result.Default = user.Default
+ }
+
+ // Override/add user formats
+ maps.Copy(result.Formats, user.Formats)
+
+ return result
+}
+
+// Resolve returns the SimpleTypeSpec for a given format string.
+// If the format has a specific mapping, that is returned; otherwise the default is used.
+func (fm FormatMapping) Resolve(format string) SimpleTypeSpec {
+ if format != "" {
+ if spec, ok := fm.Formats[format]; ok {
+ return spec
+ }
+ }
+ return fm.Default
+}
+
+// DefaultTypeMapping provides the default OpenAPI type/format to Go type mappings.
+var DefaultTypeMapping = TypeMapping{
+ Integer: FormatMapping{
+ Default: SimpleTypeSpec{Type: "int"},
+ Formats: map[string]SimpleTypeSpec{
+ "int": {Type: "int"},
+ "int8": {Type: "int8"},
+ "int16": {Type: "int16"},
+ "int32": {Type: "int32"},
+ "int64": {Type: "int64"},
+ "uint": {Type: "uint"},
+ "uint8": {Type: "uint8"},
+ "uint16": {Type: "uint16"},
+ "uint32": {Type: "uint32"},
+ "uint64": {Type: "uint64"},
+ },
+ },
+ Number: FormatMapping{
+ Default: SimpleTypeSpec{Type: "float32"},
+ Formats: map[string]SimpleTypeSpec{
+ "float": {Type: "float32"},
+ "double": {Type: "float64"},
+ },
+ },
+ Boolean: FormatMapping{
+ Default: SimpleTypeSpec{Type: "bool"},
+ },
+ String: FormatMapping{
+ Default: SimpleTypeSpec{Type: "string"},
+ Formats: map[string]SimpleTypeSpec{
+ "byte": {Type: "[]byte"},
+ "email": {Type: "openapi_types.Email"},
+ "date": {Type: "openapi_types.Date"},
+ "date-time": {Type: "time.Time", Import: "time"},
+ "json": {Type: "json.RawMessage", Import: "encoding/json"},
+ "uuid": {Type: "openapi_types.UUID"},
+ "binary": {Type: "openapi_types.File"},
+ },
+ },
+}
diff --git a/pkg/codegen/typemapping_test.go b/pkg/codegen/typemapping_test.go
new file mode 100644
index 0000000000..ca593cfd5d
--- /dev/null
+++ b/pkg/codegen/typemapping_test.go
@@ -0,0 +1,88 @@
+package codegen
+
+import (
+ "testing"
+
+ "github.com/stretchr/testify/assert"
+)
+
+func TestFormatMapping_Resolve(t *testing.T) {
+ fm := FormatMapping{
+ Default: SimpleTypeSpec{Type: "int"},
+ Formats: map[string]SimpleTypeSpec{
+ "int32": {Type: "int32"},
+ "int64": {Type: "int64"},
+ },
+ }
+
+ assert.Equal(t, "int", fm.Resolve("").Type)
+ assert.Equal(t, "int32", fm.Resolve("int32").Type)
+ assert.Equal(t, "int64", fm.Resolve("int64").Type)
+ assert.Equal(t, "int", fm.Resolve("unknown-format").Type)
+}
+
+func TestTypeMapping_Merge(t *testing.T) {
+ base := DefaultTypeMapping
+
+ user := TypeMapping{
+ Integer: FormatMapping{
+ Default: SimpleTypeSpec{Type: "int64"},
+ },
+ String: FormatMapping{
+ Formats: map[string]SimpleTypeSpec{
+ "date-time": {Type: "civil.DateTime", Import: "cloud.google.com/go/civil"},
+ },
+ },
+ }
+
+ merged := base.Merge(user)
+
+ // Integer default overridden
+ assert.Equal(t, "int64", merged.Integer.Default.Type)
+ // Integer formats still inherited from base
+ assert.Equal(t, "int32", merged.Integer.Formats["int32"].Type)
+
+ // String date-time overridden
+ assert.Equal(t, "civil.DateTime", merged.String.Formats["date-time"].Type)
+ assert.Equal(t, "cloud.google.com/go/civil", merged.String.Formats["date-time"].Import)
+ // String default still inherited from base
+ assert.Equal(t, "string", merged.String.Default.Type)
+ // Other string formats still inherited
+ assert.Equal(t, "openapi_types.UUID", merged.String.Formats["uuid"].Type)
+
+ // Number and Boolean unchanged
+ assert.Equal(t, "float32", merged.Number.Default.Type)
+ assert.Equal(t, "bool", merged.Boolean.Default.Type)
+}
+
+func TestDefaultTypeMapping_Completeness(t *testing.T) {
+ // Verify all the default mappings match what was previously hardcoded
+ dm := DefaultTypeMapping
+
+ // Integer
+ assert.Equal(t, "int", dm.Integer.Resolve("").Type)
+ assert.Equal(t, "int32", dm.Integer.Resolve("int32").Type)
+ assert.Equal(t, "int64", dm.Integer.Resolve("int64").Type)
+ assert.Equal(t, "uint32", dm.Integer.Resolve("uint32").Type)
+ assert.Equal(t, "int", dm.Integer.Resolve("unknown").Type)
+
+ // Number
+ assert.Equal(t, "float32", dm.Number.Resolve("").Type)
+ assert.Equal(t, "float32", dm.Number.Resolve("float").Type)
+ assert.Equal(t, "float64", dm.Number.Resolve("double").Type)
+ assert.Equal(t, "float32", dm.Number.Resolve("unknown").Type)
+
+ // Boolean
+ assert.Equal(t, "bool", dm.Boolean.Resolve("").Type)
+
+ // String
+ assert.Equal(t, "string", dm.String.Resolve("").Type)
+ assert.Equal(t, "[]byte", dm.String.Resolve("byte").Type)
+ assert.Equal(t, "openapi_types.Email", dm.String.Resolve("email").Type)
+ assert.Equal(t, "openapi_types.Date", dm.String.Resolve("date").Type)
+ assert.Equal(t, "time.Time", dm.String.Resolve("date-time").Type)
+ assert.Equal(t, "json.RawMessage", dm.String.Resolve("json").Type)
+ assert.Equal(t, "openapi_types.UUID", dm.String.Resolve("uuid").Type)
+ assert.Equal(t, "openapi_types.File", dm.String.Resolve("binary").Type)
+ assert.Equal(t, "string", dm.String.Resolve("unknown").Type)
+}
diff --git a/pkg/codegen/utils.go b/pkg/codegen/utils.go
index 6494248c72..496faf5648 100644
--- a/pkg/codegen/utils.go
+++ b/pkg/codegen/utils.go
@@ -14,12 +14,15 @@
package codegen
import (
+ "bytes"
+ "cmp"
"fmt"
"go/token"
+ "maps"
"net/url"
"reflect"
"regexp"
- "sort"
+ "slices"
"strconv"
"strings"
"unicode"
@@ -31,8 +34,70 @@ var (
pathParamRE *regexp.Regexp
predeclaredSet map[string]struct{}
separatorSet map[rune]struct{}
+ nameNormalizer NameNormalizer = ToCamelCase
)
+type NameNormalizerFunction string
+
+const (
+ // NameNormalizerFunctionUnset is the default case, where the `name-normalizer` option hasn't been set. This will use the `ToCamelCase` function.
+ //
+ // See the docs for `NameNormalizerFunctionToCamelCase` for more details.
+ NameNormalizerFunctionUnset NameNormalizerFunction = ""
+ // NameNormalizerFunctionToCamelCase will use the `ToCamelCase` function.
+ //
+ // For instance:
+ //
+ // - `getHttpPet` => `GetHttpPet`
+ // - `OneOf2things` => `OneOf2things`
+ NameNormalizerFunctionToCamelCase NameNormalizerFunction = "ToCamelCase"
+ // NameNormalizerFunctionToCamelCaseWithDigits will use the `NameNormalizerFunctionToCamelCaseWithDigits` function.
+ //
+ // For instance:
+ //
+ // - `getHttpPet` => `GetHttpPet`
+ // - `OneOf2things` => `OneOf2Things`
+ NameNormalizerFunctionToCamelCaseWithDigits NameNormalizerFunction = "ToCamelCaseWithDigits"
+ // NameNormalizerFunctionToCamelCaseWithInitialisms will use the `NameNormalizerFunctionToCamelCaseWithInitialisms` function.
+ //
+ // For instance:
+ //
+ // - `getHttpPet` => `GetHTTPPet`
+ // - `OneOf2things` => `OneOf2things`
+ NameNormalizerFunctionToCamelCaseWithInitialisms NameNormalizerFunction = "ToCamelCaseWithInitialisms"
+)
+
+// NameNormalizer is a function that takes a type name, and returns that type name converted into a different format.
+//
+// This may be an Operation ID i.e. `retrieveUserRequests` or a Schema name i.e. `BigBlockOfCheese`
+//
+// NOTE: this must return a string that can be used as a valid Go type name
+type NameNormalizer func(string) string
+
+type NameNormalizerMap map[NameNormalizerFunction]NameNormalizer
+
+func (m NameNormalizerMap) Options() []string {
+ options := make([]string, 0, len(m))
+
+ for key := range NameNormalizers {
+ options = append(options, string(key))
+ }
+
+ slices.Sort(options)
+
+ return options
+}
+
+// NameNormalizers contains the valid options for `NameNormalizerFunction`s that `oapi-codegen` supports.
+//
+// If you are calling `oapi-codegen` as a library, this allows you to specify your own normalisation types before generating code.
+var NameNormalizers = NameNormalizerMap{
+ NameNormalizerFunctionUnset: ToCamelCase,
+ NameNormalizerFunctionToCamelCase: ToCamelCase,
+ NameNormalizerFunctionToCamelCaseWithDigits: ToCamelCaseWithDigits,
+ NameNormalizerFunctionToCamelCaseWithInitialisms: ToCamelCaseWithInitialisms,
+}
+
func init() {
pathParamRE = regexp.MustCompile(`{[.;?]?([^{}*]+)\*?}`)
@@ -133,6 +198,27 @@ func LowercaseFirstCharacter(str string) string {
return string(runes)
}
+// Lowercase the first upper characters in a string for case of abbreviation.
+// This assumes UTF-8, so we have to be careful with unicode, don't treat it as a byte array.
+func LowercaseFirstCharacters(str string) string {
+ if str == "" {
+ return ""
+ }
+
+ runes := []rune(str)
+
+ for i := range runes {
+ next := i + 1
+ if i != 0 && next < len(runes) && unicode.IsLower(runes[next]) {
+ break
+ }
+
+ runes[i] = unicode.ToLower(runes[i])
+ }
+
+ return string(runes)
+}
+
// ToCamelCase will convert query-arg style strings to CamelCase. We will
// use `., -, +, :, ;, _, ~, ' ', (, ), {, }, [, ]` as valid delimiters for words.
// So, "word.word-word+word:word;word_word~word word(word)word{word}[word]"
@@ -140,25 +226,95 @@ func LowercaseFirstCharacter(str string) string {
func ToCamelCase(str string) string {
s := strings.Trim(str, " ")
- n := ""
+ var n strings.Builder
capNext := true
for _, v := range s {
if unicode.IsUpper(v) {
- n += string(v)
+ n.WriteString(string(v))
}
if unicode.IsDigit(v) {
- n += string(v)
+ n.WriteString(string(v))
}
if unicode.IsLower(v) {
if capNext {
- n += strings.ToUpper(string(v))
+ n.WriteString(strings.ToUpper(string(v)))
} else {
- n += string(v)
+ n.WriteString(string(v))
}
}
_, capNext = separatorSet[v]
}
- return n
+ return n.String()
+}
+
+// ToCamelCaseWithDigits function will convert query-arg style strings to CamelCase. We will
+// use `., -, +, :, ;, _, ~, ' ', (, ), {, }, [, ]` as valid delimiters for words.
+// The difference of ToCamelCase that letter after a number becomes capitalized.
+// So, "word.word-word+word:word;word_word~word word(word)word{word}[word]3word"
+// would be converted to WordWordWordWordWordWordWordWordWordWordWordWordWord3Word
+func ToCamelCaseWithDigits(s string) string {
+ res := bytes.NewBuffer(nil)
+ capNext := true
+ for _, v := range s {
+ if unicode.IsUpper(v) {
+ res.WriteRune(v)
+ capNext = false
+ continue
+ }
+ if unicode.IsDigit(v) {
+ res.WriteRune(v)
+ capNext = true
+ continue
+ }
+ if unicode.IsLower(v) {
+ if capNext {
+ res.WriteRune(unicode.ToUpper(v))
+ } else {
+ res.WriteRune(v)
+ }
+ capNext = false
+ continue
+ }
+ capNext = true
+ }
+ return res.String()
+}
+
+// ToCamelCaseWithInitialisms function will convert query-arg style strings to CamelCase with initialisms in uppercase.
+// So, httpOperationId would be converted to HTTPOperationID
+func ToCamelCaseWithInitialisms(s string) string {
+ parts := camelCaseMatchParts.FindAllString(ToCamelCaseWithDigits(s), -1)
+ for i := range parts {
+ if v, ok := globalState.initialismsMap[strings.ToLower(parts[i])]; ok {
+ parts[i] = v
+ }
+ }
+ return strings.Join(parts, "")
+}
+
+var camelCaseMatchParts = regexp.MustCompile(`[\p{Lu}\d]+([\p{Ll}\d]+|$)`)
+
+var initialismsList = []string{
+ "ACL", "API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON",
+ "QPS", "RAM", "RPC", "SLA", "SMTP", "SQL", "SSH", "TCP", "TLS", "TTL", "UDP", "UI", "GID", "UID", "UUID",
+ "URI", "URL", "UTF8", "VM", "XML", "XMPP", "XSRF", "XSS", "SIP", "RTP", "AMQP", "DB", "TS",
+}
+
+// targetWordRegex is a regex that matches all initialisms.
+var targetWordRegex *regexp.Regexp
+
+func makeInitialismsMap(additionalInitialisms []string) map[string]string {
+ l := append(initialismsList, additionalInitialisms...)
+
+ m := make(map[string]string, len(l))
+ for i := range l {
+ m[strings.ToLower(l[i])] = l[i]
+ }
+
+ // Create a regex to match the initialisms
+ targetWordRegex = regexp.MustCompile(`(?i)(` + strings.Join(l, "|") + `)`)
+
+ return m
}
func ToCamelCaseWithInitialism(str string) string {
@@ -168,8 +324,6 @@ func ToCamelCaseWithInitialism(str string) string {
func replaceInitialism(s string) string {
// These strings do not apply CamelCase
// Do not do CamelCase when these characters match when the preceding character is lowercase
- // ["Acl", "Api", "Ascii", "Cpu", "Css", "Dns", "Eof", "Guid", "Html", "Http", "Https", "Id", "Ip", "Json", "Qps", "Ram", "Rpc", "Sla", "Smtp", "Sql", "Ssh", "Tcp", "Tls", "Ttl", "Udp", "Ui", "Gid", "Uid", "Uuid", "Uri", "Url", "Utf8", "Vm", "Xml", "Xmpp", "Xsrf", "Xss", "Sip", "Rtp", "Amqp", "Db", "Ts"]
- targetWordRegex := regexp.MustCompile(`(?i)(Acl|Api|Ascii|Cpu|Css|Dns|Eof|Guid|Html|Http|Https|Id|Ip|Json|Qps|Ram|Rpc|Sla|Smtp|Sql|Ssh|Tcp|Tls|Ttl|Udp|Ui|Gid|Uid|Uuid|Uri|Url|Utf8|Vm|Xml|Xmpp|Xsrf|Xss|Sip|Rtp|Amqp|Db|Ts)`)
return targetWordRegex.ReplaceAllStringFunc(s, func(s string) string {
// If the preceding character is lowercase, do not do CamelCase
if unicode.IsLower(rune(s[0])) {
@@ -190,134 +344,73 @@ func mediaTypeToCamelCase(s string) string {
return ToCamelCaseWithInitialism(s)
}
-// SortedSchemaKeys returns the keys of the given SchemaRef dictionary in sorted
-// order, since Golang scrambles dictionary keys
-func SortedSchemaKeys(dict map[string]*openapi3.SchemaRef) []string {
- keys := make([]string, len(dict))
- i := 0
- for key := range dict {
- keys[i] = key
- i++
+// SortedMapKeys takes a map with keys of type string and returns a slice of those
+// keys sorted lexicographically.
+func SortedMapKeys[T any](m map[string]T) []string {
+ keys := make([]string, 0, len(m))
+ for k := range m {
+ keys = append(keys, k)
}
- sort.Strings(keys)
+ slices.Sort(keys)
return keys
}
-// SortedPathsKeys is the same as above, except it sorts the keys for a Paths
-// dictionary.
-func SortedPathsKeys(dict openapi3.Paths) []string {
+// SortedSchemaKeys returns the keys of the given SchemaRef dictionary in sorted
+// order, since Golang scrambles dictionary keys. This isn't a generic key sort, because
+// we support an extension to grant specific orders to schemas to help control output
+// ordering.
+func SortedSchemaKeys(dict map[string]*openapi3.SchemaRef) []string {
keys := make([]string, len(dict))
+ orders := make(map[string]int64, len(dict))
i := 0
- for key := range dict {
- keys[i] = key
- i++
- }
- sort.Strings(keys)
- return keys
-}
-// SortedOperationsKeys returns Operation dictionary keys in sorted order
-func SortedOperationsKeys(dict map[string]*openapi3.Operation) []string {
- keys := make([]string, len(dict))
- i := 0
- for key := range dict {
- keys[i] = key
+ for key, v := range dict {
+ keys[i], orders[key] = key, int64(len(dict))
i++
- }
- sort.Strings(keys)
- return keys
-}
-// SortedResponsesKeys returns Responses dictionary keys in sorted order
-func SortedResponsesKeys(dict openapi3.Responses) []string {
- keys := make([]string, len(dict))
- i := 0
- for key := range dict {
- keys[i] = key
- i++
+ if order, ok := schemaXOrder(v); ok {
+ orders[key] = order
+ }
}
- sort.Strings(keys)
- return keys
-}
-func SortedHeadersKeys(dict openapi3.Headers) []string {
- keys := make([]string, len(dict))
- i := 0
- for key := range dict {
- keys[i] = key
- i++
- }
- sort.Strings(keys)
+ slices.SortFunc(keys, func(a, b string) int {
+ return cmp.Or(
+ cmp.Compare(orders[a], orders[b]),
+ cmp.Compare(a, b),
+ )
+ })
return keys
}
-// SortedContentKeys returns Content dictionary keys in sorted order
-func SortedContentKeys(dict openapi3.Content) []string {
- keys := make([]string, len(dict))
- i := 0
- for key := range dict {
- keys[i] = key
- i++
+func schemaXOrder(v *openapi3.SchemaRef) (int64, bool) {
+ if v == nil {
+ return 0, false
}
- sort.Strings(keys)
- return keys
-}
-// SortedStringKeys returns string map keys in sorted order
-func SortedStringKeys(dict map[string]string) []string {
- keys := make([]string, len(dict))
- i := 0
- for key := range dict {
- keys[i] = key
- i++
+ // YAML parsing picks up the x-order as a float64
+ if order, ok := v.Extensions[extOrder].(float64); ok {
+ return int64(order), true
}
- sort.Strings(keys)
- return keys
-}
-// SortedParameterKeys returns sorted keys for a ParameterRef dict
-func SortedParameterKeys(dict map[string]*openapi3.ParameterRef) []string {
- keys := make([]string, len(dict))
- i := 0
- for key := range dict {
- keys[i] = key
- i++
+ if v.Value == nil {
+ return 0, false
}
- sort.Strings(keys)
- return keys
-}
-func SortedRequestBodyKeys(dict map[string]*openapi3.RequestBodyRef) []string {
- keys := make([]string, len(dict))
- i := 0
- for key := range dict {
- keys[i] = key
- i++
- }
- sort.Strings(keys)
- return keys
-}
+ // if v.Value is set, then this is actually a `$ref`, and we should check if there's an x-order set on that
-func SortedSecurityRequirementKeys(sr openapi3.SecurityRequirement) []string {
- keys := make([]string, len(sr))
- i := 0
- for key := range sr {
- keys[i] = key
- i++
+ // YAML parsing picks up the x-order as a float64
+ if order, ok := v.Value.Extensions[extOrder].(float64); ok {
+ return int64(order), true
}
- sort.Strings(keys)
- return keys
+
+ return 0, false
}
-// StringInArray checks whether the specified string is present in an array
-// of strings
-func StringInArray(str string, array []string) bool {
- for _, elt := range array {
- if elt == str {
- return true
- }
- }
- return false
+// SortedSecuritySchemeKeys returns sorted keys for a SecuritySchemeRef dict
+func SortedSecuritySchemeKeys(dict map[string]*openapi3.SecuritySchemeRef) []string {
+ keys := slices.Collect(maps.Keys(dict))
+ slices.Sort(keys)
+ return keys
}
// RefPathToObjName returns the name of referenced object without changes.
@@ -351,44 +444,73 @@ func RefPathToGoType(refPath string) (string, error) {
// refPathToGoType returns the Go typename for refPath given its
func refPathToGoType(refPath string, local bool) (string, error) {
if refPath[0] == '#' {
- pathParts := strings.Split(refPath, "/")
- depth := len(pathParts)
- if local {
- if depth != 4 {
- return "", fmt.Errorf("unexpected reference depth: %d for ref: %s local: %t", depth, refPath, local)
- }
- } else if depth != 4 && depth != 2 {
- return "", fmt.Errorf("unexpected reference depth: %d for ref: %s local: %t", depth, refPath, local)
- }
-
- // Schemas may have been renamed locally, so look up the actual name in
- // the spec.
- name, err := findSchemaNameByRefPath(refPath, globalState.spec)
- if err != nil {
- return "", fmt.Errorf("error finding ref: %s in spec: %v", refPath, err)
- }
- if name != "" {
- return name, nil
- }
- // lastPart now stores the final element of the type path. This is what
- // we use as the base for a type name.
- lastPart := pathParts[len(pathParts)-1]
- return SchemaNameToTypeName(lastPart), nil
+ return refPathToGoTypeSelf(refPath, local)
}
pathParts := strings.Split(refPath, "#")
if len(pathParts) != 2 {
return "", fmt.Errorf("unsupported reference: %s", refPath)
}
remoteComponent, flatComponent := pathParts[0], pathParts[1]
- if goImport, ok := globalState.importMapping[remoteComponent]; !ok {
+ goPkg, ok := globalState.importMapping[remoteComponent]
+
+ if !ok {
return "", fmt.Errorf("unrecognized external reference '%s'; please provide the known import for this reference using option --import-mapping", remoteComponent)
- } else {
- goType, err := refPathToGoType("#"+flatComponent, false)
- if err != nil {
- return "", err
+ }
+
+ if goPkg.Path == importMappingCurrentPackage {
+ return refPathToGoTypeSelf(fmt.Sprintf("#%s", pathParts[1]), local)
+ }
+
+ return refPathToGoTypeRemote(flatComponent, goPkg)
+
+}
+
+func refPathToGoTypeSelf(refPath string, local bool) (string, error) {
+ pathParts := strings.Split(refPath, "/")
+ depth := len(pathParts)
+ if local {
+ if depth != 4 {
+ return "", fmt.Errorf("unexpected reference depth: %d for ref: %s local: %t", depth, refPath, local)
}
- return fmt.Sprintf("%s.%s", goImport.Name, goType), nil
+ } else if depth != 4 && depth != 2 {
+ return "", fmt.Errorf("unexpected reference depth: %d for ref: %s local: %t", depth, refPath, local)
}
+
+ // When multi-pass name resolution is active, the resolved name takes
+ // precedence over the spec-given name. For a $ref like
+ // #/components/schemas/Thing, we pass the section ("schemas") and
+ // name ("Thing") to resolvedNameForComponent, which looks up the
+ // final Go type name assigned by the collision resolver.
+ // Note: the resolver prioritizes component schemas — if a schema and
+ // a response both claim "Thing", the component schema keeps the original
+ // name and the response becomes "ThingResponse".
+ if depth == 4 && pathParts[0] == "#" && pathParts[1] == "components" {
+ if resolved := resolvedNameForComponent(pathParts[2], pathParts[3]); resolved != "" {
+ return resolved, nil
+ }
+ }
+
+ // Schemas may have been renamed locally, so look up the actual name in
+ // the spec.
+ name, err := findSchemaNameByRefPath(refPath, globalState.spec)
+ if err != nil {
+ return "", fmt.Errorf("error finding ref: %s in spec: %v", refPath, err)
+ }
+ if name != "" {
+ return name, nil
+ }
+ // lastPart now stores the final element of the type path. This is what
+ // we use as the base for a type name.
+ lastPart := pathParts[len(pathParts)-1]
+ return SchemaNameToTypeName(lastPart), nil
+}
+
+func refPathToGoTypeRemote(flatComponent string, goPkg goImport) (string, error) {
+ goType, err := refPathToGoType("#"+flatComponent, false)
+ if err != nil {
+ return "", err
+ }
+ return fmt.Sprintf("%s.%s", goPkg.Name, goType), nil
}
// IsGoTypeReference takes a $ref value and checks if it has link to go type.
@@ -505,6 +627,32 @@ func SwaggerUriToGorillaUri(uri string) string {
return pathParamRE.ReplaceAllString(uri, "{$1}")
}
+// SwaggerUriToStdHttpUri converts a swagger style path URI with parameters to a
+// net/http ServeMux compatible path URI. Parameter names are sanitized to be
+// valid Go identifiers, as required by ServeMux wildcard segments. Valid input
+// parameters are:
+//
+// {param}
+// {param*}
+// {.param}
+// {.param*}
+// {;param}
+// {;param*}
+// {?param}
+// {?param*}
+func SwaggerUriToStdHttpUri(uri string) string {
+ // https://pkg.go.dev/net/http#hdr-Patterns-ServeMux
+ // The special wildcard {$} matches only the end of the URL. For example, the pattern "/{$}" matches only the path "/", whereas the pattern "/" matches every path.
+ if uri == "/" {
+ return "/{$}"
+ }
+
+ return pathParamRE.ReplaceAllStringFunc(uri, func(match string) string {
+ sub := pathParamRE.FindStringSubmatch(match)
+ return "{" + SanitizeGoIdentifier(sub[1]) + "}"
+ })
+}
+
// OrderedParamsFromUri returns the argument names, in order, in a given URI string, so for
// /path/{param1}/{.param2*}/{?param3}, it would return param1, param2, param3
func OrderedParamsFromUri(uri string) []string {
@@ -522,15 +670,29 @@ func ReplacePathParamsWithStr(uri string) string {
}
// SortParamsByPath reorders the given parameter definitions to match those in the path URI.
+// If a parameter appears more than once in the path (e.g. Keycloak's
+// /clients/{client-uuid}/roles/{role-name}/composites/clients/{client-uuid}),
+// duplicates are removed and only the first occurrence determines the order.
func SortParamsByPath(path string, in []ParameterDefinition) ([]ParameterDefinition, error) {
pathParams := OrderedParamsFromUri(path)
+
+ // Deduplicate, preserving first-occurrence order.
+ seen := make(map[string]struct{}, len(pathParams))
+ uniqueParams := make([]string, 0, len(pathParams))
+ for _, name := range pathParams {
+ if _, exists := seen[name]; !exists {
+ seen[name] = struct{}{}
+ uniqueParams = append(uniqueParams, name)
+ }
+ }
+
n := len(in)
- if len(pathParams) != n {
+ if len(uniqueParams) != n {
return nil, fmt.Errorf("path '%s' has %d positional parameters, but spec has %d declared",
- path, len(pathParams), n)
+ path, len(uniqueParams), n)
}
- out := make([]ParameterDefinition, len(in))
- for i, name := range pathParams {
+ out := make([]ParameterDefinition, n)
+ for i, name := range uniqueParams {
p := ParameterDefinitions(in).FindByName(name)
if p == nil {
return nil, fmt.Errorf("path '%s' refers to parameter '%s', which doesn't exist in specification",
@@ -587,9 +749,12 @@ func IsValidGoIdentity(str string) bool {
return !IsPredeclaredGoIdentifier(str)
}
-// SanitizeGoIdentity deletes and replaces the illegal runes in the given
-// string to use the string as a valid identity.
-func SanitizeGoIdentity(str string) string {
+// SanitizeGoIdentifier replaces illegal runes in the given string so that
+// it is a valid Go identifier. Unlike SanitizeGoIdentity, it does not
+// prefix reserved keywords or predeclared identifiers. This is useful for
+// contexts where the name must be a valid identifier but is not used as a
+// Go symbol (e.g. net/http ServeMux wildcard names).
+func SanitizeGoIdentifier(str string) string {
sanitized := []rune(str)
for i, c := range sanitized {
@@ -600,7 +765,14 @@ func SanitizeGoIdentity(str string) string {
}
}
- str = string(sanitized)
+ return string(sanitized)
+}
+
+// SanitizeGoIdentity deletes and replaces the illegal runes in the given
+// string to use the string as a valid identity. It also prefixes reserved
+// keywords and predeclared identifiers with an underscore.
+func SanitizeGoIdentity(str string) string {
+ str = SanitizeGoIdentifier(str)
if IsGoKeyword(str) || IsPredeclaredGoIdentifier(str) {
str = "_" + str
@@ -670,6 +842,10 @@ func typeNamePrefix(name string) (prefix string) {
prefix += "Tilde"
case '=':
prefix += "Equal"
+ case '>':
+ prefix += "GreaterThan"
+ case '<':
+ prefix += "LessThan"
case '#':
prefix += "Hash"
case '.':
@@ -680,6 +856,8 @@ func typeNamePrefix(name string) (prefix string) {
prefix += "Caret"
case '%':
prefix += "Percent"
+ case '_':
+ prefix += "Underscore"
default:
// Prepend "N" to schemas starting with a number
if prefix == "" && unicode.IsDigit(r) {
@@ -697,7 +875,7 @@ func typeNamePrefix(name string) (prefix string) {
// SchemaNameToTypeName converts a Schema name to a valid Go type name. It converts to camel case, and makes sure the name is
// valid in Go
func SchemaNameToTypeName(name string) string {
- return typeNamePrefix(name) + ToCamelCase(name)
+ return typeNamePrefix(name) + nameNormalizer(name)
}
// According to the spec, additionalProperties may be true, false, or a
@@ -721,11 +899,20 @@ func SchemaHasAdditionalProperties(schema *openapi3.Schema) bool {
// type name.
func PathToTypeName(path []string) string {
for i, p := range path {
- path[i] = ToCamelCase(p)
+ path[i] = nameNormalizer(p)
}
return strings.Join(path, "_")
}
+// StringToGoString takes an arbitrary string and converts it to a valid Go string literal,
+// including the quotes. For instance, `foo "bar"` would be converted to `"foo \"bar\""`.
+//
+// strconv.Quote escapes backslashes, newlines and other control characters too,
+// so untrusted spec text cannot break out of the generated string literal.
+func StringToGoString(in string) string {
+ return strconv.Quote(in)
+}
+
// StringToGoComment renders a possible multi-line string as a valid Go-Comment.
// Each line is prefixed as a comment.
func StringToGoComment(in string) string {
@@ -743,6 +930,8 @@ func DeprecationComment(reason string) string {
content := "Deprecated:" // The colon is required at the end even without reason
if reason != "" {
content += fmt.Sprintf(" %s", reason)
+ } else {
+ content += " this property has been marked as deprecated upstream, but no `x-deprecated-reason` was set"
}
return stringToGoCommentWithPrefix(content, "")
@@ -907,13 +1096,30 @@ func findSchemaNameByRefPath(refPath string, spec *openapi3.T) (string, error) {
}
func ParseGoImportExtension(v *openapi3.SchemaRef) (*goImport, error) {
- if v.Value.Extensions[extPropGoImport] == nil || v.Value.Extensions[extPropGoType] == nil {
+ // An x-go-type-import is only meaningful in concert with an x-go-type
+ // override. Without one, the imported package is never referenced in
+ // the generated code, producing an "imported and not used" compile
+ // error. Require at least one x-go-type to be in scope (either next to
+ // the $ref or on the referenced schema) before collecting an import.
+ hasGoType := v.Extensions[extPropGoType] != nil ||
+ (v.Value != nil && v.Value.Extensions[extPropGoType] != nil)
+ if !hasGoType {
return nil, nil
}
- goTypeImportExt := v.Value.Extensions[extPropGoImport]
+ var goTypeImportExt any
- importI, ok := goTypeImportExt.(map[string]interface{})
+ // check extensions next to the $ref before checking the schema itself
+ // values next to $ref will be used before those in the actual schema
+ if v.Extensions[extPropGoImport] != nil {
+ goTypeImportExt = v.Extensions[extPropGoImport]
+ } else if v.Value != nil && v.Value.Extensions[extPropGoImport] != nil {
+ goTypeImportExt = v.Value.Extensions[extPropGoImport]
+ } else {
+ return nil, nil
+ }
+
+ importI, ok := goTypeImportExt.(map[string]any)
if !ok {
return nil, fmt.Errorf("failed to convert type: %T", goTypeImportExt)
}
@@ -939,12 +1145,6 @@ func ParseGoImportExtension(v *openapi3.SchemaRef) (*goImport, error) {
return &gi, nil
}
-func MergeImports(dst, src map[string]goImport) {
- for k, v := range src {
- dst[k] = v
- }
-}
-
// TypeDefinitionsEquivalent checks for equality between two type definitions, but
// not every field is considered. We only want to know if they are fundamentally
// the same type.
@@ -961,5 +1161,5 @@ func isAdditionalPropertiesExplicitFalse(s *openapi3.Schema) bool {
return false
}
- return *s.AdditionalProperties.Has == false //nolint:gosimple
+ return !*s.AdditionalProperties.Has
}
diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go
index 8806c6adc5..df37c6d77a 100644
--- a/pkg/codegen/utils_test.go
+++ b/pkg/codegen/utils_test.go
@@ -18,127 +18,229 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
)
-func TestStringOps(t *testing.T) {
- // Test that each substitution works
- assert.Equal(t, "WordWordWORDWordWordWordWordWordWordWordWordWordWord", ToCamelCase("word.word-WORD+Word_word~word(Word)Word{Word}Word[Word]Word:Word;"), "Camel case conversion failed")
-
- // Make sure numbers don't interact in a funny way.
- assert.Equal(t, "Number1234", ToCamelCase("number-1234"), "Number Camelcasing not working.")
-}
-
-func TestSortedSchemaKeys(t *testing.T) {
- dict := map[string]*openapi3.SchemaRef{
- "f": nil,
- "c": nil,
- "b": nil,
- "e": nil,
- "d": nil,
- "a": nil,
+func TestToCamelCase(t *testing.T) {
+ tests := []struct {
+ str string
+ want string
+ }{{
+ str: "",
+ want: "",
+ }, {
+ str: " foo_bar ",
+ want: "FooBar",
+ }, {
+ str: "hi hello-hey-hallo",
+ want: "HiHelloHeyHallo",
+ }, {
+ str: "foo#bar",
+ want: "FooBar",
+ }, {
+ str: "foo2bar",
+ want: "Foo2bar",
+ }, {
+ // Test that each substitution works
+ str: "word.word-WORD+Word_word~word(Word)Word{Word}Word[Word]Word:Word;",
+ want: "WordWordWORDWordWordWordWordWordWordWordWordWordWord",
+ }, {
+ // Make sure numbers don't interact in a funny way.
+ str: "number-1234",
+ want: "Number1234",
+ },
}
-
- expected := []string{"a", "b", "c", "d", "e", "f"}
-
- assert.EqualValues(t, expected, SortedSchemaKeys(dict), "Keys are not sorted properly")
-}
-
-func TestSortedPathsKeys(t *testing.T) {
- dict := openapi3.Paths{
- "f": nil,
- "c": nil,
- "b": nil,
- "e": nil,
- "d": nil,
- "a": nil,
+ for i := range tests {
+ tt := tests[i]
+ t.Run(tt.str, func(t *testing.T) {
+ require.Equal(t, tt.want, ToCamelCase(tt.str))
+ })
}
-
- expected := []string{"a", "b", "c", "d", "e", "f"}
-
- assert.EqualValues(t, expected, SortedPathsKeys(dict), "Keys are not sorted properly")
}
-func TestSortedOperationsKeys(t *testing.T) {
- dict := map[string]*openapi3.Operation{
- "f": nil,
- "c": nil,
- "b": nil,
- "e": nil,
- "d": nil,
- "a": nil,
+func TestToCamelCaseWithDigits(t *testing.T) {
+ tests := []struct {
+ str string
+ want string
+ }{{
+ str: "",
+ want: "",
+ }, {
+ str: " foo_bar ",
+ want: "FooBar",
+ }, {
+ str: "hi hello-hey-hallo",
+ want: "HiHelloHeyHallo",
+ }, {
+ str: "foo#bar",
+ want: "FooBar",
+ }, {
+ str: "foo2bar",
+ want: "Foo2Bar",
+ }, {
+ str: "пир2пир",
+ want: "Пир2Пир",
+ }, {
+ // Test that each substitution works
+ str: "word.word3word-WORD+Word_word~word(Word)Word{Word}Word[Word]Word:Word;",
+ want: "WordWord3WordWORDWordWordWordWordWordWordWordWordWordWord",
+ }, {
+ // Make sure numbers don't interact in a funny way.
+ str: "number-1234",
+ want: "Number1234",
+ },
+ }
+ for i := range tests {
+ tt := tests[i]
+ t.Run(tt.str, func(t *testing.T) {
+ require.Equal(t, tt.want, ToCamelCaseWithDigits(tt.str))
+ })
}
-
- expected := []string{"a", "b", "c", "d", "e", "f"}
-
- assert.EqualValues(t, expected, SortedOperationsKeys(dict), "Keys are not sorted properly")
}
-func TestSortedResponsesKeys(t *testing.T) {
- dict := openapi3.Responses{
- "f": nil,
- "c": nil,
- "b": nil,
- "e": nil,
- "d": nil,
- "a": nil,
+func TestToCamelCaseWithInitialisms(t *testing.T) {
+ tests := []struct {
+ str string
+ want string
+ }{{
+ str: "",
+ want: "",
+ }, {
+ str: "hello",
+ want: "Hello",
+ }, {
+ str: "DBError",
+ want: "DBError",
+ }, {
+ str: "httpOperationId",
+ want: "HTTPOperationID",
+ }, {
+ str: "OperationId",
+ want: "OperationID",
+ }, {
+ str: "peer2peer",
+ want: "Peer2Peer",
+ }, {
+ str: "makeUtf8",
+ want: "MakeUTF8",
+ }, {
+ str: "utf8Hello",
+ want: "UTF8Hello",
+ }, {
+ str: "myDBError",
+ want: "MyDBError",
+ }, {
+ str: " DbLayer ",
+ want: "DBLayer",
+ }, {
+ str: "FindPetById",
+ want: "FindPetByID",
+ }, {
+ str: "MyHttpUrl",
+ want: "MyHTTPURL",
+ }, {
+ str: "find_user_by_uuid",
+ want: "FindUserByUUID",
+ }, {
+ str: "HelloПриветWorldМир42",
+ want: "HelloПриветWorldМир42",
+ }, {
+ str: "пир2пир",
+ want: "Пир2Пир",
+ }}
+ for i := range tests {
+ tt := tests[i]
+ t.Run(tt.str, func(t *testing.T) {
+ require.Equal(t, tt.want, ToCamelCaseWithInitialisms(tt.str))
+ })
}
-
- expected := []string{"a", "b", "c", "d", "e", "f"}
-
- assert.EqualValues(t, expected, SortedResponsesKeys(dict), "Keys are not sorted properly")
}
-func TestSortedContentKeys(t *testing.T) {
- dict := openapi3.Content{
- "f": nil,
- "c": nil,
- "b": nil,
- "e": nil,
- "d": nil,
- "a": nil,
+func TestSortedSchemaKeysWithXOrder(t *testing.T) {
+ withOrder := func(i float64) *openapi3.SchemaRef {
+ return &openapi3.SchemaRef{
+ Value: &openapi3.Schema{
+ Extensions: map[string]any{"x-order": i},
+ },
+ }
+ }
+ dict := map[string]*openapi3.SchemaRef{
+ "first": withOrder(1),
+ "minusTenth": withOrder(-10),
+ "zero": withOrder(0),
+ "minusHundredth_2": withOrder(-100),
+ "minusHundredth_1": withOrder(-100),
+ "afterFirst": withOrder(2),
+ "last": withOrder(100),
+ "middleA": nil,
+ "middleB": nil,
+ "middleC": nil,
}
- expected := []string{"a", "b", "c", "d", "e", "f"}
+ expected := []string{"minusHundredth_1", "minusHundredth_2", "minusTenth", "zero", "first", "afterFirst", "middleA", "middleB", "middleC", "last"}
- assert.EqualValues(t, expected, SortedContentKeys(dict), "Keys are not sorted properly")
+ assert.EqualValues(t, expected, SortedSchemaKeys(dict), "Keys are not sorted properly")
}
-func TestSortedParameterKeys(t *testing.T) {
- dict := map[string]*openapi3.ParameterRef{
- "f": nil,
- "c": nil,
- "b": nil,
- "e": nil,
- "d": nil,
- "a": nil,
- }
+func TestSortedSchemaKeysWithXOrderFromParsed(t *testing.T) {
+ rawSpec := `---
+components:
+ schemas:
+ AlwaysLast:
+ type: string
+ x-order: 100000
+ DateInterval:
+ type: object
+ required:
+ - name
+ properties:
+ end:
+ type: string
+ format: date
+ x-order: 2
+ start:
+ type: string
+ format: date
+ x-order: 1
+ `
+
+ loader := openapi3.NewLoader()
+ spec, err := loader.LoadFromData([]byte(rawSpec))
+ require.NoError(t, err)
+ require.NotNil(t, spec.Components)
+ require.NotNil(t, spec.Components.Schemas)
+
+ t.Run("for the top-level schemas", func(t *testing.T) {
+ expected := []string{"DateInterval", "AlwaysLast"}
+
+ actual := SortedSchemaKeys(spec.Components.Schemas)
+
+ assert.EqualValues(t, expected, actual)
+ })
- expected := []string{"a", "b", "c", "d", "e", "f"}
+ t.Run("for DateInterval's keys", func(t *testing.T) {
+ schemas, found := spec.Components.Schemas["DateInterval"]
+ require.True(t, found, "did not find `#/components/schemas/DateInterval`")
- assert.EqualValues(t, expected, SortedParameterKeys(dict), "Keys are not sorted properly")
-}
+ expected := []string{"start", "end"}
-func TestSortedRequestBodyKeys(t *testing.T) {
- dict := map[string]*openapi3.RequestBodyRef{
- "f": nil,
- "c": nil,
- "b": nil,
- "e": nil,
- "d": nil,
- "a": nil,
- }
+ actual := SortedSchemaKeys(schemas.Value.Properties)
- expected := []string{"a", "b", "c", "d", "e", "f"}
+ assert.EqualValues(t, expected, actual, "Keys are not sorted properly")
+ })
- assert.EqualValues(t, expected, SortedRequestBodyKeys(dict), "Keys are not sorted properly")
}
func TestRefPathToGoType(t *testing.T) {
old := globalState.importMapping
- globalState.importMapping = constructImportMapping(map[string]string{
- "doc.json": "externalref0",
- "http://deepmap.com/doc.json": "externalref1",
- })
+ globalState.importMapping = constructImportMapping(
+ map[string]string{
+ "doc.json": "externalref0",
+ "http://deepmap.com/doc.json": "externalref1",
+ // using the "current package" mapping
+ "dj-current-package.yml": "-",
+ },
+ )
defer func() { globalState.importMapping = old }()
tests := []struct {
@@ -161,6 +263,11 @@ func TestRefPathToGoType(t *testing.T) {
path: "#/components/responses/wibble",
goType: "Wibble",
},
+ {
+ name: "local-mapped-current-package",
+ path: "dj-current-package.yml#/components/schemas/Foo",
+ goType: "Foo",
+ },
{
name: "remote-root",
path: "doc.json#/foo",
@@ -314,12 +421,101 @@ func TestSwaggerUriToFiberUri(t *testing.T) {
assert.Equal(t, "/path/:arg/foo", SwaggerUriToFiberUri("/path/{?arg*}/foo"))
}
+func TestSwaggerUriToChiUri(t *testing.T) {
+ assert.Equal(t, "/path", SwaggerUriToChiUri("/path"))
+ assert.Equal(t, "/path/{arg}", SwaggerUriToChiUri("/path/{arg}"))
+ assert.Equal(t, "/path/{arg1}/{arg2}", SwaggerUriToChiUri("/path/{arg1}/{arg2}"))
+ assert.Equal(t, "/path/{arg1}/{arg2}/foo", SwaggerUriToChiUri("/path/{arg1}/{arg2}/foo"))
+
+ // Make sure all the exploded and alternate formats match too
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToChiUri("/path/{arg}/foo"))
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToChiUri("/path/{arg*}/foo"))
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToChiUri("/path/{.arg}/foo"))
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToChiUri("/path/{.arg*}/foo"))
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToChiUri("/path/{;arg}/foo"))
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToChiUri("/path/{;arg*}/foo"))
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToChiUri("/path/{?arg}/foo"))
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToChiUri("/path/{?arg*}/foo"))
+}
+
+func TestSwaggerUriToStdHttpUriUri(t *testing.T) {
+ assert.Equal(t, "/{$}", SwaggerUriToStdHttpUri("/"))
+ assert.Equal(t, "/path", SwaggerUriToStdHttpUri("/path"))
+ assert.Equal(t, "/path/{arg}", SwaggerUriToStdHttpUri("/path/{arg}"))
+ assert.Equal(t, "/path/{arg1}/{arg2}", SwaggerUriToStdHttpUri("/path/{arg1}/{arg2}"))
+ assert.Equal(t, "/path/{arg1}/{arg2}/foo", SwaggerUriToStdHttpUri("/path/{arg1}/{arg2}/foo"))
+
+ // Make sure all the exploded and alternate formats match too
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToStdHttpUri("/path/{arg}/foo"))
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToStdHttpUri("/path/{arg*}/foo"))
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToStdHttpUri("/path/{.arg}/foo"))
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToStdHttpUri("/path/{.arg*}/foo"))
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToStdHttpUri("/path/{;arg}/foo"))
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToStdHttpUri("/path/{;arg*}/foo"))
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToStdHttpUri("/path/{?arg}/foo"))
+ assert.Equal(t, "/path/{arg}/foo", SwaggerUriToStdHttpUri("/path/{?arg*}/foo"))
+
+ // Parameter names that are not valid Go identifiers must be sanitized (issue #2278)
+ assert.Equal(t, "/path/{addressing_identifier}", SwaggerUriToStdHttpUri("/path/{addressing-identifier}"))
+ assert.Equal(t, "/path/{my_param}/{other_param}", SwaggerUriToStdHttpUri("/path/{my-param}/{other-param}"))
+
+ // Go keywords are valid ServeMux wildcard names and should not be prefixed
+ assert.Equal(t, "/path/{type}", SwaggerUriToStdHttpUri("/path/{type}"))
+}
+
func TestOrderedParamsFromUri(t *testing.T) {
result := OrderedParamsFromUri("/path/{param1}/{.param2}/{;param3*}/foo")
assert.EqualValues(t, []string{"param1", "param2", "param3"}, result)
result = OrderedParamsFromUri("/path/foo")
assert.EqualValues(t, []string{}, result)
+
+ // A parameter can appear more than once in the URI (e.g. Keycloak API).
+ // OrderedParamsFromUri faithfully returns all occurrences.
+ result = OrderedParamsFromUri("/admin/realms/{realm}/clients/{client-uuid}/roles/{role-name}/composites/clients/{client-uuid}")
+ assert.EqualValues(t, []string{"realm", "client-uuid", "role-name", "client-uuid"}, result)
+}
+
+func TestSortParamsByPath(t *testing.T) {
+ strSchema := &openapi3.Schema{Type: &openapi3.Types{"string"}}
+
+ t.Run("reorders params to match path order", func(t *testing.T) {
+ params := []ParameterDefinition{
+ {ParamName: "b", In: "path", Spec: &openapi3.Parameter{Name: "b", Schema: &openapi3.SchemaRef{Value: strSchema}}},
+ {ParamName: "a", In: "path", Spec: &openapi3.Parameter{Name: "a", Schema: &openapi3.SchemaRef{Value: strSchema}}},
+ }
+ sorted, err := SortParamsByPath("/foo/{a}/bar/{b}", params)
+ require.NoError(t, err)
+ require.Len(t, sorted, 2)
+ assert.Equal(t, "a", sorted[0].ParamName)
+ assert.Equal(t, "b", sorted[1].ParamName)
+ })
+
+ t.Run("errors on missing parameter", func(t *testing.T) {
+ params := []ParameterDefinition{
+ {ParamName: "a", In: "path", Spec: &openapi3.Parameter{Name: "a", Schema: &openapi3.SchemaRef{Value: strSchema}}},
+ }
+ _, err := SortParamsByPath("/foo/{a}/bar/{b}", params)
+ assert.Error(t, err)
+ })
+
+ t.Run("handles duplicate path parameters", func(t *testing.T) {
+ // This is the Keycloak-style path where {client-uuid} appears twice.
+ // The spec only declares 3 unique parameters.
+ params := []ParameterDefinition{
+ {ParamName: "realm", In: "path", Spec: &openapi3.Parameter{Name: "realm", Schema: &openapi3.SchemaRef{Value: strSchema}}},
+ {ParamName: "client-uuid", In: "path", Spec: &openapi3.Parameter{Name: "client-uuid", Schema: &openapi3.SchemaRef{Value: strSchema}}},
+ {ParamName: "role-name", In: "path", Spec: &openapi3.Parameter{Name: "role-name", Schema: &openapi3.SchemaRef{Value: strSchema}}},
+ }
+ path := "/admin/realms/{realm}/clients/{client-uuid}/roles/{role-name}/composites/clients/{client-uuid}"
+ sorted, err := SortParamsByPath(path, params)
+ require.NoError(t, err)
+ // Should return 3 unique params in first-occurrence order
+ require.Len(t, sorted, 3)
+ assert.Equal(t, "realm", sorted[0].ParamName)
+ assert.Equal(t, "client-uuid", sorted[1].ParamName)
+ assert.Equal(t, "role-name", sorted[2].ParamName)
+ })
}
func TestReplacePathParamsWithStr(t *testing.T) {
@@ -327,6 +523,49 @@ func TestReplacePathParamsWithStr(t *testing.T) {
assert.EqualValues(t, "/path/%s/%s/%s/foo", result)
}
+func TestStringToGoStringValue(t *testing.T) {
+ testCases := []struct {
+ input string
+ expected string
+ message string
+ }{
+ {
+ input: ``,
+ expected: `""`,
+ message: "blank string should be converted to empty Go string literal",
+ },
+ {
+ input: `application/json`,
+ expected: `"application/json"`,
+ message: "typical string should be returned as-is",
+ },
+ {
+ input: `application/json; foo="bar"`,
+ expected: `"application/json; foo=\"bar\""`,
+ message: "string with quotes should include escape characters",
+ },
+ {
+ // The previous implementation only escaped `"`, so a backslash
+ // before a quote (`\"`) escaped the escaping and let untrusted
+ // spec text break out of the generated string literal.
+ input: `a\"; var Evil = 1; var _ = "`,
+ expected: `"a\\\"; var Evil = 1; var _ = \""`,
+ message: "backslashes must be escaped so a quote cannot break out of the literal",
+ },
+ {
+ input: "line1\nline2",
+ expected: `"line1\nline2"`,
+ message: "newlines must be escaped so they cannot terminate the literal",
+ },
+ }
+ for _, testCase := range testCases {
+ t.Run(testCase.message, func(t *testing.T) {
+ result := StringToGoString(testCase.input)
+ assert.EqualValues(t, testCase.expected, result, testCase.message)
+ })
+ }
+}
+
func TestStringToGoComment(t *testing.T) {
testCases := []struct {
input string
@@ -458,10 +697,15 @@ func TestSchemaNameToTypeName(t *testing.T) {
"@timestamp,": "Timestamp",
"&now": "AndNow",
"~": "Tilde",
- "_foo": "Foo",
+ "_foo": "UnderscoreFoo",
"=3": "Equal3",
"#Tag": "HashTag",
".com": "DotCom",
+ "_1": "Underscore1",
+ ">=": "GreaterThanEqual",
+ "<=": "LessThanEqual",
+ "<": "LessThan",
+ ">": "GreaterThan",
} {
assert.Equal(t, want, SchemaNameToTypeName(in))
}
@@ -491,7 +735,38 @@ func TestRefPathToObjName(t *testing.T) {
}
}
-func Test_replaceInitialisms(t *testing.T) {
+func TestLowercaseFirstCharacters(t *testing.T) {
+ tests := []struct {
+ name string
+ in string
+ expected string
+ }{
+ {
+ name: "id",
+ expected: "id",
+ },
+ {
+ name: "CamelCase",
+ expected: "camelCase",
+ },
+ {
+ name: "ID",
+ expected: "id",
+ },
+ {
+ name: "DBTree",
+ expected: "dbTree",
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ assert.Equal(t, tt.expected, LowercaseFirstCharacters(tt.name))
+ })
+ }
+}
+
+func Test_replaceInitialism(t *testing.T) {
type args struct {
s string
}
@@ -525,6 +800,16 @@ func Test_replaceInitialisms(t *testing.T) {
args: args{s: "fooIDBarAPI"},
want: "fooIDBarAPI",
},
+ {
+ name: "one initialism at start",
+ args: args{s: "idFoo"},
+ want: "idFoo",
+ },
+ {
+ name: "one initialism at start and one in middle",
+ args: args{s: "apiIdFoo"},
+ want: "apiIDFoo",
+ },
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
diff --git a/pkg/ecdsafile/ecdsafile.go b/pkg/ecdsafile/ecdsafile.go
index b5240a1468..fabb3aa3c8 100644
--- a/pkg/ecdsafile/ecdsafile.go
+++ b/pkg/ecdsafile/ecdsafile.go
@@ -29,7 +29,7 @@ func LoadEcdsaPublicKey(buf []byte) (*ecdsa.PublicKey, error) {
// which supports multiple types of keys.
keyIface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
- return nil, fmt.Errorf("Error loading public key: %w", err)
+ return nil, fmt.Errorf("error loading public key: %w", err)
}
// Now, we're assuming the key content is ECDSA, and converting.
@@ -53,7 +53,7 @@ func LoadEcdsaPrivateKey(buf []byte) (*ecdsa.PrivateKey, error) {
// and we're assuming this encoding contains X509 key material.
privateKey, err := x509.ParseECPrivateKey(block.Bytes)
if err != nil {
- return nil, fmt.Errorf("Error loading private ECDSA key: %w", err)
+ return nil, fmt.Errorf("error loading private ECDSA key: %w", err)
}
return privateKey, nil
}
diff --git a/pkg/fiber-middleware/oapi_validate.go b/pkg/fiber-middleware/oapi_validate.go
deleted file mode 100644
index a193583a8f..0000000000
--- a/pkg/fiber-middleware/oapi_validate.go
+++ /dev/null
@@ -1,207 +0,0 @@
-// Package middleware implements middleware function for server implementations,
-// which validates incoming HTTP requests to make sure that they conform to the given OAPI 3.0 specification.
-// When OAPI validation fails on the request, we return an HTTP/400.
-package middleware
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "os"
- "strings"
-
- "github.com/getkin/kin-openapi/openapi3"
- "github.com/getkin/kin-openapi/openapi3filter"
- "github.com/getkin/kin-openapi/routers"
- "github.com/getkin/kin-openapi/routers/gorillamux"
- "github.com/gofiber/fiber/v2"
- "github.com/gofiber/fiber/v2/middleware/adaptor"
-)
-
-type ctxKeyFiberContext struct{}
-type ctxKeyUserData struct{}
-
-// OapiValidatorFromYamlFile creates a validator middleware from a YAML file path
-// Deprecated: This has been replaced by github.com/oapi-codegen/fiber-middleware#OapiValidatorFromYamlFile
-func OapiValidatorFromYamlFile(path string) (fiber.Handler, error) {
-
- data, err := os.ReadFile(path)
- if err != nil {
- return nil, fmt.Errorf("error reading %s: %s", path, err)
- }
-
- swagger, err := openapi3.NewLoader().LoadFromData(data)
- if err != nil {
- return nil, fmt.Errorf("error parsing %s as Swagger YAML: %s",
- path, err)
- }
-
- return OapiRequestValidator(swagger), nil
-}
-
-// OapiRequestValidator is a fiber middleware function which validates incoming HTTP requests
-// to make sure that they conform to the given OAPI 3.0 specification. When
-// OAPI validation fails on the request, we return an HTTP/400 with error message
-// Deprecated: This has been replaced by github.com/oapi-codegen/fiber-middleware#OapiRequestValidator
-func OapiRequestValidator(swagger *openapi3.T) fiber.Handler {
- return OapiRequestValidatorWithOptions(swagger, nil)
-}
-
-// ErrorHandler is called when there is an error in validation
-// Deprecated: This has been replaced by github.com/oapi-codegen/fiber-middleware#ErrorHandler
-type ErrorHandler func(c *fiber.Ctx, message string, statusCode int)
-
-// MultiErrorHandler is called when oapi returns a MultiError type
-// Deprecated: This has been replaced by github.com/oapi-codegen/fiber-middleware#MultiErrorHandler
-type MultiErrorHandler func(openapi3.MultiError) error
-
-// Options to customize request validation. These are passed through to
-// openapi3filter.
-// Deprecated: This has been replaced by github.com/oapi-codegen/fiber-middleware#Options
-type Options struct {
- Options openapi3filter.Options
- ErrorHandler ErrorHandler
- ParamDecoder openapi3filter.ContentParameterDecoder
- UserData interface{}
- MultiErrorHandler MultiErrorHandler
-}
-
-// OapiRequestValidatorWithOptions creates a validator from a swagger object, with validation options
-// Deprecated: This has been replaced by github.com/oapi-codegen/fiber-middleware#OapiRequestValidatorWithOptions
-func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) fiber.Handler {
-
- router, err := gorillamux.NewRouter(swagger)
- if err != nil {
- panic(err)
- }
-
- return func(c *fiber.Ctx) error {
-
- err := ValidateRequestFromContext(c, router, options)
- if err != nil {
- if options != nil && options.ErrorHandler != nil {
- options.ErrorHandler(c, err.Error(), http.StatusBadRequest)
- // in case the handler didn't internally call Abort, stop the chain
- return nil
- } else {
- // note: I am not sure if this is the best way to handle this
- return fiber.NewError(http.StatusBadRequest, err.Error())
- }
- }
- return c.Next()
- }
-}
-
-// ValidateRequestFromContext is called from the middleware above and actually does the work
-// of validating a request.
-// Deprecated: This has been replaced by github.com/oapi-codegen/fiber-middleware#
-func ValidateRequestFromContext(c *fiber.Ctx, router routers.Router, options *Options) error {
-
- r, err := adaptor.ConvertRequest(c, false)
- if err != nil {
- return err
- }
-
- route, pathParams, err := router.FindRoute(r)
-
- // We failed to find a matching route for the request.
- if err != nil {
- switch e := err.(type) {
- case *routers.RouteError:
- // We've got a bad request, the path requested doesn't match
- // either server, or path, or something.
- return errors.New(e.Reason)
- default:
- // This should never happen today, but if our upstream code changes,
- // we don't want to crash the server, so handle the unexpected error.
- return fmt.Errorf("error validating route: %s", err.Error())
- }
- }
-
- // Validate request
- requestValidationInput := &openapi3filter.RequestValidationInput{
- Request: r,
- PathParams: pathParams,
- Route: route,
- }
-
- // Pass the fiber context into the request validator, so that any callbacks
- // which it invokes make it available.
- requestContext := context.WithValue(context.Background(), ctxKeyFiberContext{}, c) //nolint:staticcheck
-
- if options != nil {
- requestValidationInput.Options = &options.Options
- requestValidationInput.ParamDecoder = options.ParamDecoder
- requestContext = context.WithValue(requestContext, ctxKeyUserData{}, options.UserData) //nolint:staticcheck
- }
-
- err = openapi3filter.ValidateRequest(requestContext, requestValidationInput)
- if err != nil {
- me := openapi3.MultiError{}
- if errors.As(err, &me) {
- errFunc := getMultiErrorHandlerFromOptions(options)
- return errFunc(me)
- }
-
- switch e := err.(type) {
- case *openapi3filter.RequestError:
- // We've got a bad request
- // Split up the verbose error by lines and return the first one
- // openapi errors seem to be multi-line with a decent message on the first
- errorLines := strings.Split(e.Error(), "\n")
- return fmt.Errorf("error in openapi3filter.RequestError: %s", errorLines[0])
- case *openapi3filter.SecurityRequirementsError:
- return fmt.Errorf("error in openapi3filter.SecurityRequirementsError: %s", e.Error())
- default:
- // This should never happen today, but if our upstream code changes,
- // we don't want to crash the server, so handle the unexpected error.
- return fmt.Errorf("error validating request: %w", err)
- }
- }
- return nil
-}
-
-// GetFiberContext gets the fiber context from within requests. It returns
-// nil if not found or wrong type.
-// Deprecated: This has been replaced by github.com/oapi-codegen/fiber-middleware#GetFiberContext
-func GetFiberContext(c context.Context) *fiber.Ctx {
- iface := c.Value(ctxKeyFiberContext{})
- if iface == nil {
- return nil
- }
-
- fiberCtx, ok := iface.(*fiber.Ctx)
- if ok {
- return fiberCtx
- }
- return nil
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/fiber-middleware#GetUserData
-func GetUserData(c context.Context) interface{} {
- return c.Value(ctxKeyUserData{})
-}
-
-// getMultiErrorHandlerFromOptions attempts to get the MultiErrorHandler from the options. If it is not set,
-// return a default handler
-// Deprecated: This has been replaced by github.com/oapi-codegen/fiber-middleware#getMultiErrorHandlerFromOptions
-func getMultiErrorHandlerFromOptions(options *Options) MultiErrorHandler {
- if options == nil {
- return defaultMultiErrorHandler
- }
-
- if options.MultiErrorHandler == nil {
- return defaultMultiErrorHandler
- }
-
- return options.MultiErrorHandler
-}
-
-// defaultMultiErrorHandler returns a StatusBadRequest (400) and a list
-// of all the errors. This method is called if there are no other
-// methods defined on the options.
-// Deprecated: This has been replaced by github.com/oapi-codegen/fiber-middleware#defaultMultiErrorHandler
-func defaultMultiErrorHandler(me openapi3.MultiError) error {
- return fmt.Errorf("multiple errors encountered: %s", me)
-}
diff --git a/pkg/fiber-middleware/oapi_validate_test.go b/pkg/fiber-middleware/oapi_validate_test.go
deleted file mode 100644
index 9201e13fb8..0000000000
--- a/pkg/fiber-middleware/oapi_validate_test.go
+++ /dev/null
@@ -1,434 +0,0 @@
-package middleware
-
-import (
- "bytes"
- "context"
- _ "embed"
- "encoding/json"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/getkin/kin-openapi/openapi3"
- "github.com/getkin/kin-openapi/openapi3filter"
- "github.com/gofiber/fiber/v2"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-//go:embed test_spec.yaml
-var testSchema []byte
-
-func doGet(t *testing.T, app *fiber.App, rawURL string) *http.Response {
- t.Helper()
-
- u, err := url.Parse(rawURL)
- if err != nil {
- t.Fatalf("invalid URL %q: %v", rawURL, err)
- }
-
- req := httptest.NewRequest("GET", u.RequestURI(), nil)
- req.Header.Add("Accept", "application/json")
- req.Host = u.Host
-
- r, err := app.Test(req)
- if err != nil {
- t.Fatalf("Failed to test request, URL=%q: %v", rawURL, err)
- }
-
- return r
-}
-
-func doPost(t *testing.T, app *fiber.App, rawURL string, jsonBody interface{}) *http.Response {
- t.Helper()
-
- u, err := url.Parse(rawURL)
- if err != nil {
- t.Fatalf("invalid url %q: %v", rawURL, err)
- }
-
- buf, err := json.Marshal(jsonBody)
- if err != nil {
- t.Fatalf("failed to marshal: %v", err)
- }
-
- req := httptest.NewRequest("POST", u.RequestURI(), bytes.NewReader(buf))
- req.Header.Add("Accept", "application/json")
- req.Header.Add("Content-Type", "application/json")
- req.Host = u.Host
-
- r, err := app.Test(req)
- if err != nil {
- t.Fatalf("Failed to test request, URL=%q: %v", rawURL, err)
- }
-
- return r
-}
-
-func TestOapiRequestValidator(t *testing.T) {
-
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- // Create a new fiber router
- app := fiber.New()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- ErrorHandler: func(c *fiber.Ctx, message string, statusCode int) {
- _ = c.Status(statusCode).SendString("test: " + message)
- },
- Options: openapi3filter.Options{
- AuthenticationFunc: func(c context.Context, input *openapi3filter.AuthenticationInput) error {
- // The fiber context should be propagated into here.
- gCtx := GetFiberContext(c)
- assert.NotNil(t, gCtx)
- // As should user data
- assert.EqualValues(t, "hi!", GetUserData(c))
-
- for _, s := range input.Scopes {
- if s == "someScope" {
- return nil
- }
- if s == "unauthorized" {
- return errors.New("unauthorized")
- }
- }
- return errors.New("forbidden")
- },
- },
- UserData: "hi!",
- }
-
- // Install our OpenApi based request validator
- app.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- app.Get("/resource", func(c *fiber.Ctx) error {
- called = true
- return nil
- })
- // Let's send the request to the wrong server, this should fail validation
- {
- res := doGet(t, app, "https://not.deepmap.ai/resource")
- assert.Equal(t, http.StatusBadRequest, res.StatusCode)
- assert.False(t, called, "Handler should not have been called")
- }
-
- // Let's send a good request, it should pass
- {
- res := doGet(t, app, "https://deepmap.ai/resource")
- assert.Equal(t, http.StatusOK, res.StatusCode)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Send an out-of-spec parameter
- {
- res := doGet(t, app, "https://deepmap.ai/resource?id=500")
- assert.Equal(t, http.StatusBadRequest, res.StatusCode)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Send a bad parameter type
- {
- res := doGet(t, app, "https://deepmap.ai/resource?id=foo")
- assert.Equal(t, http.StatusBadRequest, res.StatusCode)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Add a handler for the POST message
- app.Post("/resource", func(c *fiber.Ctx) error {
- called = true
- return c.SendStatus(http.StatusNoContent)
- })
-
- called = false
- // Send a good request body
- {
- body := struct {
- Name string `json:"name"`
- }{
- Name: "Marcin",
- }
- res := doPost(t, app, "https://deepmap.ai/resource", body)
- assert.Equal(t, http.StatusNoContent, res.StatusCode)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Send a malformed body
- {
- body := struct {
- Name int `json:"name"`
- }{
- Name: 7,
- }
- res := doPost(t, app, "https://deepmap.ai/resource", body)
- assert.Equal(t, http.StatusBadRequest, res.StatusCode)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- app.Get("/protected_resource", func(c *fiber.Ctx) error {
- called = true
- return c.SendStatus(http.StatusNoContent)
- })
-
- // Call a protected function to which we have access
- {
- res := doGet(t, app, "https://deepmap.ai/protected_resource")
- assert.Equal(t, http.StatusNoContent, res.StatusCode)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- app.Get("/protected_resource2", func(c *fiber.Ctx) error {
- called = true
- return c.SendStatus(http.StatusNoContent)
- })
- // Call a protected function to which we don't have access
- {
- res := doGet(t, app, "https://deepmap.ai/protected_resource2")
- assert.Equal(t, http.StatusBadRequest, res.StatusCode)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- app.Get("/protected_resource_401", func(c *fiber.Ctx) error {
- called = true
- return c.SendStatus(http.StatusNoContent)
- })
- // Call a protected function without credentials
- {
- res := doGet(t, app, "https://deepmap.ai/protected_resource_401")
- assert.Equal(t, http.StatusBadRequest, res.StatusCode)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Equal(t, "test: error in openapi3filter.SecurityRequirementsError: security requirements failed: unauthorized", string(body))
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-}
-
-func TestOapiRequestValidatorWithOptionsMultiError(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- app := fiber.New()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- Options: openapi3filter.Options{
- ExcludeRequestBody: false,
- ExcludeResponseBody: false,
- IncludeResponseStatus: true,
- MultiError: true,
- },
- }
-
- // register middleware
- app.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- app.Get("/multiparamresource", func(c *fiber.Ctx) error {
- called = true
- return nil
- })
-
- // Let's send a good request, it should pass
- {
- res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50&id2=50")
- assert.Equal(t, http.StatusOK, res.StatusCode)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Let's send a request with a missing parameter, it should return
- // a bad status
- {
- res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50")
- assert.Equal(t, http.StatusBadRequest, res.StatusCode)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "multiple errors encountered")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 2 missing parameters, it should return
- // a bad status
- {
- res := doGet(t, app, "https://deepmap.ai/multiparamresource")
- assert.Equal(t, http.StatusBadRequest, res.StatusCode)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "multiple errors encountered")
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "value is required but missing")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 1 missing parameter, and another outside
- // or the parameters. It should return a bad status
- {
- res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=500")
- assert.Equal(t, http.StatusBadRequest, res.StatusCode)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "multiple errors encountered")
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "number must be at most 100")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a parameters that do not meet spec. It should
- // return a bad status
- {
- res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=abc&id2=1")
- assert.Equal(t, http.StatusBadRequest, res.StatusCode)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "multiple errors encountered")
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "number must be at least 10")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-}
-
-func TestOapiRequestValidatorWithOptionsMultiErrorAndCustomHandler(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- app := fiber.New()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- Options: openapi3filter.Options{
- ExcludeRequestBody: false,
- ExcludeResponseBody: false,
- IncludeResponseStatus: true,
- MultiError: true,
- },
- MultiErrorHandler: func(me openapi3.MultiError) error {
- return fmt.Errorf("Bad stuff - %s", me.Error())
- },
- }
-
- // register middleware
- app.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- app.Get("/multiparamresource", func(c *fiber.Ctx) error {
- called = true
- return nil
- })
-
- // Let's send a good request, it should pass
- {
- res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50&id2=50")
- assert.Equal(t, http.StatusOK, res.StatusCode)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Let's send a request with a missing parameter, it should return
- // a bad status
- {
- res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=50")
- assert.Equal(t, http.StatusBadRequest, res.StatusCode)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "Bad stuff")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 2 missing parameters, it should return
- // a bad status
- {
- res := doGet(t, app, "https://deepmap.ai/multiparamresource")
- assert.Equal(t, http.StatusBadRequest, res.StatusCode)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "Bad stuff")
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "value is required but missing")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 1 missing parameter, and another outside
- // or the parameters. It should return a bad status
- {
- res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=500")
- assert.Equal(t, http.StatusBadRequest, res.StatusCode)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "Bad stuff")
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "number must be at most 100")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a parameters that do not meet spec. It should
- // return a bad status
- {
- res := doGet(t, app, "https://deepmap.ai/multiparamresource?id=abc&id2=1")
- assert.Equal(t, http.StatusBadRequest, res.StatusCode)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "Bad stuff")
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "number must be at least 10")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-}
diff --git a/pkg/fiber-middleware/test_spec.yaml b/pkg/fiber-middleware/test_spec.yaml
deleted file mode 100644
index 6e0a2415d2..0000000000
--- a/pkg/fiber-middleware/test_spec.yaml
+++ /dev/null
@@ -1,103 +0,0 @@
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: TestServer
-servers:
- - url: http://deepmap.ai/
-paths:
- /resource:
- get:
- operationId: getResource
- parameters:
- - name: id
- in: query
- schema:
- type: integer
- minimum: 10
- maximum: 100
- responses:
- '200':
- description: success
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- id:
- type: integer
- post:
- operationId: createResource
- responses:
- '204':
- description: No content
- requestBody:
- required: true
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- /protected_resource:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - someScope
- responses:
- '204':
- description: no content
- /protected_resource2:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - otherScope
- responses:
- '204':
- description: no content
- /protected_resource_401:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - unauthorized
- responses:
- '401':
- description: no content
- /multiparamresource:
- get:
- operationId: getResource
- parameters:
- - name: id
- in: query
- required: true
- schema:
- type: integer
- minimum: 10
- maximum: 100
- - name: id2
- required: true
- in: query
- schema:
- type: integer
- minimum: 10
- maximum: 100
- responses:
- '200':
- description: success
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- id:
- type: integer
-components:
- securitySchemes:
- BearerAuth:
- type: http
- scheme: bearer
- bearerFormat: JWT
diff --git a/pkg/gin-middleware/oapi_validate.go b/pkg/gin-middleware/oapi_validate.go
deleted file mode 100644
index d28b13749e..0000000000
--- a/pkg/gin-middleware/oapi_validate.go
+++ /dev/null
@@ -1,221 +0,0 @@
-// Copyright 2021 DeepMap, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package middleware
-
-import (
- "context"
- "errors"
- "fmt"
- "log"
- "net/http"
- "os"
- "strings"
-
- "github.com/getkin/kin-openapi/openapi3"
- "github.com/getkin/kin-openapi/openapi3filter"
- "github.com/getkin/kin-openapi/routers"
- "github.com/getkin/kin-openapi/routers/gorillamux"
- "github.com/gin-gonic/gin"
-)
-
-const (
- GinContextKey = "oapi-codegen/gin-context"
- UserDataKey = "oapi-codegen/user-data"
-)
-
-// OapiValidatorFromYamlFile creates a validator middleware from a YAML file path
-// Deprecated: This has been replaced by github.com/oapi-codegen/gin-middleware#OapiValidatorFromYamlFile
-func OapiValidatorFromYamlFile(path string) (gin.HandlerFunc, error) {
- data, err := os.ReadFile(path)
- if err != nil {
- return nil, fmt.Errorf("error reading %s: %s", path, err)
- }
-
- swagger, err := openapi3.NewLoader().LoadFromData(data)
- if err != nil {
- return nil, fmt.Errorf("error parsing %s as Swagger YAML: %s",
- path, err)
- }
- return OapiRequestValidator(swagger), nil
-}
-
-// OapiRequestValidator is an gin middleware function which validates incoming HTTP requests
-// to make sure that they conform to the given OAPI 3.0 specification. When
-// OAPI validation fails on the request, we return an HTTP/400 with error message
-// Deprecated: This has been replaced by github.com/oapi-codegen/gin-middleware#OapiRequestValidator
-func OapiRequestValidator(swagger *openapi3.T) gin.HandlerFunc {
- return OapiRequestValidatorWithOptions(swagger, nil)
-}
-
-// ErrorHandler is called when there is an error in validation
-// Deprecated: This has been replaced by github.com/oapi-codegen/gin-middleware#ErrorHandler
-type ErrorHandler func(c *gin.Context, message string, statusCode int)
-
-// MultiErrorHandler is called when oapi returns a MultiError type
-// Deprecated: This has been replaced by github.com/oapi-codegen/gin-middleware#MultiErrorHandler
-type MultiErrorHandler func(openapi3.MultiError) error
-
-// Options to customize request validation. These are passed through to
-// openapi3filter.
-// Deprecated: This has been replaced by github.com/oapi-codegen/gin-middleware#Options
-type Options struct {
- ErrorHandler ErrorHandler
- Options openapi3filter.Options
- ParamDecoder openapi3filter.ContentParameterDecoder
- UserData interface{}
- MultiErrorHandler MultiErrorHandler
- // SilenceServersWarning allows silencing a warning for https://github.com/deepmap/oapi-codegen/issues/882 that reports when an OpenAPI spec has `spec.Servers != nil`
- SilenceServersWarning bool
-}
-
-// OapiRequestValidatorWithOptions creates a validator from a swagger object, with validation options
-// Deprecated: This has been replaced by github.com/oapi-codegen/gin-middleware#OapiRequestValidatorWithOptions
-func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) gin.HandlerFunc {
- if swagger.Servers != nil && (options == nil || !options.SilenceServersWarning) {
- log.Println("WARN: OapiRequestValidatorWithOptions called with an OpenAPI spec that has `Servers` set. This may lead to an HTTP 400 with `no matching operation was found` when sending a valid request, as the validator performs `Host` header validation. If you're expecting `Host` header validation, you can silence this warning by setting `Options.SilenceServersWarning = true`. See https://github.com/deepmap/oapi-codegen/issues/882 for more information.")
- }
-
- router, err := gorillamux.NewRouter(swagger)
- if err != nil {
- panic(err)
- }
- return func(c *gin.Context) {
- err := ValidateRequestFromContext(c, router, options)
- if err != nil {
- // using errors.Is did not work
- if options != nil && options.ErrorHandler != nil && err.Error() == routers.ErrPathNotFound.Error() {
- options.ErrorHandler(c, err.Error(), http.StatusNotFound)
- // in case the handler didn't internally call Abort, stop the chain
- c.Abort()
- } else if options != nil && options.ErrorHandler != nil {
- options.ErrorHandler(c, err.Error(), http.StatusBadRequest)
- // in case the handler didn't internally call Abort, stop the chain
- c.Abort()
- } else if err.Error() == routers.ErrPathNotFound.Error() {
- // note: i am not sure if this is the best way to handle this
- c.AbortWithStatusJSON(http.StatusNotFound, gin.H{"error": err.Error()})
- } else {
- // note: i am not sure if this is the best way to handle this
- c.AbortWithStatusJSON(http.StatusBadRequest, gin.H{"error": err.Error()})
- }
- }
- c.Next()
- }
-}
-
-// ValidateRequestFromContext is called from the middleware above and actually does the work
-// of validating a request.
-// Deprecated: This has been replaced by github.com/oapi-codegen/gin-middleware#ValidateRequestFromContext
-func ValidateRequestFromContext(c *gin.Context, router routers.Router, options *Options) error {
- req := c.Request
- route, pathParams, err := router.FindRoute(req)
-
- // We failed to find a matching route for the request.
- if err != nil {
- switch e := err.(type) {
- case *routers.RouteError:
- // We've got a bad request, the path requested doesn't match
- // either server, or path, or something.
- return errors.New(e.Reason)
- default:
- // This should never happen today, but if our upstream code changes,
- // we don't want to crash the server, so handle the unexpected error.
- return fmt.Errorf("error validating route: %s", err.Error())
- }
- }
-
- validationInput := &openapi3filter.RequestValidationInput{
- Request: req,
- PathParams: pathParams,
- Route: route,
- }
-
- // Pass the gin context into the request validator, so that any callbacks
- // which it invokes make it available.
- requestContext := context.WithValue(context.Background(), GinContextKey, c) //nolint:staticcheck
-
- if options != nil {
- validationInput.Options = &options.Options
- validationInput.ParamDecoder = options.ParamDecoder
- requestContext = context.WithValue(requestContext, UserDataKey, options.UserData) //nolint:staticcheck
- }
-
- err = openapi3filter.ValidateRequest(requestContext, validationInput)
- if err != nil {
- me := openapi3.MultiError{}
- if errors.As(err, &me) {
- errFunc := getMultiErrorHandlerFromOptions(options)
- return errFunc(me)
- }
-
- switch e := err.(type) {
- case *openapi3filter.RequestError:
- // We've got a bad request
- // Split up the verbose error by lines and return the first one
- // openapi errors seem to be multi-line with a decent message on the first
- errorLines := strings.Split(e.Error(), "\n")
- return fmt.Errorf("error in openapi3filter.RequestError: %s", errorLines[0])
- case *openapi3filter.SecurityRequirementsError:
- return fmt.Errorf("error in openapi3filter.SecurityRequirementsError: %s", e.Error())
- default:
- // This should never happen today, but if our upstream code changes,
- // we don't want to crash the server, so handle the unexpected error.
- return fmt.Errorf("error validating request: %w", err)
- }
- }
- return nil
-}
-
-// GetGinContext gets the echo context from within requests. It returns
-// nil if not found or wrong type.
-// Deprecated: This has been replaced by github.com/oapi-codegen/gin-middleware#GetGinContext
-func GetGinContext(c context.Context) *gin.Context {
- iface := c.Value(GinContextKey)
- if iface == nil {
- return nil
- }
- ginCtx, ok := iface.(*gin.Context)
- if !ok {
- return nil
- }
- return ginCtx
-}
-
-func GetUserData(c context.Context) interface{} {
- return c.Value(UserDataKey)
-}
-
-// attempt to get the MultiErrorHandler from the options. If it is not set,
-// return a default handler
-// Deprecated: This has been replaced by github.com/oapi-codegen/gin-middleware#getMultiErrorHandlerFromOptions
-func getMultiErrorHandlerFromOptions(options *Options) MultiErrorHandler {
- if options == nil {
- return defaultMultiErrorHandler
- }
-
- if options.MultiErrorHandler == nil {
- return defaultMultiErrorHandler
- }
-
- return options.MultiErrorHandler
-}
-
-// defaultMultiErrorHandler returns a StatusBadRequest (400) and a list
-// of all of the errors. This method is called if there are no other
-// methods defined on the options.
-// Deprecated: This has been replaced by github.com/oapi-codegen/gin-middleware#defaultMultiErrorHandler
-func defaultMultiErrorHandler(me openapi3.MultiError) error {
- return fmt.Errorf("multiple errors encountered: %s", me)
-}
diff --git a/pkg/gin-middleware/oapi_validate_test.go b/pkg/gin-middleware/oapi_validate_test.go
deleted file mode 100644
index 4781d34fd7..0000000000
--- a/pkg/gin-middleware/oapi_validate_test.go
+++ /dev/null
@@ -1,414 +0,0 @@
-// Copyright 2021 DeepMap, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package middleware
-
-import (
- "context"
- _ "embed"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/deepmap/oapi-codegen/pkg/testutil"
- "github.com/getkin/kin-openapi/openapi3"
- "github.com/getkin/kin-openapi/openapi3filter"
- "github.com/gin-gonic/gin"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-//go:embed test_spec.yaml
-var testSchema []byte
-
-func doGet(t *testing.T, handler http.Handler, rawURL string) *httptest.ResponseRecorder {
- u, err := url.Parse(rawURL)
- if err != nil {
- t.Fatalf("Invalid url: %s", rawURL)
- }
-
- response := testutil.NewRequest().Get(u.RequestURI()).WithHost(u.Host).WithAcceptJson().GoWithHTTPHandler(t, handler)
- return response.Recorder
-}
-
-func doPost(t *testing.T, handler http.Handler, rawURL string, jsonBody interface{}) *httptest.ResponseRecorder {
- u, err := url.Parse(rawURL)
- if err != nil {
- t.Fatalf("Invalid url: %s", rawURL)
- }
-
- response := testutil.NewRequest().Post(u.RequestURI()).WithHost(u.Host).WithJsonBody(jsonBody).GoWithHTTPHandler(t, handler)
- return response.Recorder
-}
-
-func TestOapiRequestValidator(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- // Create a new echo router
- g := gin.New()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- ErrorHandler: func(c *gin.Context, message string, statusCode int) {
- c.String(statusCode, "test: "+message)
- },
- Options: openapi3filter.Options{
- AuthenticationFunc: func(c context.Context, input *openapi3filter.AuthenticationInput) error {
- // The gin context should be propagated into here.
- gCtx := GetGinContext(c)
- assert.NotNil(t, gCtx)
- // As should user data
- assert.EqualValues(t, "hi!", GetUserData(c))
-
- for _, s := range input.Scopes {
- if s == "someScope" {
- return nil
- }
- if s == "unauthorized" {
- return errors.New("unauthorized")
- }
- }
- return errors.New("forbidden")
- },
- },
- UserData: "hi!",
- }
-
- // Install our OpenApi based request validator
- g.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- g.GET("/resource", func(c *gin.Context) {
- called = true
- })
- // Let's send the request to the wrong server, this should return 404
- {
- rec := doGet(t, g, "http://not.deepmap.ai/resource")
- assert.Equal(t, http.StatusNotFound, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- }
-
- // Let's send a good request, it should pass
- {
- rec := doGet(t, g, "http://deepmap.ai/resource")
- assert.Equal(t, http.StatusOK, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Send an out-of-spec parameter
- {
- rec := doGet(t, g, "http://deepmap.ai/resource?id=500")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Send a bad parameter type
- {
- rec := doGet(t, g, "http://deepmap.ai/resource?id=foo")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Add a handler for the POST message
- g.POST("/resource", func(c *gin.Context) {
- called = true
- c.AbortWithStatus(http.StatusNoContent)
- })
-
- called = false
- // Send a good request body
- {
- body := struct {
- Name string `json:"name"`
- }{
- Name: "Marcin",
- }
- rec := doPost(t, g, "http://deepmap.ai/resource", body)
- assert.Equal(t, http.StatusNoContent, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Send a malformed body
- {
- body := struct {
- Name int `json:"name"`
- }{
- Name: 7,
- }
- rec := doPost(t, g, "http://deepmap.ai/resource", body)
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- g.GET("/protected_resource", func(c *gin.Context) {
- called = true
- c.AbortWithStatus(http.StatusNoContent)
- })
-
- // Call a protected function to which we have access
- {
- rec := doGet(t, g, "http://deepmap.ai/protected_resource")
- assert.Equal(t, http.StatusNoContent, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- g.GET("/protected_resource2", func(c *gin.Context) {
- called = true
- c.AbortWithStatus(http.StatusNoContent)
- })
- // Call a protected function to which we don't have access
- {
- rec := doGet(t, g, "http://deepmap.ai/protected_resource2")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- g.GET("/protected_resource_401", func(c *gin.Context) {
- called = true
- c.AbortWithStatus(http.StatusNoContent)
- })
- // Call a protected function without credentials
- {
- rec := doGet(t, g, "http://deepmap.ai/protected_resource_401")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- assert.Equal(t, "test: error in openapi3filter.SecurityRequirementsError: security requirements failed: unauthorized", rec.Body.String())
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-}
-
-func TestOapiRequestValidatorWithOptionsMultiError(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- g := gin.New()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- Options: openapi3filter.Options{
- ExcludeRequestBody: false,
- ExcludeResponseBody: false,
- IncludeResponseStatus: true,
- MultiError: true,
- },
- }
-
- // register middleware
- g.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- g.GET("/multiparamresource", func(c *gin.Context) {
- called = true
- })
-
- // Let's send a good request, it should pass
- {
- rec := doGet(t, g, "http://deepmap.ai/multiparamresource?id=50&id2=50")
- assert.Equal(t, http.StatusOK, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Let's send a request with a missing parameter, it should return
- // a bad status
- {
- rec := doGet(t, g, "http://deepmap.ai/multiparamresource?id=50")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "multiple errors encountered")
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 2 missing parameters, it should return
- // a bad status
- {
- rec := doGet(t, g, "http://deepmap.ai/multiparamresource")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "multiple errors encountered")
- assert.Contains(t, string(body), "parameter \\\"id\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 1 missing parameter, and another outside
- // or the parameters. It should return a bad status
- {
- rec := doGet(t, g, "http://deepmap.ai/multiparamresource?id=500")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "multiple errors encountered")
- assert.Contains(t, string(body), "parameter \\\"id\\\"")
- assert.Contains(t, string(body), "number must be at most 100")
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a parameters that do not meet spec. It should
- // return a bad status
- {
- rec := doGet(t, g, "http://deepmap.ai/multiparamresource?id=abc&id2=1")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "multiple errors encountered")
- assert.Contains(t, string(body), "parameter \\\"id\\\"")
- assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax")
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "number must be at least 10")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-}
-
-func TestOapiRequestValidatorWithOptionsMultiErrorAndCustomHandler(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- g := gin.New()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- Options: openapi3filter.Options{
- ExcludeRequestBody: false,
- ExcludeResponseBody: false,
- IncludeResponseStatus: true,
- MultiError: true,
- },
- MultiErrorHandler: func(me openapi3.MultiError) error {
- return fmt.Errorf("Bad stuff - %s", me.Error())
- },
- }
-
- // register middleware
- g.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- g.GET("/multiparamresource", func(c *gin.Context) {
- called = true
- })
-
- // Let's send a good request, it should pass
- {
- rec := doGet(t, g, "http://deepmap.ai/multiparamresource?id=50&id2=50")
- assert.Equal(t, http.StatusOK, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Let's send a request with a missing parameter, it should return
- // a bad status
- {
- rec := doGet(t, g, "http://deepmap.ai/multiparamresource?id=50")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "Bad stuff")
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 2 missing parameters, it should return
- // a bad status
- {
- rec := doGet(t, g, "http://deepmap.ai/multiparamresource")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "Bad stuff")
- assert.Contains(t, string(body), "parameter \\\"id\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 1 missing parameter, and another outside
- // or the parameters. It should return a bad status
- {
- rec := doGet(t, g, "http://deepmap.ai/multiparamresource?id=500")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "Bad stuff")
- assert.Contains(t, string(body), "parameter \\\"id\\\"")
- assert.Contains(t, string(body), "number must be at most 100")
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a parameters that do not meet spec. It should
- // return a bad status
- {
- rec := doGet(t, g, "http://deepmap.ai/multiparamresource?id=abc&id2=1")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "Bad stuff")
- assert.Contains(t, string(body), "parameter \\\"id\\\"")
- assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax")
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "number must be at least 10")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-}
diff --git a/pkg/gin-middleware/test_spec.yaml b/pkg/gin-middleware/test_spec.yaml
deleted file mode 100644
index 6e0a2415d2..0000000000
--- a/pkg/gin-middleware/test_spec.yaml
+++ /dev/null
@@ -1,103 +0,0 @@
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: TestServer
-servers:
- - url: http://deepmap.ai/
-paths:
- /resource:
- get:
- operationId: getResource
- parameters:
- - name: id
- in: query
- schema:
- type: integer
- minimum: 10
- maximum: 100
- responses:
- '200':
- description: success
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- id:
- type: integer
- post:
- operationId: createResource
- responses:
- '204':
- description: No content
- requestBody:
- required: true
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- /protected_resource:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - someScope
- responses:
- '204':
- description: no content
- /protected_resource2:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - otherScope
- responses:
- '204':
- description: no content
- /protected_resource_401:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - unauthorized
- responses:
- '401':
- description: no content
- /multiparamresource:
- get:
- operationId: getResource
- parameters:
- - name: id
- in: query
- required: true
- schema:
- type: integer
- minimum: 10
- maximum: 100
- - name: id2
- required: true
- in: query
- schema:
- type: integer
- minimum: 10
- maximum: 100
- responses:
- '200':
- description: success
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- id:
- type: integer
-components:
- securitySchemes:
- BearerAuth:
- type: http
- scheme: bearer
- bearerFormat: JWT
diff --git a/pkg/iris-middleware/oapi_validate.go b/pkg/iris-middleware/oapi_validate.go
deleted file mode 100644
index e41a9b2af6..0000000000
--- a/pkg/iris-middleware/oapi_validate.go
+++ /dev/null
@@ -1,195 +0,0 @@
-package middleware
-
-import (
- "context"
- "errors"
- "fmt"
- "net/http"
- "os"
- "strings"
-
- "github.com/getkin/kin-openapi/openapi3"
- "github.com/getkin/kin-openapi/openapi3filter"
- "github.com/getkin/kin-openapi/routers"
- "github.com/getkin/kin-openapi/routers/gorillamux"
- "github.com/kataras/iris/v12"
-)
-
-const (
- IrisContextKey = "oapi-codegen/iris-context"
- UserDataKey = "oapi-codegen/user-data"
-)
-
-// OapiValidatorFromYamlFile creates a validator middleware from a YAML file path
-// Deprecated: This has been replaced by github.com/oapi-codegen/iris-middleware#OapiValidatorFromYamlFile
-func OapiValidatorFromYamlFile(path string) (iris.Handler, error) {
- data, err := os.ReadFile(path)
- if err != nil {
- return nil, fmt.Errorf("error reading %s: %w", path, err)
- }
-
- swagger, err := openapi3.NewLoader().LoadFromData(data)
- if err != nil {
- return nil, fmt.Errorf("error parsing %s as Swagger YAML: %w",
- path, err)
- }
-
- return OapiRequestValidator(swagger), nil
-}
-
-// OapiRequestValidator is a iris middleware function which validates incoming HTTP requests
-// to make sure that they conform to the given OAPI 3.0 specification. When
-// OAPI validation fails on the request, we return an HTTP/400 with error message
-// Deprecated: This has been replaced by github.com/oapi-codegen/iris-middleware#OapiRequestValidator
-func OapiRequestValidator(swagger *openapi3.T) iris.Handler {
- return OapiRequestValidatorWithOptions(swagger, nil)
-}
-
-// ErrorHandler is called when there is an error in validation
-// Deprecated: This has been replaced by github.com/oapi-codegen/iris-middleware#ErrorHandler
-type ErrorHandler func(ctx iris.Context, message string, statusCode int)
-
-// MultiErrorHandler is called when oapi returns a MultiError type
-// Deprecated: This has been replaced by github.com/oapi-codegen/iris-middleware#MultiErrorHandler
-type MultiErrorHandler func(openapi3.MultiError) error
-
-// Options to customize request validation. These are passed through to
-// openapi3filter.
-// Deprecated: This has been replaced by github.com/oapi-codegen/iris-middleware#Options
-type Options struct {
- Options openapi3filter.Options
- ErrorHandler ErrorHandler
- ParamDecoder openapi3filter.ContentParameterDecoder
- UserData interface{}
- MultiErrorHandler MultiErrorHandler
- // SilenceServersWarning allows silencing a warning for https://github.com/deepmap/oapi-codegen/issues/882 that reports when an OpenAPI spec has `spec.Servers != nil`
- SilenceServersWarning bool
-}
-
-// OapiRequestValidatorWithOptions creates a validator from a swagger object, with validation options
-// Deprecated: This has been replaced by github.com/oapi-codegen/iris-middleware#OapiRequestValidatorWithOptions
-func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) iris.Handler {
- router, err := gorillamux.NewRouter(swagger)
- if err != nil {
- panic(err)
- }
-
- return func(ctx iris.Context) {
- err := ValidateRequestFromContext(ctx, router, options)
- if err != nil {
- if options != nil && options.ErrorHandler != nil {
- options.ErrorHandler(ctx, err.Error(), http.StatusBadRequest)
- } else {
- ctx.StopWithError(http.StatusBadRequest, err)
- }
- }
- ctx.Next()
- }
-}
-
-// ValidateRequestFromContext is called from the middleware above and actually does the work
-// of validating a request.
-// Deprecated: This has been replaced by github.com/oapi-codegen/iris-middleware#ValidateRequestFromContext
-func ValidateRequestFromContext(ctx iris.Context, router routers.Router, options *Options) error {
- req := ctx.Request()
- route, pathParams, err := router.FindRoute(req)
- // We failed to find a matching route for the request.
- if err != nil {
- switch e := err.(type) {
- case *routers.RouteError:
- // We've got a bad request, the path requested doesn't match
- // either server, or path, or something.
- return errors.New(e.Reason)
- default:
- // This should never happen today, but if our upstream code changes,
- // we don't want to crash the server, so handle the unexpected error.
- return fmt.Errorf("error validating route: %w", err)
- }
- }
-
- // Validate request
- requestValidationInput := &openapi3filter.RequestValidationInput{
- Request: req,
- PathParams: pathParams,
- Route: route,
- }
-
- // Pass the iris context into the request validator, so that any callbacks
- // which it invokes make it available.
- requestContext := context.WithValue(context.Background(), IrisContextKey, ctx) //nolint:staticcheck
-
- if options != nil {
- requestValidationInput.Options = &options.Options
- requestValidationInput.ParamDecoder = options.ParamDecoder
- requestContext = context.WithValue(requestContext, UserDataKey, options.UserData) //nolint:staticcheck
- }
-
- err = openapi3filter.ValidateRequest(requestContext, requestValidationInput)
- if err != nil {
- me := openapi3.MultiError{}
- if errors.As(err, &me) {
- errFunc := getMultiErrorHandlerFromOptions(options)
- return errFunc(me)
- }
-
- switch e := err.(type) {
- case *openapi3filter.RequestError:
- // We've got a bad request
- // Split up the verbose error by lines and return the first one
- // openapi errors seem to be multi-line with a decent message on the first
- errorLines := strings.Split(e.Error(), "\n")
- return fmt.Errorf("error in openapi3filter.RequestError: %s", errorLines[0])
- case *openapi3filter.SecurityRequirementsError:
- return fmt.Errorf("error in openapi3filter.SecurityRequirementsError: %s", e.Error())
- default:
- // This should never happen today, but if our upstream code changes,
- // we don't want to crash the server, so handle the unexpected error.
- return fmt.Errorf("error validating request: %w", err)
- }
- }
- return nil
-}
-
-// GetIrisContext gets the iris context from within requests. It returns
-// nil if not found or wrong type.
-// Deprecated: This has been replaced by github.com/oapi-codegen/iris-middleware#GetIrisContext
-func GetIrisContext(ctx context.Context) iris.Context {
- iface := ctx.Value(IrisContextKey)
- if iface == nil {
- return nil
- }
-
- iCtx, ok := iface.(iris.Context)
- if ok {
- return iCtx
- }
- return nil
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/iris-middleware#GetUserData
-func GetUserData(ctx context.Context) interface{} {
- return ctx.Value(UserDataKey)
-}
-
-// getMultiErrorHandlerFromOptions attempts to get the MultiErrorHandler from the options. If it is not set,
-// return a default handler
-// Deprecated: This has been replaced by github.com/oapi-codegen/iris-middleware#getMultiErrorHandlerFromOptions
-func getMultiErrorHandlerFromOptions(options *Options) MultiErrorHandler {
- if options == nil {
- return defaultMultiErrorHandler
- }
-
- if options.MultiErrorHandler == nil {
- return defaultMultiErrorHandler
- }
-
- return options.MultiErrorHandler
-}
-
-// defaultMultiErrorHandler returns a StatusBadRequest (400) and a list
-// of all the errors. This method is called if there are no other
-// methods defined on the options.
-// Deprecated: This has been replaced by github.com/oapi-codegen/iris-middleware#defaultMultiErrorHandler
-func defaultMultiErrorHandler(me openapi3.MultiError) error {
- return fmt.Errorf("multiple errors encountered: %s", me)
-}
diff --git a/pkg/iris-middleware/oapi_validate_test.go b/pkg/iris-middleware/oapi_validate_test.go
deleted file mode 100644
index 4035fb1330..0000000000
--- a/pkg/iris-middleware/oapi_validate_test.go
+++ /dev/null
@@ -1,418 +0,0 @@
-package middleware
-
-import (
- "context"
- _ "embed"
- "errors"
- "fmt"
- "io"
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/deepmap/oapi-codegen/pkg/testutil"
- "github.com/getkin/kin-openapi/openapi3"
- "github.com/getkin/kin-openapi/openapi3filter"
- "github.com/kataras/iris/v12"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-//go:embed test_spec.yaml
-var testSchema []byte
-
-func doGet(t *testing.T, i *iris.Application, rawURL string) *httptest.ResponseRecorder {
- u, err := url.Parse(rawURL)
- if err != nil {
- t.Fatalf("Invalid url: %s", rawURL)
- }
-
- response := testutil.NewRequest().Get(u.RequestURI()).WithHost(u.Host).WithAcceptJson().GoWithHTTPHandler(t, i)
- return response.Recorder
-}
-
-func doPost(t *testing.T, i *iris.Application, rawURL string, jsonBody interface{}) *httptest.ResponseRecorder {
- u, err := url.Parse(rawURL)
- if err != nil {
- t.Fatalf("Invalid url: %s", rawURL)
- }
-
- response := testutil.NewRequest().Post(u.RequestURI()).WithHost(u.Host).WithJsonBody(jsonBody).GoWithHTTPHandler(t, i)
- return response.Recorder
-}
-
-func TestOapiRequestValidator(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- // Create a new iris router
- i := iris.New()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- ErrorHandler: func(ctx iris.Context, message string, statusCode int) {
- ctx.StopWithText(statusCode, "test: "+message)
- },
- Options: openapi3filter.Options{
- AuthenticationFunc: func(ctx context.Context, input *openapi3filter.AuthenticationInput) error {
- // The iris context should be propagated into here.
- iCtx := GetIrisContext(ctx)
- assert.NotNil(t, iCtx)
- // As should user data
- assert.EqualValues(t, "hi!", GetUserData(ctx))
-
- for _, s := range input.Scopes {
- if s == "someScope" {
- return nil
- }
- if s == "unauthorized" {
- return errors.New("unauthorized")
- }
- }
- return errors.New("forbidden")
- },
- },
- UserData: "hi!",
- }
-
- // Install our OpenApi based request validator
- i.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- i.Get("/resource", func(ctx iris.Context) {
- called = true
- })
-
- // Add a handler for the POST message
- i.Post("/resource", func(ctx iris.Context) {
- called = true
- ctx.StatusCode(http.StatusNoContent)
- })
-
- i.Get("/protected_resource", func(ctx iris.Context) {
- called = true
- ctx.StatusCode(http.StatusNoContent)
- })
-
- i.Get("/protected_resource2", func(ctx iris.Context) {
- called = true
- ctx.StatusCode(http.StatusNoContent)
- })
-
- i.Get("/protected_resource_401", func(ctx iris.Context) {
- called = true
- ctx.StatusCode(http.StatusNoContent)
- })
-
- if err := i.Build(); err != nil {
- t.Fatalf("Error building iris: %s", err)
- }
-
- // Let's send the request to the wrong server, this should fail validation
- {
- res := doGet(t, i, "https://not.deepmap.ai/resource")
- assert.Equal(t, http.StatusBadRequest, res.Code)
- assert.False(t, called, "Handler should not have been called")
- }
-
- // Let's send a good request, it should pass
- {
- res := doGet(t, i, "https://deepmap.ai/resource")
- assert.Equal(t, http.StatusOK, res.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Send an out-of-spec parameter
- {
- res := doGet(t, i, "https://deepmap.ai/resource?id=500")
- assert.Equal(t, http.StatusBadRequest, res.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Send a bad parameter type
- {
- res := doGet(t, i, "https://deepmap.ai/resource?id=foo")
- assert.Equal(t, http.StatusBadRequest, res.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- called = false
- // Send a good request body
- {
- body := struct {
- Name string `json:"name"`
- }{
- Name: "Marcin",
- }
- res := doPost(t, i, "https://deepmap.ai/resource", body)
- assert.Equal(t, http.StatusNoContent, res.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Send a malformed body
- {
- body := struct {
- Name int `json:"name"`
- }{
- Name: 7,
- }
- res := doPost(t, i, "https://deepmap.ai/resource", body)
- assert.Equal(t, http.StatusBadRequest, res.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Call a protected function to which we have access
- {
- res := doGet(t, i, "https://deepmap.ai/protected_resource")
- assert.Equal(t, http.StatusNoContent, res.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Call a protected function to which we don't have access
- {
- res := doGet(t, i, "https://deepmap.ai/protected_resource2")
- assert.Equal(t, http.StatusBadRequest, res.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Call a protected function without credentials
- {
- res := doGet(t, i, "https://deepmap.ai/protected_resource_401")
- assert.Equal(t, http.StatusBadRequest, res.Code)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Equal(t, "test: error in openapi3filter.SecurityRequirementsError: security requirements failed: unauthorized", string(body))
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-}
-
-func TestOapiRequestValidatorWithOptionsMultiError(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- i := iris.New()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- Options: openapi3filter.Options{
- ExcludeRequestBody: false,
- ExcludeResponseBody: false,
- IncludeResponseStatus: true,
- MultiError: true,
- },
- }
-
- // register middleware
- i.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- i.Get("/multiparamresource", func(ctx iris.Context) {
- called = true
- })
-
- if err := i.Build(); err != nil {
- t.Fatalf("Error building iris: %s", err)
- }
-
- // Let's send a good request, it should pass
- {
- res := doGet(t, i, "https://deepmap.ai/multiparamresource?id=50&id2=50")
- assert.Equal(t, http.StatusOK, res.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Let's send a request with a missing parameter, it should return
- // a bad status
- {
- res := doGet(t, i, "https://deepmap.ai/multiparamresource?id=50")
- assert.Equal(t, http.StatusBadRequest, res.Code)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "multiple errors encountered")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 2 missing parameters, it should return
- // a bad status
- {
- res := doGet(t, i, "https://deepmap.ai/multiparamresource")
- assert.Equal(t, http.StatusBadRequest, res.Code)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "multiple errors encountered")
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "value is required but missing")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 1 missing parameter, and another outside
- // or the parameters. It should return a bad status
- {
- res := doGet(t, i, "https://deepmap.ai/multiparamresource?id=500")
- assert.Equal(t, http.StatusBadRequest, res.Code)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "multiple errors encountered")
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "number must be at most 100")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a parameters that do not meet spec. It should
- // return a bad status
- {
- res := doGet(t, i, "https://deepmap.ai/multiparamresource?id=abc&id2=1")
- assert.Equal(t, http.StatusBadRequest, res.Code)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "multiple errors encountered")
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "number must be at least 10")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-}
-
-func TestOapiRequestValidatorWithOptionsMultiErrorAndCustomHandler(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- i := iris.New()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- Options: openapi3filter.Options{
- ExcludeRequestBody: false,
- ExcludeResponseBody: false,
- IncludeResponseStatus: true,
- MultiError: true,
- },
- MultiErrorHandler: func(me openapi3.MultiError) error {
- return fmt.Errorf("Bad stuff - %s", me.Error())
- },
- }
-
- // register middleware
- i.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- i.Get("/multiparamresource", func(ctx iris.Context) {
- called = true
- })
-
- if err := i.Build(); err != nil {
- t.Fatalf("Error building iris: %s", err)
- }
-
- // Let's send a good request, it should pass
- {
- res := doGet(t, i, "https://deepmap.ai/multiparamresource?id=50&id2=50")
- assert.Equal(t, http.StatusOK, res.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Let's send a request with a missing parameter, it should return
- // a bad status
- {
- res := doGet(t, i, "https://deepmap.ai/multiparamresource?id=50")
- assert.Equal(t, http.StatusBadRequest, res.Code)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "Bad stuff")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 2 missing parameters, it should return
- // a bad status
- {
- res := doGet(t, i, "https://deepmap.ai/multiparamresource")
- assert.Equal(t, http.StatusBadRequest, res.Code)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "Bad stuff")
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "value is required but missing")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 1 missing parameter, and another outside
- // or the parameters. It should return a bad status
- {
- res := doGet(t, i, "https://deepmap.ai/multiparamresource?id=500")
- assert.Equal(t, http.StatusBadRequest, res.Code)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "Bad stuff")
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "number must be at most 100")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a parameters that do not meet spec. It should
- // return a bad status
- {
- res := doGet(t, i, "https://deepmap.ai/multiparamresource?id=abc&id2=1")
- assert.Equal(t, http.StatusBadRequest, res.Code)
- body, err := io.ReadAll(res.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "Bad stuff")
- assert.Contains(t, string(body), "parameter \"id\"")
- assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax")
- assert.Contains(t, string(body), "parameter \"id2\"")
- assert.Contains(t, string(body), "number must be at least 10")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-}
diff --git a/pkg/iris-middleware/test_spec.yaml b/pkg/iris-middleware/test_spec.yaml
deleted file mode 100644
index 1f847d756a..0000000000
--- a/pkg/iris-middleware/test_spec.yaml
+++ /dev/null
@@ -1,103 +0,0 @@
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: TestServer
-servers:
- - url: http://deepmap.ai
-paths:
- /resource:
- get:
- operationId: getResource
- parameters:
- - name: id
- in: query
- schema:
- type: integer
- minimum: 10
- maximum: 100
- responses:
- '200':
- description: success
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- id:
- type: integer
- post:
- operationId: createResource
- responses:
- '204':
- description: No content
- requestBody:
- required: true
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- /protected_resource:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - someScope
- responses:
- '204':
- description: no content
- /protected_resource2:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - otherScope
- responses:
- '204':
- description: no content
- /protected_resource_401:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - unauthorized
- responses:
- '401':
- description: no content
- /multiparamresource:
- get:
- operationId: getResource
- parameters:
- - name: id
- in: query
- required: true
- schema:
- type: integer
- minimum: 10
- maximum: 100
- - name: id2
- required: true
- in: query
- schema:
- type: integer
- minimum: 10
- maximum: 100
- responses:
- '200':
- description: success
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- id:
- type: integer
-components:
- securitySchemes:
- BearerAuth:
- type: http
- scheme: bearer
- bearerFormat: JWT
diff --git a/pkg/middleware/oapi_validate.go b/pkg/middleware/oapi_validate.go
deleted file mode 100644
index 3f93468c9b..0000000000
--- a/pkg/middleware/oapi_validate.go
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright 2019 DeepMap, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package middleware
-
-import (
- "context"
- "errors"
- "fmt"
- "log"
- "net/http"
- "os"
- "strings"
-
- "github.com/getkin/kin-openapi/openapi3"
- "github.com/getkin/kin-openapi/openapi3filter"
- "github.com/getkin/kin-openapi/routers"
- "github.com/getkin/kin-openapi/routers/gorillamux"
- "github.com/labstack/echo/v4"
- echomiddleware "github.com/labstack/echo/v4/middleware"
-)
-
-const (
- EchoContextKey = "oapi-codegen/echo-context"
- UserDataKey = "oapi-codegen/user-data"
-)
-
-// OapiValidatorFromYamlFile is an Echo middleware function which validates incoming HTTP requests
-// to make sure that they conform to the given OAPI 3.0 specification. When
-// OAPI validation fails on the request, we return an HTTP/400.
-// Create validator middleware from a YAML file path
-// Deprecated: This has been replaced by github.com/oapi-codegen/echo-middleware#OapiValidatorFromYamlFile
-func OapiValidatorFromYamlFile(path string) (echo.MiddlewareFunc, error) {
- data, err := os.ReadFile(path)
- if err != nil {
- return nil, fmt.Errorf("error reading %s: %w", path, err)
- }
-
- swagger, err := openapi3.NewLoader().LoadFromData(data)
- if err != nil {
- return nil, fmt.Errorf("error parsing %s as Swagger YAML: %w", path, err)
- }
- return OapiRequestValidator(swagger), nil
-}
-
-// OapiRequestValidator creates a validator from a swagger object.
-// Deprecated: This has been replaced by github.com/oapi-codegen/echo-middleware#OapiRequestValidator
-func OapiRequestValidator(swagger *openapi3.T) echo.MiddlewareFunc {
- return OapiRequestValidatorWithOptions(swagger, nil)
-}
-
-// ErrorHandler is called when there is an error in validation
-// Deprecated: This has been replaced by github.com/oapi-codegen/echo-middleware#ErrorHandler
-type ErrorHandler func(c echo.Context, err *echo.HTTPError) error
-
-// MultiErrorHandler is called when oapi returns a MultiError type
-// Deprecated: This has been replaced by github.com/oapi-codegen/echo-middleware#MultiErrorHandler
-type MultiErrorHandler func(openapi3.MultiError) *echo.HTTPError
-
-// Options to customize request validation. These are passed through to
-// openapi3filter.
-// Deprecated: This has been replaced by github.com/oapi-codegen/echo-middleware#Options
-type Options struct {
- ErrorHandler ErrorHandler
- Options openapi3filter.Options
- ParamDecoder openapi3filter.ContentParameterDecoder
- UserData interface{}
- Skipper echomiddleware.Skipper
- MultiErrorHandler MultiErrorHandler
- // SilenceServersWarning allows silencing a warning for https://github.com/deepmap/oapi-codegen/issues/882 that reports when an OpenAPI spec has `spec.Servers != nil`
- SilenceServersWarning bool
-}
-
-// OapiRequestValidatorWithOptions creates a validator from a swagger object, with validation options
-// Deprecated: This has been replaced by github.com/oapi-codegen/echo-middleware#OapiRequestValidatorWithOptions
-func OapiRequestValidatorWithOptions(swagger *openapi3.T, options *Options) echo.MiddlewareFunc {
- if swagger.Servers != nil && (options == nil || !options.SilenceServersWarning) {
- log.Println("WARN: OapiRequestValidatorWithOptions called with an OpenAPI spec that has `Servers` set. This may lead to an HTTP 400 with `no matching operation was found` when sending a valid request, as the validator performs `Host` header validation. If you're expecting `Host` header validation, you can silence this warning by setting `Options.SilenceServersWarning = true`. See https://github.com/deepmap/oapi-codegen/issues/882 for more information.")
- }
-
- router, err := gorillamux.NewRouter(swagger)
- if err != nil {
- panic(err)
- }
-
- skipper := getSkipperFromOptions(options)
- return func(next echo.HandlerFunc) echo.HandlerFunc {
- return func(c echo.Context) error {
- if skipper(c) {
- return next(c)
- }
-
- err := ValidateRequestFromContext(c, router, options)
- if err != nil {
- if options != nil && options.ErrorHandler != nil {
- return options.ErrorHandler(c, err)
- }
- return err
- }
- return next(c)
- }
- }
-}
-
-// ValidateRequestFromContext is called from the middleware above and actually does the work
-// of validating a request.
-// Deprecated: This has been replaced by github.com/oapi-codegen/echo-middleware#ValidateRequestFromContext
-func ValidateRequestFromContext(ctx echo.Context, router routers.Router, options *Options) *echo.HTTPError {
- req := ctx.Request()
- route, pathParams, err := router.FindRoute(req)
-
- // We failed to find a matching route for the request.
- if err != nil {
- switch e := err.(type) {
- case *routers.RouteError:
- // We've got a bad request, the path requested doesn't match
- // either server, or path, or something.
- return echo.NewHTTPError(http.StatusNotFound, e.Reason)
- default:
- // This should never happen today, but if our upstream code changes,
- // we don't want to crash the server, so handle the unexpected error.
- return echo.NewHTTPError(http.StatusInternalServerError,
- fmt.Sprintf("error validating route: %s", err.Error()))
- }
- }
-
- validationInput := &openapi3filter.RequestValidationInput{
- Request: req,
- PathParams: pathParams,
- Route: route,
- }
-
- // Pass the Echo context into the request validator, so that any callbacks
- // which it invokes make it available.
- requestContext := context.WithValue(context.Background(), EchoContextKey, ctx) //nolint:staticcheck
-
- if options != nil {
- validationInput.Options = &options.Options
- validationInput.ParamDecoder = options.ParamDecoder
- requestContext = context.WithValue(requestContext, UserDataKey, options.UserData) //nolint:staticcheck
- }
-
- err = openapi3filter.ValidateRequest(requestContext, validationInput)
- if err != nil {
- me := openapi3.MultiError{}
- if errors.As(err, &me) {
- errFunc := getMultiErrorHandlerFromOptions(options)
- return errFunc(me)
- }
-
- switch e := err.(type) {
- case *openapi3filter.RequestError:
- // We've got a bad request
- // Split up the verbose error by lines and return the first one
- // openapi errors seem to be multi-line with a decent message on the first
- errorLines := strings.Split(e.Error(), "\n")
- return &echo.HTTPError{
- Code: http.StatusBadRequest,
- Message: errorLines[0],
- Internal: err,
- }
- case *openapi3filter.SecurityRequirementsError:
- for _, err := range e.Errors {
- httpErr, ok := err.(*echo.HTTPError)
- if ok {
- return httpErr
- }
- }
- return &echo.HTTPError{
- Code: http.StatusForbidden,
- Message: e.Error(),
- Internal: err,
- }
- default:
- // This should never happen today, but if our upstream code changes,
- // we don't want to crash the server, so handle the unexpected error.
- return &echo.HTTPError{
- Code: http.StatusInternalServerError,
- Message: fmt.Sprintf("error validating request: %s", err),
- Internal: err,
- }
- }
- }
- return nil
-}
-
-// GetEchoContext gets the echo context from within requests. It returns
-// nil if not found or wrong type.
-// Deprecated: This has been replaced by github.com/oapi-codegen/echo-middleware#GetEchoContext
-func GetEchoContext(c context.Context) echo.Context {
- iface := c.Value(EchoContextKey)
- if iface == nil {
- return nil
- }
- eCtx, ok := iface.(echo.Context)
- if !ok {
- return nil
- }
- return eCtx
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/echo-middleware#GetUserData
-func GetUserData(c context.Context) interface{} {
- return c.Value(UserDataKey)
-}
-
-// attempt to get the skipper from the options whether it is set or not
-// Deprecated: This has been replaced by github.com/oapi-codegen/echo-middleware#getSkipperFromOptions
-func getSkipperFromOptions(options *Options) echomiddleware.Skipper {
- if options == nil {
- return echomiddleware.DefaultSkipper
- }
-
- if options.Skipper == nil {
- return echomiddleware.DefaultSkipper
- }
-
- return options.Skipper
-}
-
-// attempt to get the MultiErrorHandler from the options. If it is not set,
-// return a default handler
-// Deprecated: This has been replaced by github.com/oapi-codegen/echo-middleware#getMultiErrorHandlerFromOptions
-func getMultiErrorHandlerFromOptions(options *Options) MultiErrorHandler {
- if options == nil {
- return defaultMultiErrorHandler
- }
-
- if options.MultiErrorHandler == nil {
- return defaultMultiErrorHandler
- }
-
- return options.MultiErrorHandler
-}
-
-// defaultMultiErrorHandler returns a StatusBadRequest (400) and a list
-// of all of the errors. This method is called if there are no other
-// methods defined on the options.
-// Deprecated: This has been replaced by github.com/oapi-codegen/echo-middleware#defaultMultiErrorHandler
-func defaultMultiErrorHandler(me openapi3.MultiError) *echo.HTTPError {
- return &echo.HTTPError{
- Code: http.StatusBadRequest,
- Message: me.Error(),
- Internal: me,
- }
-}
diff --git a/pkg/middleware/oapi_validate_test.go b/pkg/middleware/oapi_validate_test.go
deleted file mode 100644
index fe7237e3be..0000000000
--- a/pkg/middleware/oapi_validate_test.go
+++ /dev/null
@@ -1,430 +0,0 @@
-// Copyright 2019 DeepMap, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-package middleware
-
-import (
- "context"
- _ "embed"
- "errors"
- "io"
- "net/http"
- "net/http/httptest"
- "net/url"
- "testing"
-
- "github.com/deepmap/oapi-codegen/pkg/testutil"
- "github.com/getkin/kin-openapi/openapi3"
- "github.com/getkin/kin-openapi/openapi3filter"
- "github.com/labstack/echo/v4"
- echomiddleware "github.com/labstack/echo/v4/middleware"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-//go:embed test_spec.yaml
-var testSchema []byte
-
-func doGet(t *testing.T, e *echo.Echo, rawURL string) *httptest.ResponseRecorder {
- u, err := url.Parse(rawURL)
- if err != nil {
- t.Fatalf("Invalid url: %s", rawURL)
- }
-
- response := testutil.NewRequest().Get(u.RequestURI()).WithHost(u.Host).WithAcceptJson().GoWithHTTPHandler(t, e)
- return response.Recorder
-}
-
-func doPost(t *testing.T, e *echo.Echo, rawURL string, jsonBody interface{}) *httptest.ResponseRecorder {
- u, err := url.Parse(rawURL)
- if err != nil {
- t.Fatalf("Invalid url: %s", rawURL)
- }
-
- response := testutil.NewRequest().Post(u.RequestURI()).WithHost(u.Host).WithJsonBody(jsonBody).GoWithHTTPHandler(t, e)
- return response.Recorder
-}
-
-func TestOapiRequestValidator(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- // Create a new echo router
- e := echo.New()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- ErrorHandler: func(c echo.Context, err *echo.HTTPError) error {
- return c.String(err.Code, "test: "+err.Error())
- },
- Options: openapi3filter.Options{
- AuthenticationFunc: func(c context.Context, input *openapi3filter.AuthenticationInput) error {
- // The echo context should be propagated into here.
- eCtx := GetEchoContext(c)
- assert.NotNil(t, eCtx)
- // As should user data
- assert.EqualValues(t, "hi!", GetUserData(c))
-
- for _, s := range input.Scopes {
- if s == "someScope" {
- return nil
- }
- if s == "unauthorized" {
- return echo.ErrUnauthorized
- }
- }
- return errors.New("forbidden")
- },
- },
- UserData: "hi!",
- }
-
- // Install our OpenApi based request validator
- e.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- e.GET("/resource", func(c echo.Context) error {
- called = true
- return nil
- })
- // Let's send the request to the wrong server, this should return 404
- {
- rec := doGet(t, e, "http://not.deepmap.ai/resource")
- assert.Equal(t, http.StatusNotFound, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- }
-
- // Let's send a good request, it should pass
- {
- rec := doGet(t, e, "http://deepmap.ai/resource")
- assert.Equal(t, http.StatusOK, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Send an out-of-spec parameter
- {
- rec := doGet(t, e, "http://deepmap.ai/resource?id=500")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Send a bad parameter type
- {
- rec := doGet(t, e, "http://deepmap.ai/resource?id=foo")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Add a handler for the POST message
- e.POST("/resource", func(c echo.Context) error {
- called = true
- return c.NoContent(http.StatusNoContent)
- })
-
- called = false
- // Send a good request body
- {
- body := struct {
- Name string `json:"name"`
- }{
- Name: "Marcin",
- }
- rec := doPost(t, e, "http://deepmap.ai/resource", body)
- assert.Equal(t, http.StatusNoContent, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Send a malformed body
- {
- body := struct {
- Name int `json:"name"`
- }{
- Name: 7,
- }
- rec := doPost(t, e, "http://deepmap.ai/resource", body)
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- e.GET("/protected_resource", func(c echo.Context) error {
- called = true
- return c.NoContent(http.StatusNoContent)
-
- })
-
- // Call a protected function to which we have access
- {
- rec := doGet(t, e, "http://deepmap.ai/protected_resource")
- assert.Equal(t, http.StatusNoContent, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- e.GET("/protected_resource2", func(c echo.Context) error {
- called = true
- return c.NoContent(http.StatusNoContent)
- })
- // Call a protected function to which we dont have access
- {
- rec := doGet(t, e, "http://deepmap.ai/protected_resource2")
- assert.Equal(t, http.StatusForbidden, rec.Code)
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- e.GET("/protected_resource_401", func(c echo.Context) error {
- called = true
- return c.NoContent(http.StatusNoContent)
- })
- // Call a protected function without credentials
- {
- rec := doGet(t, e, "http://deepmap.ai/protected_resource_401")
- assert.Equal(t, http.StatusUnauthorized, rec.Code)
- assert.Equal(t, "test: code=401, message=Unauthorized", rec.Body.String())
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-}
-
-func TestOapiRequestValidatorWithOptionsMultiError(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- // Create a new echo router
- e := echo.New()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- Options: openapi3filter.Options{
- ExcludeRequestBody: false,
- ExcludeResponseBody: false,
- IncludeResponseStatus: true,
- MultiError: true,
- },
- }
-
- // register middleware
- e.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- e.GET("/multiparamresource", func(c echo.Context) error {
- called = true
- return nil
- })
-
- // Let's send a good request, it should pass
- {
- rec := doGet(t, e, "http://deepmap.ai/multiparamresource?id=50&id2=50")
- assert.Equal(t, http.StatusOK, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Let's send a request with a missing parameter, it should return
- // a bad status
- {
- rec := doGet(t, e, "http://deepmap.ai/multiparamresource?id=50")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 2 missing parameters, it should return
- // a bad status
- {
- rec := doGet(t, e, "http://deepmap.ai/multiparamresource")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \\\"id\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 1 missing parameter, and another outside
- // or the parameters. It should return a bad status
- {
- rec := doGet(t, e, "http://deepmap.ai/multiparamresource?id=500")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \\\"id\\\"")
- assert.Contains(t, string(body), "number must be at most 100")
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a parameters that do not meet spec. It should
- // return a bad status
- {
- rec := doGet(t, e, "http://deepmap.ai/multiparamresource?id=abc&id2=1")
- assert.Equal(t, http.StatusBadRequest, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \\\"id\\\"")
- assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax")
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "number must be at least 10")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-}
-
-func TestOapiRequestValidatorWithOptionsMultiErrorAndCustomHandler(t *testing.T) {
- swagger, err := openapi3.NewLoader().LoadFromData(testSchema)
- require.NoError(t, err, "Error initializing swagger")
-
- // Create a new echo router
- e := echo.New()
-
- // Set up an authenticator to check authenticated function. It will allow
- // access to "someScope", but disallow others.
- options := Options{
- Options: openapi3filter.Options{
- ExcludeRequestBody: false,
- ExcludeResponseBody: false,
- IncludeResponseStatus: true,
- MultiError: true,
- },
- MultiErrorHandler: func(me openapi3.MultiError) *echo.HTTPError {
- return &echo.HTTPError{
- Code: http.StatusTeapot,
- Message: me.Error(),
- Internal: me,
- }
- },
- }
-
- // register middleware
- e.Use(OapiRequestValidatorWithOptions(swagger, &options))
-
- called := false
-
- // Install a request handler for /resource. We want to make sure it doesn't
- // get called.
- e.GET("/multiparamresource", func(c echo.Context) error {
- called = true
- return nil
- })
-
- // Let's send a good request, it should pass
- {
- rec := doGet(t, e, "http://deepmap.ai/multiparamresource?id=50&id2=50")
- assert.Equal(t, http.StatusOK, rec.Code)
- assert.True(t, called, "Handler should have been called")
- called = false
- }
-
- // Let's send a request with a missing parameter, it should return
- // a bad status
- {
- rec := doGet(t, e, "http://deepmap.ai/multiparamresource?id=50")
- assert.Equal(t, http.StatusTeapot, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 2 missing parameters, it should return
- // a bad status
- {
- rec := doGet(t, e, "http://deepmap.ai/multiparamresource")
- assert.Equal(t, http.StatusTeapot, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \\\"id\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a 1 missing parameter, and another outside
- // or the parameters. It should return a bad status
- {
- rec := doGet(t, e, "http://deepmap.ai/multiparamresource?id=500")
- assert.Equal(t, http.StatusTeapot, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \\\"id\\\"")
- assert.Contains(t, string(body), "number must be at most 100")
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "value is required but missing")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-
- // Let's send a request with a parameters that do not meet spec. It should
- // return a bad status
- {
- rec := doGet(t, e, "http://deepmap.ai/multiparamresource?id=abc&id2=1")
- assert.Equal(t, http.StatusTeapot, rec.Code)
- body, err := io.ReadAll(rec.Body)
- if assert.NoError(t, err) {
- assert.Contains(t, string(body), "parameter \\\"id\\\"")
- assert.Contains(t, string(body), "value abc: an invalid integer: invalid syntax")
- assert.Contains(t, string(body), "parameter \\\"id2\\\"")
- assert.Contains(t, string(body), "number must be at least 10")
- }
- assert.False(t, called, "Handler should not have been called")
- called = false
- }
-}
-
-func TestGetSkipperFromOptions(t *testing.T) {
-
- options := new(Options)
- assert.NotNil(t, getSkipperFromOptions(options))
-
- options = &Options{}
- assert.NotNil(t, getSkipperFromOptions(options))
-
- options = &Options{
- Skipper: echomiddleware.DefaultSkipper,
- }
- assert.NotNil(t, getSkipperFromOptions(options))
-}
diff --git a/pkg/middleware/test_spec.yaml b/pkg/middleware/test_spec.yaml
deleted file mode 100644
index 1f847d756a..0000000000
--- a/pkg/middleware/test_spec.yaml
+++ /dev/null
@@ -1,103 +0,0 @@
-openapi: "3.0.0"
-info:
- version: 1.0.0
- title: TestServer
-servers:
- - url: http://deepmap.ai
-paths:
- /resource:
- get:
- operationId: getResource
- parameters:
- - name: id
- in: query
- schema:
- type: integer
- minimum: 10
- maximum: 100
- responses:
- '200':
- description: success
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- id:
- type: integer
- post:
- operationId: createResource
- responses:
- '204':
- description: No content
- requestBody:
- required: true
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- /protected_resource:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - someScope
- responses:
- '204':
- description: no content
- /protected_resource2:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - otherScope
- responses:
- '204':
- description: no content
- /protected_resource_401:
- get:
- operationId: getProtectedResource
- security:
- - BearerAuth:
- - unauthorized
- responses:
- '401':
- description: no content
- /multiparamresource:
- get:
- operationId: getResource
- parameters:
- - name: id
- in: query
- required: true
- schema:
- type: integer
- minimum: 10
- maximum: 100
- - name: id2
- required: true
- in: query
- schema:
- type: integer
- minimum: 10
- maximum: 100
- responses:
- '200':
- description: success
- content:
- application/json:
- schema:
- properties:
- name:
- type: string
- id:
- type: integer
-components:
- securitySchemes:
- BearerAuth:
- type: http
- scheme: bearer
- bearerFormat: JWT
diff --git a/pkg/runtime/bind.go b/pkg/runtime/bind.go
deleted file mode 100644
index f802478569..0000000000
--- a/pkg/runtime/bind.go
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2021 DeepMap, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package runtime
-
-// Binder is the interface implemented by types that can be bound to a query string or a parameter string
-// The input can be assumed to be a valid string. If you define a Bind method you are responsible for all
-// data being completely bound to the type.
-//
-// By convention, to approximate the behavior of Bind functions themselves,
-// Binder implements Bind("") as a no-op.
-//
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#Binder
-type Binder interface {
- Bind(src string) error
-}
diff --git a/pkg/runtime/bindform.go b/pkg/runtime/bindform.go
deleted file mode 100644
index 77e38b5003..0000000000
--- a/pkg/runtime/bindform.go
+++ /dev/null
@@ -1,313 +0,0 @@
-package runtime
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "mime/multipart"
- "net/url"
- "reflect"
- "strconv"
- "strings"
-
- "github.com/deepmap/oapi-codegen/pkg/types"
-)
-
-const tagName = "json"
-const jsonContentType = "application/json"
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#RequestBodyEncoding
-type RequestBodyEncoding struct {
- ContentType string
- Style string
- Explode *bool
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#BindMultipart
-func BindMultipart(ptr interface{}, reader multipart.Reader) error {
- const defaultMemory = 32 << 20
- form, err := reader.ReadForm(defaultMemory)
- if err != nil {
- return err
- }
- return BindForm(ptr, form.Value, form.File, nil)
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#BindForm
-func BindForm(ptr interface{}, form map[string][]string, files map[string][]*multipart.FileHeader, encodings map[string]RequestBodyEncoding) error {
- ptrVal := reflect.Indirect(reflect.ValueOf(ptr))
- if ptrVal.Kind() != reflect.Struct {
- return errors.New("form data body should be a struct")
- }
- tValue := ptrVal.Type()
-
- for i := 0; i < tValue.NumField(); i++ {
- field := ptrVal.Field(i)
- tag := tValue.Field(i).Tag.Get(tagName)
- if !field.CanInterface() || tag == "-" {
- continue
- }
- tag = strings.Split(tag, ",")[0] // extract the name of the tag
- if encoding, ok := encodings[tag]; ok {
- // custom encoding
- values := form[tag]
- if len(values) == 0 {
- continue
- }
- value := values[0]
- if encoding.ContentType != "" {
- if strings.HasPrefix(encoding.ContentType, jsonContentType) {
- if err := json.Unmarshal([]byte(value), ptr); err != nil {
- return err
- }
- }
- return errors.New("unsupported encoding, only application/json is supported")
- } else {
- var explode bool
- if encoding.Explode != nil {
- explode = *encoding.Explode
- }
- if err := BindStyledParameterWithLocation(encoding.Style, explode, tag, ParamLocationUndefined, value, field.Addr().Interface()); err != nil {
- return err
- }
- }
- } else {
- // regular form data
- if _, err := bindFormImpl(field, form, files, tag); err != nil {
- return err
- }
- }
- }
-
- return nil
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#MarshalForm
-func MarshalForm(ptr interface{}, encodings map[string]RequestBodyEncoding) (url.Values, error) {
- ptrVal := reflect.Indirect(reflect.ValueOf(ptr))
- if ptrVal.Kind() != reflect.Struct {
- return nil, errors.New("form data body should be a struct")
- }
- tValue := ptrVal.Type()
- result := make(url.Values)
- for i := 0; i < tValue.NumField(); i++ {
- field := ptrVal.Field(i)
- tag := tValue.Field(i).Tag.Get(tagName)
- if !field.CanInterface() || tag == "-" {
- continue
- }
- omitEmpty := strings.HasSuffix(tag, ",omitempty")
- if omitEmpty && field.IsZero() {
- continue
- }
- tag = strings.Split(tag, ",")[0] // extract the name of the tag
- if encoding, ok := encodings[tag]; ok && encoding.ContentType != "" {
- if strings.HasPrefix(encoding.ContentType, jsonContentType) {
- if data, err := json.Marshal(field); err != nil { //nolint:staticcheck
- return nil, err
- } else {
- result[tag] = append(result[tag], string(data))
- }
- }
- return nil, errors.New("unsupported encoding, only application/json is supported")
- } else {
- marshalFormImpl(field, result, tag)
- }
- }
- return result, nil
-}
-
-func bindFormImpl(v reflect.Value, form map[string][]string, files map[string][]*multipart.FileHeader, name string) (bool, error) {
- var hasData bool
- switch v.Kind() {
- case reflect.Interface:
- return bindFormImpl(v.Elem(), form, files, name)
- case reflect.Ptr:
- ptrData := v.Elem()
- if !ptrData.IsValid() {
- ptrData = reflect.New(v.Type().Elem())
- }
- ptrHasData, err := bindFormImpl(ptrData, form, files, name)
- if err == nil && ptrHasData && !v.Elem().IsValid() {
- v.Set(ptrData)
- }
- return ptrHasData, err
- case reflect.Slice:
- if files := append(files[name], files[name+"[]"]...); len(files) != 0 {
- if _, ok := v.Interface().([]types.File); ok {
- result := make([]types.File, len(files))
- for i, file := range files {
- result[i].InitFromMultipart(file)
- }
- v.Set(reflect.ValueOf(result))
- hasData = true
- }
- }
- indexedElementsCount := indexedElementsCount(form, files, name)
- items := append(form[name], form[name+"[]"]...)
- if indexedElementsCount+len(items) != 0 {
- result := reflect.MakeSlice(v.Type(), indexedElementsCount+len(items), indexedElementsCount+len(items))
- for i := 0; i < indexedElementsCount; i++ {
- if _, err := bindFormImpl(result.Index(i), form, files, fmt.Sprintf("%s[%v]", name, i)); err != nil {
- return false, err
- }
- }
- for i, item := range items {
- if err := BindStringToObject(item, result.Index(indexedElementsCount+i).Addr().Interface()); err != nil {
- return false, err
- }
- }
- v.Set(result)
- hasData = true
- }
- case reflect.Struct:
- if files := files[name]; len(files) != 0 {
- if file, ok := v.Interface().(types.File); ok {
- file.InitFromMultipart(files[0])
- v.Set(reflect.ValueOf(file))
- return true, nil
- }
- }
- for i := 0; i < v.NumField(); i++ {
- field := v.Type().Field(i)
- tag := field.Tag.Get(tagName)
- if field.Name == "AdditionalProperties" && field.Type.Kind() == reflect.Map && tag == "-" {
- additionalPropertiesHasData, err := bindAdditionalProperties(v.Field(i), v, form, files, name)
- if err != nil {
- return false, err
- }
- hasData = hasData || additionalPropertiesHasData
- }
- if !v.Field(i).CanInterface() || tag == "-" {
- continue
- }
- tag = strings.Split(tag, ",")[0] // extract the name of the tag
- fieldHasData, err := bindFormImpl(v.Field(i), form, files, fmt.Sprintf("%s[%s]", name, tag))
- if err != nil {
- return false, err
- }
- hasData = hasData || fieldHasData
- }
- return hasData, nil
- default:
- value := form[name]
- if len(value) != 0 {
- return true, BindStringToObject(value[0], v.Addr().Interface())
- }
- }
- return hasData, nil
-}
-
-func indexedElementsCount(form map[string][]string, files map[string][]*multipart.FileHeader, name string) int {
- name += "["
- maxIndex := -1
- for k := range form {
- if strings.HasPrefix(k, name) {
- str := strings.TrimPrefix(k, name)
- str = str[:strings.Index(str, "]")]
- if idx, err := strconv.Atoi(str); err == nil {
- if idx > maxIndex {
- maxIndex = idx
- }
- }
- }
- }
- for k := range files {
- if strings.HasPrefix(k, name) {
- str := strings.TrimPrefix(k, name)
- str = str[:strings.Index(str, "]")]
- if idx, err := strconv.Atoi(str); err == nil {
- if idx > maxIndex {
- maxIndex = idx
- }
- }
- }
- }
- return maxIndex + 1
-}
-
-func bindAdditionalProperties(additionalProperties reflect.Value, parentStruct reflect.Value, form map[string][]string, files map[string][]*multipart.FileHeader, name string) (bool, error) {
- hasData := false
- valueType := additionalProperties.Type().Elem()
-
- // store all fixed properties in a set
- fieldsSet := make(map[string]struct{})
- for i := 0; i < parentStruct.NumField(); i++ {
- tag := parentStruct.Type().Field(i).Tag.Get(tagName)
- if !parentStruct.Field(i).CanInterface() || tag == "-" {
- continue
- }
- tag = strings.Split(tag, ",")[0]
- fieldsSet[tag] = struct{}{}
- }
-
- result := reflect.MakeMap(additionalProperties.Type())
- for k := range form {
- if strings.HasPrefix(k, name+"[") {
- key := strings.TrimPrefix(k, name+"[")
- key = key[:strings.Index(key, "]")]
- if _, ok := fieldsSet[key]; ok {
- continue
- }
- value := reflect.New(valueType)
- ptrHasData, err := bindFormImpl(value, form, files, fmt.Sprintf("%s[%s]", name, key))
- if err != nil {
- return false, err
- }
- result.SetMapIndex(reflect.ValueOf(key), value.Elem())
- hasData = hasData || ptrHasData
- }
- }
- for k := range files {
- if strings.HasPrefix(k, name+"[") {
- key := strings.TrimPrefix(k, name+"[")
- key = key[:strings.Index(key, "]")]
- if _, ok := fieldsSet[key]; ok {
- continue
- }
- value := reflect.New(valueType)
- result.SetMapIndex(reflect.ValueOf(key), value)
- ptrHasData, err := bindFormImpl(value, form, files, fmt.Sprintf("%s[%s]", name, key))
- if err != nil {
- return false, err
- }
- result.SetMapIndex(reflect.ValueOf(key), value.Elem())
- hasData = hasData || ptrHasData
- }
- }
- if hasData {
- additionalProperties.Set(result)
- }
- return hasData, nil
-}
-
-func marshalFormImpl(v reflect.Value, result url.Values, name string) {
- switch v.Kind() {
- case reflect.Interface, reflect.Ptr:
- marshalFormImpl(v.Elem(), result, name)
- case reflect.Slice:
- for i := 0; i < v.Len(); i++ {
- elem := v.Index(i)
- marshalFormImpl(elem, result, fmt.Sprintf("%s[%v]", name, i))
- }
- case reflect.Struct:
- for i := 0; i < v.NumField(); i++ {
- field := v.Type().Field(i)
- tag := field.Tag.Get(tagName)
- if field.Name == "AdditionalProperties" && tag == "-" {
- iter := v.MapRange()
- for iter.Next() {
- marshalFormImpl(iter.Value(), result, fmt.Sprintf("%s[%s]", name, iter.Key().String()))
- }
- continue
- }
- if !v.Field(i).CanInterface() || tag == "-" {
- continue
- }
- tag = strings.Split(tag, ",")[0] // extract the name of the tag
- marshalFormImpl(v.Field(i), result, fmt.Sprintf("%s[%s]", name, tag))
- }
- default:
- result[name] = append(result[name], fmt.Sprint(v.Interface()))
- }
-}
diff --git a/pkg/runtime/bindform_test.go b/pkg/runtime/bindform_test.go
deleted file mode 100644
index 398f9b00e3..0000000000
--- a/pkg/runtime/bindform_test.go
+++ /dev/null
@@ -1,195 +0,0 @@
-package runtime
-
-import (
- "bytes"
- "mime/multipart"
- "net/url"
- "testing"
-
- "github.com/deepmap/oapi-codegen/pkg/types"
- "github.com/stretchr/testify/assert"
-)
-
-func TestBindURLForm(t *testing.T) {
- type testSubStruct struct {
- Int int `json:"int"`
- String string `json:"string"`
- AdditionalProperties map[string]string `json:"-"`
- }
- type testStruct struct {
- Int int `json:"int"`
- Bool bool `json:"bool,omitempty"`
- String string `json:"string"`
- IntSlice []int `json:"int_slice"`
- Struct testSubStruct `json:"struct"`
- StructSlice []testSubStruct `json:"struct_slice"`
- OptInt *int `json:"opt_int,omitempty"`
- OptBool *bool `json:"opt_bool,omitempty"`
- OptString *string `json:"opt_string,omitempty"`
- OptStruct *testSubStruct `json:"opt_struct,omitempty"`
- OptStructSlice *[]testSubStruct `json:"opt_struct_slice,omitempty"`
- NotSerializable int `json:"-"`
- unexported int //nolint:unused
- }
-
- testCases := map[string]testStruct{
- "int=123": {Int: 123},
- "bool=true": {Bool: true},
- "string=example": {String: "example"},
- "int_slice=1&int_slice=2&int_slice=3": {IntSlice: []int{1, 2, 3}},
- "int_slice[]=1&int_slice[]=2&int_slice[]=3": {IntSlice: []int{1, 2, 3}},
- "int_slice[2]=3&int_slice[1]=2&int_slice[0]=1": {IntSlice: []int{1, 2, 3}},
- "struct[int]=789&struct[string]=abc": {Struct: testSubStruct{Int: 789, String: "abc"}},
- "struct_slice[0][int]=3&struct_slice[0][string]=a&struct_slice[1][int]=2&struct_slice[1][string]=b&struct_slice[2][int]=1&struct_slice[2][string]=c": {
- StructSlice: []testSubStruct{{Int: 3, String: "a"}, {Int: 2, String: "b"}, {Int: 1, String: "c"}},
- },
- "opt_int=456": {OptInt: func(v int) *int { return &v }(456)},
- "opt_bool=true": {OptBool: func(v bool) *bool { return &v }(true)},
- "opt_string=def": {OptString: func(v string) *string { return &v }("def")},
- "opt_struct[int]=456&opt_struct[string]=def": {OptStruct: &testSubStruct{Int: 456, String: "def"}},
- "opt_struct_slice[0][int]=123&opt_struct_slice[0][string]=abc&opt_struct_slice[1][int]=456&opt_struct_slice[1][string]=def": {
- OptStructSlice: &([]testSubStruct{{Int: 123, String: "abc"}, {Int: 456, String: "def"}}),
- },
- "opt_struct[additional_property]=123": {
- OptStruct: &testSubStruct{AdditionalProperties: map[string]string{"additional_property": "123"}},
- },
- }
-
- for k, v := range testCases {
- values, err := url.ParseQuery(k)
- assert.NoError(t, err)
- var result testStruct
- err = BindForm(&result, values, nil, nil)
- assert.NoError(t, err)
- assert.Equal(t, v, result)
- }
-}
-
-func TestBindMultipartForm(t *testing.T) {
- var testStruct struct {
- File types.File `json:"file"`
- OptFile *types.File `json:"opt_file,omitempty"`
- Files []types.File `json:"files"`
- OptFiles *[]types.File `json:"opt_files"`
- }
-
- form, err := makeMultipartFilesForm([]fileData{{field: "file", filename: "123.txt", content: []byte("123")}})
- assert.NoError(t, err)
- err = BindForm(&testStruct, form.Value, form.File, nil)
- assert.NoError(t, err)
- assert.Equal(t, "123.txt", testStruct.File.Filename())
- content, err := testStruct.File.Bytes()
- assert.NoError(t, err)
- assert.Equal(t, []byte("123"), content)
-
- form, err = makeMultipartFilesForm([]fileData{
- {field: "files", filename: "123.pdf", content: []byte("123")},
- {field: "files", filename: "456.pdf", content: []byte("456")},
- {field: "files", filename: "789.pdf", content: []byte("789")},
- })
- assert.NoError(t, err)
- err = BindForm(&testStruct, form.Value, form.File, nil)
- assert.NoError(t, err)
- assert.Equal(t, 3, len(testStruct.Files))
- assert.Equal(t, "123.pdf", testStruct.Files[0].Filename())
- assert.Equal(t, "456.pdf", testStruct.Files[1].Filename())
- assert.Equal(t, "789.pdf", testStruct.Files[2].Filename())
-
- form, err = makeMultipartFilesForm([]fileData{{field: "opt_file", filename: "456.png", content: []byte("456")}})
- assert.NoError(t, err)
- err = BindForm(&testStruct, form.Value, form.File, nil)
- assert.NoError(t, err)
- assert.Equal(t, "456.png", testStruct.OptFile.Filename())
- content, err = testStruct.OptFile.Bytes()
- assert.NoError(t, err)
- assert.Equal(t, []byte("456"), content)
-
- form, err = makeMultipartFilesForm([]fileData{
- {field: "opt_files[2]", filename: "123.pdf", content: []byte("123")},
- {field: "opt_files[1]", filename: "456.pdf", content: []byte("456")},
- {field: "opt_files[0]", filename: "789.pdf", content: []byte("789")},
- })
- assert.NoError(t, err)
- err = BindForm(&testStruct, form.Value, form.File, nil)
- assert.NoError(t, err)
- assert.NotNil(t, testStruct.OptFiles)
- assert.Equal(t, 3, len(*testStruct.OptFiles))
- assert.Equal(t, "789.pdf", (*testStruct.OptFiles)[0].Filename())
- assert.Equal(t, "456.pdf", (*testStruct.OptFiles)[1].Filename())
- assert.Equal(t, "123.pdf", (*testStruct.OptFiles)[2].Filename())
-}
-
-func TestMarshalForm(t *testing.T) {
- type testSubStruct struct {
- Int int `json:"int"`
- String string `json:"string"`
- }
- type testStruct struct {
- Int int `json:"int,omitempty"`
- Bool bool `json:"bool,omitempty"`
- String string `json:"string,omitempty"`
- IntSlice []int `json:"int_slice,omitempty"`
- Struct testSubStruct `json:"struct,omitempty"`
- StructSlice []testSubStruct `json:"struct_slice,omitempty"`
- OptInt *int `json:"opt_int,omitempty"`
- OptBool *bool `json:"opt_bool,omitempty"`
- OptString *string `json:"opt_string,omitempty"`
- OptStruct *testSubStruct `json:"opt_struct,omitempty"`
- OptStructSlice *[]testSubStruct `json:"opt_struct_slice,omitempty"`
- NotSerializable int `json:"-"`
- unexported int //nolint:unused
- }
-
- testCases := map[string]testStruct{
- "int=123": {Int: 123},
- "bool=true": {Bool: true},
- "string=example": {String: "example"},
- "int_slice[0]=1&int_slice[1]=2&int_slice[2]=3": {IntSlice: []int{1, 2, 3}},
- "struct[int]=789&struct[string]=abc": {Struct: testSubStruct{Int: 789, String: "abc"}},
- "struct_slice[0][int]=3&struct_slice[0][string]=a&struct_slice[1][int]=2&struct_slice[1][string]=b&struct_slice[2][int]=1&struct_slice[2][string]=c": {
- StructSlice: []testSubStruct{{Int: 3, String: "a"}, {Int: 2, String: "b"}, {Int: 1, String: "c"}},
- },
- "opt_int=456": {OptInt: func(v int) *int { return &v }(456)},
- "opt_bool=true": {OptBool: func(v bool) *bool { return &v }(true)},
- "opt_string=def": {OptString: func(v string) *string { return &v }("def")},
- "opt_struct[int]=456&opt_struct[string]=def": {OptStruct: &testSubStruct{Int: 456, String: "def"}},
- "opt_struct_slice[0][int]=123&opt_struct_slice[0][string]=abc&opt_struct_slice[1][int]=456&opt_struct_slice[1][string]=def": {
- OptStructSlice: &([]testSubStruct{{Int: 123, String: "abc"}, {Int: 456, String: "def"}}),
- },
- }
-
- for k, v := range testCases {
- marshaled, err := MarshalForm(v, nil)
- assert.NoError(t, err)
- encoded, err := url.QueryUnescape(marshaled.Encode())
- assert.NoError(t, err)
- assert.Equal(t, k, encoded)
- }
-}
-
-type fileData struct {
- field string
- filename string
- content []byte
-}
-
-func makeMultipartFilesForm(files []fileData) (*multipart.Form, error) {
- var buffer bytes.Buffer
- mw := multipart.NewWriter(&buffer)
- for _, file := range files {
- w, err := mw.CreateFormFile(file.field, file.filename)
- if err != nil {
- return nil, err
- }
- _, err = w.Write(file.content)
- if err != nil {
- return nil, err
- }
- }
- err := mw.Close()
- if err != nil {
- return nil, err
- }
- mr := multipart.NewReader(&buffer, mw.Boundary())
- return mr.ReadForm(1024)
-}
diff --git a/pkg/runtime/bindparam.go b/pkg/runtime/bindparam.go
deleted file mode 100644
index 91463d787c..0000000000
--- a/pkg/runtime/bindparam.go
+++ /dev/null
@@ -1,532 +0,0 @@
-// Copyright 2019 DeepMap, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package runtime
-
-import (
- "encoding"
- "encoding/json"
- "errors"
- "fmt"
- "net/url"
- "reflect"
- "strings"
- "time"
-
- "github.com/deepmap/oapi-codegen/pkg/types"
-)
-
-// BindStyledParameter binds a parameter as described in the Path Parameters
-// section here to a Go object:
-// https://swagger.io/docs/specification/serialization/
-// It is a backward compatible function to clients generated with codegen
-// up to version v1.5.5. v1.5.6+ calls the function below.
-//
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#BindStyledParameter
-func BindStyledParameter(style string, explode bool, paramName string,
- value string, dest interface{}) error {
- return BindStyledParameterWithLocation(style, explode, paramName, ParamLocationUndefined, value, dest)
-}
-
-// BindStyledParameterWithLocation binds a parameter as described in the Path Parameters
-// section here to a Go object:
-// https://swagger.io/docs/specification/serialization/
-//
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#BindStyledParameterWithLocation
-func BindStyledParameterWithLocation(style string, explode bool, paramName string,
- paramLocation ParamLocation, value string, dest interface{}) error {
-
- if value == "" {
- return fmt.Errorf("parameter '%s' is empty, can't bind its value", paramName)
- }
-
- // Based on the location of the parameter, we need to unescape it properly.
- var err error
- switch paramLocation {
- case ParamLocationQuery, ParamLocationUndefined:
- // We unescape undefined parameter locations here for older generated code,
- // since prior to this refactoring, they always query unescaped.
- value, err = url.QueryUnescape(value)
- if err != nil {
- return fmt.Errorf("error unescaping query parameter '%s': %v", paramName, err)
- }
- case ParamLocationPath:
- value, err = url.PathUnescape(value)
- if err != nil {
- return fmt.Errorf("error unescaping path parameter '%s': %v", paramName, err)
- }
- default:
- // Headers and cookies aren't escaped.
- }
-
- // If the destination implements encoding.TextUnmarshaler we use it for binding
- if tu, ok := dest.(encoding.TextUnmarshaler); ok {
- if err := tu.UnmarshalText([]byte(value)); err != nil {
- return fmt.Errorf("error unmarshaling '%s' text as %T: %s", value, dest, err)
- }
-
- return nil
- }
-
- // Everything comes in by pointer, dereference it
- v := reflect.Indirect(reflect.ValueOf(dest))
-
- // This is the basic type of the destination object.
- t := v.Type()
-
- if t.Kind() == reflect.Struct {
- // We've got a destination object, we'll create a JSON representation
- // of the input value, and let the json library deal with the unmarshaling
- parts, err := splitStyledParameter(style, explode, true, paramName, value)
- if err != nil {
- return err
- }
-
- return bindSplitPartsToDestinationStruct(paramName, parts, explode, dest)
- }
-
- if t.Kind() == reflect.Slice {
- // Chop up the parameter into parts based on its style
- parts, err := splitStyledParameter(style, explode, false, paramName, value)
- if err != nil {
- return fmt.Errorf("error splitting input '%s' into parts: %s", value, err)
- }
-
- return bindSplitPartsToDestinationArray(parts, dest)
- }
-
- // Try to bind the remaining types as a base type.
- return BindStringToObject(value, dest)
-}
-
-// This is a complex set of operations, but each given parameter style can be
-// packed together in multiple ways, using different styles of separators, and
-// different packing strategies based on the explode flag. This function takes
-// as input any parameter format, and unpacks it to a simple list of strings
-// or key-values which we can then treat generically.
-// Why, oh why, great Swagger gods, did you have to make this so complicated?
-func splitStyledParameter(style string, explode bool, object bool, paramName string, value string) ([]string, error) {
- switch style {
- case "simple":
- // In the simple case, we always split on comma
- parts := strings.Split(value, ",")
- return parts, nil
- case "label":
- // In the label case, it's more tricky. In the no explode case, we have
- // /users/.3,4,5 for arrays
- // /users/.role,admin,firstName,Alex for objects
- // in the explode case, we have:
- // /users/.3.4.5
- // /users/.role=admin.firstName=Alex
- if explode {
- // In the exploded case, split everything on periods.
- parts := strings.Split(value, ".")
- // The first part should be an empty string because we have a
- // leading period.
- if parts[0] != "" {
- return nil, fmt.Errorf("invalid format for label parameter '%s', should start with '.'", paramName)
- }
- return parts[1:], nil
-
- } else {
- // In the unexploded case, we strip off the leading period.
- if value[0] != '.' {
- return nil, fmt.Errorf("invalid format for label parameter '%s', should start with '.'", paramName)
- }
- // The rest is comma separated.
- return strings.Split(value[1:], ","), nil
- }
-
- case "matrix":
- if explode {
- // In the exploded case, we break everything up on semicolon
- parts := strings.Split(value, ";")
- // The first part should always be empty string, since we started
- // with ;something
- if parts[0] != "" {
- return nil, fmt.Errorf("invalid format for matrix parameter '%s', should start with ';'", paramName)
- }
- parts = parts[1:]
- // Now, if we have an object, we just have a list of x=y statements.
- // for a non-object, like an array, we have id=x, id=y. id=z, etc,
- // so we need to strip the prefix from each of them.
- if !object {
- prefix := paramName + "="
- for i := range parts {
- parts[i] = strings.TrimPrefix(parts[i], prefix)
- }
- }
- return parts, nil
- } else {
- // In the unexploded case, parameters will start with ;paramName=
- prefix := ";" + paramName + "="
- if !strings.HasPrefix(value, prefix) {
- return nil, fmt.Errorf("expected parameter '%s' to start with %s", paramName, prefix)
- }
- str := strings.TrimPrefix(value, prefix)
- return strings.Split(str, ","), nil
- }
- case "form":
- var parts []string
- if explode {
- parts = strings.Split(value, "&")
- if !object {
- prefix := paramName + "="
- for i := range parts {
- parts[i] = strings.TrimPrefix(parts[i], prefix)
- }
- }
- return parts, nil
- } else {
- parts = strings.Split(value, ",")
- prefix := paramName + "="
- for i := range parts {
- parts[i] = strings.TrimPrefix(parts[i], prefix)
- }
- }
- return parts, nil
- }
-
- return nil, fmt.Errorf("unhandled parameter style: %s", style)
-}
-
-// Given a set of values as a slice, create a slice to hold them all, and
-// assign to each one by one.
-func bindSplitPartsToDestinationArray(parts []string, dest interface{}) error {
- // Everything comes in by pointer, dereference it
- v := reflect.Indirect(reflect.ValueOf(dest))
-
- // This is the basic type of the destination object.
- t := v.Type()
-
- // We've got a destination array, bind each object one by one.
- // This generates a slice of the correct element type and length to
- // hold all the parts.
- newArray := reflect.MakeSlice(t, len(parts), len(parts))
- for i, p := range parts {
- err := BindStringToObject(p, newArray.Index(i).Addr().Interface())
- if err != nil {
- return fmt.Errorf("error setting array element: %w", err)
- }
- }
- v.Set(newArray)
- return nil
-}
-
-// Given a set of chopped up parameter parts, bind them to a destination
-// struct. The exploded parameter controls whether we send key value pairs
-// in the exploded case, or a sequence of values which are interpreted as
-// tuples.
-// Given the struct Id { firstName string, role string }, as in the canonical
-// swagger examples, in the exploded case, we would pass
-// ["firstName=Alex", "role=admin"], where in the non-exploded case, we would
-// pass "firstName", "Alex", "role", "admin"]
-//
-// We punt the hard work of binding these values to the object to the json
-// library. We'll turn those arrays into JSON strings, and unmarshal
-// into the struct.
-func bindSplitPartsToDestinationStruct(paramName string, parts []string, explode bool, dest interface{}) error {
- // We've got a destination object, we'll create a JSON representation
- // of the input value, and let the json library deal with the unmarshaling
- var fields []string
- if explode {
- fields = make([]string, len(parts))
- for i, property := range parts {
- propertyParts := strings.Split(property, "=")
- if len(propertyParts) != 2 {
- return fmt.Errorf("parameter '%s' has invalid exploded format", paramName)
- }
- fields[i] = "\"" + propertyParts[0] + "\":\"" + propertyParts[1] + "\""
- }
- } else {
- if len(parts)%2 != 0 {
- return fmt.Errorf("parameter '%s' has invalid format, property/values need to be pairs", paramName)
- }
- fields = make([]string, len(parts)/2)
- for i := 0; i < len(parts); i += 2 {
- key := parts[i]
- value := parts[i+1]
- fields[i/2] = "\"" + key + "\":\"" + value + "\""
- }
- }
- jsonParam := "{" + strings.Join(fields, ",") + "}"
- err := json.Unmarshal([]byte(jsonParam), dest)
- if err != nil {
- return fmt.Errorf("error binding parameter %s fields: %s", paramName, err)
- }
- return nil
-}
-
-// BindQueryParameter works much like BindStyledParameter, however it takes a query argument
-// input array from the url package, since query arguments come through a
-// different path than the styled arguments. They're also exceptionally fussy.
-// For example, consider the exploded and unexploded form parameter examples:
-// (exploded) /users?role=admin&firstName=Alex
-// (unexploded) /users?id=role,admin,firstName,Alex
-//
-// In the first case, we can pull the "id" parameter off the context,
-// and unmarshal via json as an intermediate. Easy. In the second case, we
-// don't have the id QueryParam present, but must find "role", and "firstName".
-// what if there is another parameter similar to "ID" named "role"? We can't
-// tell them apart. This code tries to fail, but the moral of the story is that
-// you shouldn't pass objects via form styled query arguments, just use
-// the Content parameter form.
-//
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#BindQueryParameter
-func BindQueryParameter(style string, explode bool, required bool, paramName string,
- queryParams url.Values, dest interface{}) error {
-
- // dv = destination value.
- dv := reflect.Indirect(reflect.ValueOf(dest))
-
- // intermediate value form which is either dv or dv dereferenced.
- v := dv
-
- // inner code will bind the string's value to this interface.
- var output interface{}
-
- if required {
- // If the parameter is required, then the generated code will pass us
- // a pointer to it: &int, &object, and so forth. We can directly set
- // them.
- output = dest
- } else {
- // For optional parameters, we have an extra indirect. An optional
- // parameter of type "int" will be *int on the struct. We pass that
- // in by pointer, and have **int.
-
- // If the destination, is a nil pointer, we need to allocate it.
- if v.IsNil() {
- t := v.Type()
- newValue := reflect.New(t.Elem())
- // for now, hang onto the output buffer separately from destination,
- // as we don't want to write anything to destination until we can
- // unmarshal successfully, and check whether a field is required.
- output = newValue.Interface()
- } else {
- // If the destination isn't nil, just use that.
- output = v.Interface()
- }
-
- // Get rid of that extra indirect as compared to the required case,
- // so the code below doesn't have to care.
- v = reflect.Indirect(reflect.ValueOf(output))
- }
-
- // This is the basic type of the destination object.
- t := v.Type()
- k := t.Kind()
-
- switch style {
- case "form":
- var parts []string
- if explode {
- // ok, the explode case in query arguments is very, very annoying,
- // because an exploded object, such as /users?role=admin&firstName=Alex
- // isn't actually present in the parameter array. We have to do
- // different things based on destination type.
- values, found := queryParams[paramName]
- var err error
-
- switch k {
- case reflect.Slice:
- // In the slice case, we simply use the arguments provided by
- // http library.
-
- if !found {
- if required {
- return fmt.Errorf("query parameter '%s' is required", paramName)
- } else {
- // If an optional parameter is not found, we do nothing,
- return nil
- }
- }
- err = bindSplitPartsToDestinationArray(values, output)
- case reflect.Struct:
- // This case is really annoying, and error prone, but the
- // form style object binding doesn't tell us which arguments
- // in the query string correspond to the object's fields. We'll
- // try to bind field by field.
- var fieldsPresent bool
- fieldsPresent, err = bindParamsToExplodedObject(paramName, queryParams, output)
- // If no fields were set, and there is no error, we will not fall
- // through to assign the destination.
- if !fieldsPresent {
- return nil
- }
- default:
- // Primitive object case. We expect to have 1 value to
- // unmarshal.
- if len(values) == 0 {
- if required {
- return fmt.Errorf("query parameter '%s' is required", paramName)
- } else {
- return nil
- }
- }
- if len(values) != 1 {
- return fmt.Errorf("multiple values for single value parameter '%s'", paramName)
- }
-
- if !found {
- if required {
- return fmt.Errorf("query parameter '%s' is required", paramName)
- } else {
- // If an optional parameter is not found, we do nothing,
- return nil
- }
- }
- err = BindStringToObject(values[0], output)
- }
- if err != nil {
- return err
- }
- // If the parameter is required, and we've successfully unmarshaled
- // it, this assigns the new object to the pointer pointer.
- if !required {
- dv.Set(reflect.ValueOf(output))
- }
- return nil
- } else {
- values, found := queryParams[paramName]
- if !found {
- if required {
- return fmt.Errorf("query parameter '%s' is required", paramName)
- } else {
- return nil
- }
- }
- if len(values) != 1 {
- return fmt.Errorf("parameter '%s' is not exploded, but is specified multiple times", paramName)
- }
- parts = strings.Split(values[0], ",")
- }
- var err error
- switch k {
- case reflect.Slice:
- err = bindSplitPartsToDestinationArray(parts, output)
- case reflect.Struct:
- err = bindSplitPartsToDestinationStruct(paramName, parts, explode, output)
- default:
- if len(parts) == 0 {
- if required {
- return fmt.Errorf("query parameter '%s' is required", paramName)
- } else {
- return nil
- }
- }
- if len(parts) != 1 {
- return fmt.Errorf("multiple values for single value parameter '%s'", paramName)
- }
- err = BindStringToObject(parts[0], output)
- }
- if err != nil {
- return err
- }
- if !required {
- dv.Set(reflect.ValueOf(output))
- }
- return nil
- case "deepObject":
- if !explode {
- return errors.New("deepObjects must be exploded")
- }
- return UnmarshalDeepObject(dest, paramName, queryParams)
- case "spaceDelimited", "pipeDelimited":
- return fmt.Errorf("query arguments of style '%s' aren't yet supported", style)
- default:
- return fmt.Errorf("style '%s' on parameter '%s' is invalid", style, paramName)
-
- }
-}
-
-// bindParamsToExplodedObject reflects the destination structure, and pulls the value for
-// each settable field from the given parameters map. This is to deal with the
-// exploded form styled object which may occupy any number of parameter names.
-// We don't try to be smart here, if the field exists as a query argument,
-// set its value. This function returns a boolean, telling us whether there was
-// anything to bind. There will be nothing to bind if a parameter isn't found by name,
-// or none of an exploded object's fields are present.
-func bindParamsToExplodedObject(paramName string, values url.Values, dest interface{}) (bool, error) {
- // Dereference pointers to their destination values
- binder, v, t := indirect(dest)
- if binder != nil {
- _, found := values[paramName]
- if !found {
- return false, nil
- }
- return true, BindStringToObject(values.Get(paramName), dest)
- }
- if t.Kind() != reflect.Struct {
- return false, fmt.Errorf("unmarshaling query arg '%s' into wrong type", paramName)
- }
-
- fieldsPresent := false
- for i := 0; i < t.NumField(); i++ {
- fieldT := t.Field(i)
-
- // Skip unsettable fields, such as internal ones.
- if !v.Field(i).CanSet() {
- continue
- }
-
- // Find the json annotation on the field, and use the json specified
- // name if available, otherwise, just the field name.
- tag := fieldT.Tag.Get("json")
- fieldName := fieldT.Name
- if tag != "" {
- tagParts := strings.Split(tag, ",")
- name := tagParts[0]
- if name != "" {
- fieldName = name
- }
- }
-
- // At this point, we look up field name in the parameter list.
- fieldVal, found := values[fieldName]
- if found {
- if len(fieldVal) != 1 {
- return false, fmt.Errorf("field '%s' specified multiple times for param '%s'", fieldName, paramName)
- }
- err := BindStringToObject(fieldVal[0], v.Field(i).Addr().Interface())
- if err != nil {
- return false, fmt.Errorf("could not bind query arg '%s' to request object: %s'", paramName, err)
- }
- fieldsPresent = true
- }
- }
- return fieldsPresent, nil
-}
-
-// indirect
-func indirect(dest interface{}) (interface{}, reflect.Value, reflect.Type) {
- v := reflect.ValueOf(dest)
- if v.Type().NumMethod() > 0 && v.CanInterface() {
- if u, ok := v.Interface().(Binder); ok {
- return u, reflect.Value{}, nil
- }
- }
- v = reflect.Indirect(v)
- t := v.Type()
- // special handling for custom types which might look like an object. We
- // don't want to use object binding on them, but rather treat them as
- // primitive types. time.Time{} is a unique case since we can't add a Binder
- // to it without changing the underlying generated code.
- if t.ConvertibleTo(reflect.TypeOf(time.Time{})) {
- return dest, reflect.Value{}, nil
- }
- if t.ConvertibleTo(reflect.TypeOf(types.Date{})) {
- return dest, reflect.Value{}, nil
- }
- return nil, v, t
-}
diff --git a/pkg/runtime/bindparam_test.go b/pkg/runtime/bindparam_test.go
deleted file mode 100644
index 2334c50a1a..0000000000
--- a/pkg/runtime/bindparam_test.go
+++ /dev/null
@@ -1,500 +0,0 @@
-// Copyright 2019 DeepMap, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package runtime
-
-import (
- "encoding/json"
- "fmt"
- "math/big"
- "net/url"
- "testing"
- "time"
-
- "github.com/deepmap/oapi-codegen/pkg/types"
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-// MockBinder is just an independent version of Binder that has the Bind implemented
-type MockBinder struct {
- time.Time
-}
-
-func (d *MockBinder) Bind(src string) error {
- // Don't fail on empty string.
- if src == "" {
- return nil
- }
- parsedTime, err := time.Parse(types.DateFormat, src)
- if err != nil {
- return fmt.Errorf("error parsing '%s' as date: %s", src, err)
- }
- d.Time = parsedTime
- return nil
-}
-
-func (d MockBinder) MarshalJSON() ([]byte, error) {
- return json.Marshal(d.Time.Format(types.DateFormat))
-}
-
-func (d *MockBinder) UnmarshalJSON(data []byte) error {
- var dateStr string
- err := json.Unmarshal(data, &dateStr)
- if err != nil {
- return err
- }
- parsed, err := time.Parse(types.DateFormat, dateStr)
- if err != nil {
- return err
- }
- d.Time = parsed
- return nil
-}
-
-// EmbeddedMockBinder has an embedded MockBinder and so keeps the Binder Method from MockBinder.
-type EmbeddedMockBinder struct {
- MockBinder
-}
-
-// AnotherMockBinder is an entirely new type we have to create a bind method with it to implement Binder as well.
-type AnotherMockBinder MockBinder
-
-func (b *AnotherMockBinder) Bind(src string) error {
- // Don't fail on empty string.
- if src == "" {
- return nil
- }
- parsedTime, err := time.Parse(types.DateFormat, src)
- if err != nil {
- return fmt.Errorf("error parsing '%s' as date: %s", src, err)
- }
- b.Time = parsedTime
- return nil
-}
-
-func TestSplitParameter(t *testing.T) {
- // Please see the parameter serialization docs to understand these test
- // cases
-
- expectedPrimitive := []string{"5"}
- expectedArray := []string{"3", "4", "5"}
- expectedObject := []string{"role", "admin", "firstName", "Alex"}
- expectedExplodedObject := []string{"role=admin", "firstName=Alex"}
-
- var result []string
- var err error
- // ------------------------ simple style ---------------------------------
- result, err = splitStyledParameter("simple",
- false,
- false,
- "id",
- "5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedPrimitive, result)
-
- result, err = splitStyledParameter("simple",
- false,
- false,
- "id",
- "3,4,5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedArray, result)
-
- result, err = splitStyledParameter("simple",
- false,
- true,
- "id",
- "role,admin,firstName,Alex")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedObject, result)
-
- result, err = splitStyledParameter("simple",
- true,
- false,
- "id",
- "5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedPrimitive, result)
-
- result, err = splitStyledParameter("simple",
- true,
- false,
- "id",
- "3,4,5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedArray, result)
-
- result, err = splitStyledParameter("simple",
- true,
- true,
- "id",
- "role=admin,firstName=Alex")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedExplodedObject, result)
-
- // ------------------------ label style ---------------------------------
- result, err = splitStyledParameter("label",
- false,
- false,
- "id",
- ".5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedPrimitive, result)
-
- result, err = splitStyledParameter("label",
- false,
- false,
- "id",
- ".3,4,5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedArray, result)
-
- result, err = splitStyledParameter("label",
- false,
- true,
- "id",
- ".role,admin,firstName,Alex")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedObject, result)
-
- result, err = splitStyledParameter("label",
- true,
- false,
- "id",
- ".5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedPrimitive, result)
-
- result, err = splitStyledParameter("label",
- true,
- false,
- "id",
- ".3.4.5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedArray, result)
-
- result, err = splitStyledParameter("label",
- true,
- true,
- "id",
- ".role=admin.firstName=Alex")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedExplodedObject, result)
-
- // ------------------------ matrix style ---------------------------------
- result, err = splitStyledParameter("matrix",
- false,
- false,
- "id",
- ";id=5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedPrimitive, result)
-
- result, err = splitStyledParameter("matrix",
- false,
- false,
- "id",
- ";id=3,4,5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedArray, result)
-
- result, err = splitStyledParameter("matrix",
- false,
- true,
- "id",
- ";id=role,admin,firstName,Alex")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedObject, result)
-
- result, err = splitStyledParameter("matrix",
- true,
- false,
- "id",
- ";id=5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedPrimitive, result)
-
- result, err = splitStyledParameter("matrix",
- true,
- false,
- "id",
- ";id=3;id=4;id=5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedArray, result)
-
- result, err = splitStyledParameter("matrix",
- true,
- true,
- "id",
- ";role=admin;firstName=Alex")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedExplodedObject, result)
-
- // ------------------------ form style ---------------------------------
- result, err = splitStyledParameter("form",
- false,
- false,
- "id",
- "id=5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedPrimitive, result)
-
- result, err = splitStyledParameter("form",
- false,
- false,
- "id",
- "id=3,4,5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedArray, result)
-
- result, err = splitStyledParameter("form",
- false,
- true,
- "id",
- "id=role,admin,firstName,Alex")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedObject, result)
-
- result, err = splitStyledParameter("form",
- true,
- false,
- "id",
- "id=5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedPrimitive, result)
-
- result, err = splitStyledParameter("form",
- true,
- false,
- "id",
- "id=3&id=4&id=5")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedArray, result)
-
- result, err = splitStyledParameter("form",
- true,
- true,
- "id",
- "role=admin&firstName=Alex")
- assert.NoError(t, err)
- assert.EqualValues(t, expectedExplodedObject, result)
-}
-
-func TestBindQueryParameter(t *testing.T) {
- t.Run("deepObject", func(t *testing.T) {
- type ID struct {
- FirstName *string `json:"firstName"`
- LastName *string `json:"lastName"`
- Role string `json:"role"`
- Birthday *types.Date `json:"birthday"`
- Married *MockBinder `json:"married"`
- }
-
- expectedName := "Alex"
- expectedDeepObject := &ID{
- FirstName: &expectedName,
- Role: "admin",
- Birthday: &types.Date{Time: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)},
- Married: &MockBinder{time.Date(2020, 2, 2, 0, 0, 0, 0, time.UTC)},
- }
-
- actual := new(ID)
- paramName := "id"
- queryParams := url.Values{
- "id[firstName]": {"Alex"},
- "id[role]": {"admin"},
- "foo": {"bar"},
- "id[birthday]": {"2020-01-01"},
- "id[married]": {"2020-02-02"},
- }
-
- err := BindQueryParameter("deepObject", true, false, paramName, queryParams, &actual)
- assert.NoError(t, err)
- assert.Equal(t, expectedDeepObject, actual)
- })
-
- t.Run("form", func(t *testing.T) {
- expected := &MockBinder{Time: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)}
- birthday := &MockBinder{}
- queryParams := url.Values{
- "birthday": {"2020-01-01"},
- }
- err := BindQueryParameter("form", true, false, "birthday", queryParams, &birthday)
- assert.NoError(t, err)
- assert.Equal(t, expected, birthday)
- })
-
- t.Run("optional", func(t *testing.T) {
- queryParams := url.Values{
- "time": {"2020-12-09T16:09:53+00:00"},
- "number": {"100"},
- }
- // An optional time will be a pointer to a time in a parameter object
- var optionalTime *time.Time
- err := BindQueryParameter("form", true, false, "notfound", queryParams, &optionalTime)
- require.NoError(t, err)
- assert.Nil(t, optionalTime)
-
- var optionalNumber *int
- err = BindQueryParameter("form", true, false, "notfound", queryParams, &optionalNumber)
- require.NoError(t, err)
- assert.Nil(t, optionalNumber)
-
- // If we require values, we require errors when they're not present.
- err = BindQueryParameter("form", true, true, "notfound", queryParams, &optionalTime)
- assert.Error(t, err)
- err = BindQueryParameter("form", true, true, "notfound", queryParams, &optionalNumber)
- assert.Error(t, err)
-
- })
-}
-
-func TestBindParameterViaAlias(t *testing.T) {
- // We don't need to check every parameter format type here, since the binding
- // code is identical irrespective of parameter type, buy we do want to test
- // a bunch of types.
- type AString string
- type Aint int
- type Afloat float64
- type Atime = time.Time
- type Adate = MockBinder
-
- type AliasTortureTest struct {
- S AString `json:"s"`
- Sp *AString `json:"sp,omitempty"`
- I Aint `json:"i"`
- Ip *Aint `json:"ip,omitempty"`
- F Afloat `json:"f"`
- Fp *Afloat `json:"fp,omitempty"`
- T Atime `json:"t"`
- Tp *Atime `json:"tp,omitempty"`
- D Adate `json:"d"`
- Dp *Adate `json:"dp,omitempty"`
- }
-
- now := time.Now().UTC()
- later := now.Add(time.Hour)
-
- queryParams := url.Values{
- "alias[s]": {"str"},
- "alias[sp]": {"strp"},
- "alias[i]": {"1"},
- "alias[ip]": {"2"},
- "alias[f]": {"3.5"},
- "alias[fp]": {"4.5"},
- "alias[t]": {now.Format(time.RFC3339Nano)},
- "alias[tp]": {later.Format(time.RFC3339Nano)},
- "alias[d]": {"2020-11-06"},
- "alias[dp]": {"2020-11-07"},
- }
-
- dst := new(AliasTortureTest)
-
- err := BindQueryParameter("deepObject", true, false, "alias", queryParams, &dst)
- require.NoError(t, err)
-
- var sp AString = "strp"
- var ip Aint = 2
- var fp Afloat = 4.5
- dp := Adate{Time: time.Date(2020, 11, 7, 0, 0, 0, 0, time.UTC)}
-
- expected := AliasTortureTest{
- S: "str",
- Sp: &sp,
- I: 1,
- Ip: &ip,
- F: 3.5,
- Fp: &fp,
- T: now,
- Tp: &later,
- D: Adate{Time: time.Date(2020, 11, 6, 0, 0, 0, 0, time.UTC)},
- Dp: &dp,
- }
-
- // Compare field by field, makes errors easier to track.
- assert.EqualValues(t, expected.S, dst.S)
- assert.EqualValues(t, expected.Sp, dst.Sp)
- assert.EqualValues(t, expected.I, dst.I)
- assert.EqualValues(t, expected.Ip, dst.Ip)
- assert.EqualValues(t, expected.F, dst.F)
- assert.EqualValues(t, expected.Fp, dst.Fp)
- assert.EqualValues(t, expected.T, dst.T)
- assert.EqualValues(t, expected.Tp, dst.Tp)
- assert.EqualValues(t, expected.D, dst.D)
- assert.EqualValues(t, expected.Dp, dst.Dp)
-}
-
-// bindParamsToExplodedObject has to special case some types. Make sure that
-// these non-object types are handled correctly. The other parts of the functionality
-// are tested via more generic code above.
-func TestBindParamsToExplodedObject(t *testing.T) {
- now := time.Now().UTC()
- values := url.Values{
- "time": {now.Format(time.RFC3339Nano)},
- "date": {"2020-11-06"},
- }
-
- var dstTime time.Time
- fieldsPresent, err := bindParamsToExplodedObject("time", values, &dstTime)
- assert.NoError(t, err)
- assert.True(t, fieldsPresent)
- assert.EqualValues(t, now, dstTime)
-
- type AliasedTime time.Time
- var aDstTime AliasedTime
- fieldsPresent, err = bindParamsToExplodedObject("time", values, &aDstTime)
- assert.NoError(t, err)
- assert.True(t, fieldsPresent)
- assert.EqualValues(t, now, aDstTime)
-
- expectedDate := MockBinder{Time: time.Date(2020, 11, 6, 0, 0, 0, 0, time.UTC)}
-
- var dstDate MockBinder
- fieldsPresent, err = bindParamsToExplodedObject("date", values, &dstDate)
- assert.NoError(t, err)
- assert.True(t, fieldsPresent)
- assert.EqualValues(t, expectedDate, dstDate)
-
- var eDstDate EmbeddedMockBinder
- fieldsPresent, err = bindParamsToExplodedObject("date", values, &eDstDate)
- assert.NoError(t, err)
- assert.True(t, fieldsPresent)
- assert.EqualValues(t, expectedDate, dstDate)
-
- var nTDstDate AnotherMockBinder
- fieldsPresent, err = bindParamsToExplodedObject("date", values, &nTDstDate)
- assert.NoError(t, err)
- assert.True(t, fieldsPresent)
- assert.EqualValues(t, expectedDate, nTDstDate)
-
- type ObjectWithOptional struct {
- Time *time.Time `json:"time,omitempty"`
- }
-
- var optDstTime ObjectWithOptional
- fieldsPresent, err = bindParamsToExplodedObject("explodedObject", values, &optDstTime)
- assert.NoError(t, err)
- assert.True(t, fieldsPresent)
- assert.EqualValues(t, &now, optDstTime.Time)
-}
-
-func TestBindStyledParameterWithLocation(t *testing.T) {
- expectedBig := big.NewInt(12345678910)
-
- var dstBigNumber big.Int
- err := BindStyledParameterWithLocation("simple", false, "id", ParamLocationUndefined,
- "12345678910", &dstBigNumber)
- assert.NoError(t, err)
- assert.Equal(t, *expectedBig, dstBigNumber)
-}
diff --git a/pkg/runtime/bindstring.go b/pkg/runtime/bindstring.go
deleted file mode 100644
index 6b128c41e6..0000000000
--- a/pkg/runtime/bindstring.go
+++ /dev/null
@@ -1,176 +0,0 @@
-// Copyright 2019 DeepMap, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package runtime
-
-import (
- "encoding"
- "errors"
- "fmt"
- "reflect"
- "strconv"
- "time"
-
- "github.com/deepmap/oapi-codegen/pkg/types"
-)
-
-// BindStringToObject takes a string, and attempts to assign it to the destination
-// interface via whatever type conversion is necessary. We have to do this
-// via reflection instead of a much simpler type switch so that we can handle
-// type aliases. This function was the easy way out, the better way, since we
-// know the destination type each place that we use this, is to generate code
-// to read each specific type.
-//
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#BindStringToObject
-func BindStringToObject(src string, dst interface{}) error {
- var err error
-
- v := reflect.ValueOf(dst)
- t := reflect.TypeOf(dst)
-
- // We need to dereference pointers
- if t.Kind() == reflect.Ptr {
- v = reflect.Indirect(v)
- t = v.Type()
- }
-
- // For some optional args
- if t.Kind() == reflect.Ptr {
- if v.IsNil() {
- v.Set(reflect.New(t.Elem()))
- }
-
- v = reflect.Indirect(v)
- t = v.Type()
- }
-
- // The resulting type must be settable. reflect will catch issues like
- // passing the destination by value.
- if !v.CanSet() {
- return errors.New("destination is not settable")
- }
-
- switch t.Kind() {
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- var val int64
- val, err = strconv.ParseInt(src, 10, 64)
- if err == nil {
- if v.OverflowInt(val) {
- err = fmt.Errorf("value '%s' overflows destination of type: %s", src, t.Kind())
- }
- if err == nil {
- v.SetInt(val)
- }
- }
- case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
- var val uint64
- val, err = strconv.ParseUint(src, 10, 64)
- if err == nil {
- if v.OverflowUint(val) {
- err = fmt.Errorf("value '%s' overflows destination of type: %s", src, t.Kind())
- }
- v.SetUint(val)
- }
- case reflect.String:
- v.SetString(src)
- err = nil
- case reflect.Float64, reflect.Float32:
- var val float64
- val, err = strconv.ParseFloat(src, 64)
- if err == nil {
- if v.OverflowFloat(val) {
- err = fmt.Errorf("value '%s' overflows destination of type: %s", src, t.Kind())
- }
- v.SetFloat(val)
- }
- case reflect.Bool:
- var val bool
- val, err = strconv.ParseBool(src)
- if err == nil {
- v.SetBool(val)
- }
- case reflect.Array:
- if tu, ok := dst.(encoding.TextUnmarshaler); ok {
- if err := tu.UnmarshalText([]byte(src)); err != nil {
- return fmt.Errorf("error unmarshaling '%s' text as %T: %s", src, dst, err)
- }
-
- return nil
- }
- fallthrough
- case reflect.Struct:
- // if this is not of type Time or of type Date look to see if this is of type Binder.
- if dstType, ok := dst.(Binder); ok {
- return dstType.Bind(src)
- }
-
- if t.ConvertibleTo(reflect.TypeOf(time.Time{})) {
- // Don't fail on empty string.
- if src == "" {
- return nil
- }
- // Time is a special case of a struct that we handle
- parsedTime, err := time.Parse(time.RFC3339Nano, src)
- if err != nil {
- parsedTime, err = time.Parse(types.DateFormat, src)
- if err != nil {
- return fmt.Errorf("error parsing '%s' as RFC3339 or 2006-01-02 time: %s", src, err)
- }
- }
- // So, assigning this gets a little fun. We have a value to the
- // dereference destination. We can't do a conversion to
- // time.Time because the result isn't assignable, so we need to
- // convert pointers.
- if t != reflect.TypeOf(time.Time{}) {
- vPtr := v.Addr()
- vtPtr := vPtr.Convert(reflect.TypeOf(&time.Time{}))
- v = reflect.Indirect(vtPtr)
- }
- v.Set(reflect.ValueOf(parsedTime))
- return nil
- }
-
- if t.ConvertibleTo(reflect.TypeOf(types.Date{})) {
- // Don't fail on empty string.
- if src == "" {
- return nil
- }
- parsedTime, err := time.Parse(types.DateFormat, src)
- if err != nil {
- return fmt.Errorf("error parsing '%s' as date: %s", src, err)
- }
- parsedDate := types.Date{Time: parsedTime}
-
- // We have to do the same dance here to assign, just like with times
- // above.
- if t != reflect.TypeOf(types.Date{}) {
- vPtr := v.Addr()
- vtPtr := vPtr.Convert(reflect.TypeOf(&types.Date{}))
- v = reflect.Indirect(vtPtr)
- }
- v.Set(reflect.ValueOf(parsedDate))
- return nil
- }
-
- // We fall through to the error case below if we haven't handled the
- // destination type above.
- fallthrough
- default:
- // We've got a bunch of types unimplemented, don't fail silently.
- err = fmt.Errorf("can not bind to destination of type: %s", t.Kind())
- }
- if err != nil {
- return fmt.Errorf("error binding string parameter: %w", err)
- }
- return nil
-}
diff --git a/pkg/runtime/bindstring_test.go b/pkg/runtime/bindstring_test.go
deleted file mode 100644
index 0ce0914bde..0000000000
--- a/pkg/runtime/bindstring_test.go
+++ /dev/null
@@ -1,211 +0,0 @@
-// Copyright 2019 DeepMap, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package runtime
-
-import (
- "fmt"
- "math"
- "testing"
- "time"
-
- "github.com/deepmap/oapi-codegen/pkg/types"
- "github.com/stretchr/testify/assert"
-)
-
-func TestBindStringToObject(t *testing.T) {
- var i int
- assert.NoError(t, BindStringToObject("5", &i))
- assert.Equal(t, 5, i)
-
- // Let's make sure we error out on things that can't be the correct
- // type. Since we're using reflect package setters, we'll have similar
- // unassignable type errors.
- assert.Error(t, BindStringToObject("5.7", &i))
- assert.Error(t, BindStringToObject("foo", &i))
- assert.Error(t, BindStringToObject("1,2,3", &i))
-
- var i8 int8
- assert.NoError(t, BindStringToObject("12", &i8))
- assert.Equal(t, int8(12), i8)
- assert.NoError(t, BindStringToObject("-12", &i8))
- assert.Equal(t, int8(-12), i8)
-
- assert.Error(t, BindStringToObject("5.7", &i8))
- assert.Error(t, BindStringToObject("foo", &i8))
- assert.Error(t, BindStringToObject("1,2,3", &i8))
- assert.Error(t, BindStringToObject(fmt.Sprintf("%d", math.MinInt8-1), &i8))
- assert.Error(t, BindStringToObject(fmt.Sprintf("%d", math.MaxInt8+1), &i8))
-
- var i16 int16
- assert.NoError(t, BindStringToObject("12", &i16))
- assert.Equal(t, int16(12), i16)
- assert.NoError(t, BindStringToObject("-12", &i16))
- assert.Equal(t, int16(-12), i16)
-
- assert.Error(t, BindStringToObject("5.7", &i16))
- assert.Error(t, BindStringToObject("foo", &i16))
- assert.Error(t, BindStringToObject("1,2,3", &i16))
- assert.Error(t, BindStringToObject(fmt.Sprintf("%d", math.MinInt16-1), &i16))
- assert.Error(t, BindStringToObject(fmt.Sprintf("%d", math.MaxInt16+1), &i16))
-
- var i32 int32
- assert.NoError(t, BindStringToObject("12", &i32))
- assert.Equal(t, int32(12), i32)
- assert.NoError(t, BindStringToObject("-12", &i32))
- assert.Equal(t, int32(-12), i32)
-
- assert.Error(t, BindStringToObject("5.7", &i32))
- assert.Error(t, BindStringToObject("foo", &i32))
- assert.Error(t, BindStringToObject("1,2,3", &i32))
- assert.Error(t, BindStringToObject(fmt.Sprintf("%d", math.MinInt32-1), &i32))
- assert.Error(t, BindStringToObject(fmt.Sprintf("%d", math.MaxInt32+1), &i32))
-
- var i64 int64
- assert.NoError(t, BindStringToObject("124", &i64))
- assert.Equal(t, int64(124), i64)
- assert.NoError(t, BindStringToObject("-124", &i64))
- assert.Equal(t, int64(-124), i64)
-
- assert.Error(t, BindStringToObject("5.7", &i64))
- assert.Error(t, BindStringToObject("foo", &i64))
- assert.Error(t, BindStringToObject("1,2,3", &i64))
- assert.Error(t, BindStringToObject("-9223372036854775809", &i64))
- assert.Error(t, BindStringToObject("9223372036854775808", &i64)) // 1<<63
-
- var u uint
- assert.NoError(t, BindStringToObject("5", &u))
- assert.Equal(t, uint(5), u)
-
- assert.Error(t, BindStringToObject("-5", &u))
- assert.Error(t, BindStringToObject("5.7", &u))
- assert.Error(t, BindStringToObject("foo", &u))
- assert.Error(t, BindStringToObject("1,2,3", &u))
-
- var u8 uint8
- assert.NoError(t, BindStringToObject("12", &u8))
- assert.Equal(t, uint8(12), u8)
-
- assert.Error(t, BindStringToObject("-5", &u8))
- assert.Error(t, BindStringToObject("5.7", &u8))
- assert.Error(t, BindStringToObject("foo", &u8))
- assert.Error(t, BindStringToObject("1,2,3", &u8))
- assert.Error(t, BindStringToObject(fmt.Sprintf("%d", math.MaxUint8+1), &i8))
-
- var u16 uint16
- assert.NoError(t, BindStringToObject("12", &u16))
- assert.Equal(t, uint16(12), u16)
-
- assert.Error(t, BindStringToObject("-5", &u16))
- assert.Error(t, BindStringToObject("5.7", &u16))
- assert.Error(t, BindStringToObject("foo", &u16))
- assert.Error(t, BindStringToObject("1,2,3", &u16))
- assert.Error(t, BindStringToObject(fmt.Sprintf("%d", math.MaxUint16+1), &i16))
-
- var u32 uint32
- assert.NoError(t, BindStringToObject("12", &u32))
- assert.Equal(t, uint32(12), u32)
-
- assert.Error(t, BindStringToObject("-5", &u32))
- assert.Error(t, BindStringToObject("5.7", &u32))
- assert.Error(t, BindStringToObject("foo", &u32))
- assert.Error(t, BindStringToObject("1,2,3", &u32))
- assert.Error(t, BindStringToObject(fmt.Sprintf("%d", math.MaxUint32+1), &i32))
-
- var u64 uint64
- assert.NoError(t, BindStringToObject("124", &u64))
- assert.Equal(t, uint64(124), u64)
-
- assert.Error(t, BindStringToObject("-5", &u64))
- assert.Error(t, BindStringToObject("5.7", &u64))
- assert.Error(t, BindStringToObject("foo", &u64))
- assert.Error(t, BindStringToObject("1,2,3", &u64))
- assert.Error(t, BindStringToObject("18446744073709551616", &i64)) // 1<<64
-
- var b bool
- assert.NoError(t, BindStringToObject("True", &b))
- assert.Equal(t, true, b)
- assert.NoError(t, BindStringToObject("true", &b))
- assert.Equal(t, true, b)
- assert.NoError(t, BindStringToObject("1", &b))
- assert.Equal(t, true, b)
- assert.NoError(t, BindStringToObject("0", &b))
- assert.Equal(t, false, b)
- assert.Error(t, BindStringToObject("-1", &b))
- assert.Error(t, BindStringToObject("hello", &b))
-
- var f64 float64
- assert.NoError(t, BindStringToObject("1.25", &f64))
- assert.Equal(t, float64(1.25), f64)
-
- assert.Error(t, BindStringToObject("foo", &f64))
- assert.Error(t, BindStringToObject("1,2,3", &f64))
-
- var f32 float32
- assert.NoError(t, BindStringToObject("3.125", &f32))
- assert.Equal(t, float32(3.125), f32)
-
- assert.Error(t, BindStringToObject("foo", &f32))
- assert.Error(t, BindStringToObject("1,2,3", &f32))
- assert.NoError(t, BindStringToObject(fmt.Sprintf("%f", math.MaxFloat32), &f32))
- assert.Error(t, BindStringToObject(fmt.Sprintf("%f", math.MaxFloat32*2), &f32))
-
- // This checks whether binding works through a type alias.
- type SomeType int
- var st SomeType
- assert.NoError(t, BindStringToObject("5", &st))
- assert.Equal(t, SomeType(5), st)
-
- // Check time binding
- now := time.Now().UTC()
- strTime := now.Format(time.RFC3339Nano)
- var parsedTime time.Time
- assert.NoError(t, BindStringToObject(strTime, &parsedTime))
- parsedTime = parsedTime.UTC()
- assert.EqualValues(t, now, parsedTime)
-
- now = now.Truncate(time.Second)
- strTime = now.Format(time.RFC3339)
- assert.NoError(t, BindStringToObject(strTime, &parsedTime))
- parsedTime = parsedTime.UTC()
- assert.EqualValues(t, now, parsedTime)
-
- // Checks whether time binding works through a type alias.
- type AliasedTime time.Time
- var aliasedTime AliasedTime
- assert.NoError(t, BindStringToObject(strTime, &aliasedTime))
- assert.EqualValues(t, now, aliasedTime)
-
- // Checks whether date binding works directly and through an alias.
- dateString := "2020-11-05"
- var dstDate types.Date
- assert.NoError(t, BindStringToObject(dateString, &dstDate))
- type AliasedDate types.Date
- var dstAliasedDate AliasedDate
- assert.NoError(t, BindStringToObject(dateString, &dstAliasedDate))
-
- // Checks whether a mock binder works and embedded types
- var mockBinder MockBinder
- assert.NoError(t, BindStringToObject(dateString, &mockBinder))
- assert.EqualValues(t, dateString, mockBinder.Time.Format("2006-01-02"))
- var dstEmbeddedMockBinder EmbeddedMockBinder
- assert.NoError(t, BindStringToObject(dateString, &dstEmbeddedMockBinder))
- assert.EqualValues(t, dateString, dstEmbeddedMockBinder.Time.Format("2006-01-02"))
-
- // Checks UUID binding
- uuidString := "bbca1470-5e1f-4c64-ba99-fa7a6d2687b0"
- var dstUUID types.UUID
- assert.NoError(t, BindStringToObject(uuidString, &dstUUID))
- assert.Equal(t, dstUUID.String(), uuidString)
-
-}
diff --git a/pkg/runtime/deepobject.go b/pkg/runtime/deepobject.go
deleted file mode 100644
index 15394540ff..0000000000
--- a/pkg/runtime/deepobject.go
+++ /dev/null
@@ -1,373 +0,0 @@
-package runtime
-
-import (
- "encoding/json"
- "errors"
- "fmt"
- "net/url"
- "reflect"
- "sort"
- "strconv"
- "strings"
- "time"
-
- "github.com/deepmap/oapi-codegen/pkg/types"
-)
-
-func marshalDeepObject(in interface{}, path []string) ([]string, error) {
- var result []string
-
- switch t := in.(type) {
- case []interface{}:
- // For the array, we will use numerical subscripts of the form [x],
- // in the same order as the array.
- for i, iface := range t {
- newPath := append(path, strconv.Itoa(i))
- fields, err := marshalDeepObject(iface, newPath)
- if err != nil {
- return nil, fmt.Errorf("error traversing array: %w", err)
- }
- result = append(result, fields...)
- }
- case map[string]interface{}:
- // For a map, each key (field name) becomes a member of the path, and
- // we recurse. First, sort the keys.
- keys := make([]string, len(t))
- i := 0
- for k := range t {
- keys[i] = k
- i++
- }
- sort.Strings(keys)
-
- // Now, for each key, we recursively marshal it.
- for _, k := range keys {
- newPath := append(path, k)
- fields, err := marshalDeepObject(t[k], newPath)
- if err != nil {
- return nil, fmt.Errorf("error traversing map: %w", err)
- }
- result = append(result, fields...)
- }
- default:
- // Now, for a concrete value, we will turn the path elements
- // into a deepObject style set of subscripts. [a, b, c] turns into
- // [a][b][c]
- prefix := "[" + strings.Join(path, "][") + "]"
- result = []string{
- prefix + fmt.Sprintf("=%v", t),
- }
- }
- return result, nil
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#MarshalDeepObject
-func MarshalDeepObject(i interface{}, paramName string) (string, error) {
- // We're going to marshal to JSON and unmarshal into an interface{},
- // which will use the json pkg to deal with all the field annotations. We
- // can then walk the generic object structure to produce a deepObject. This
- // isn't efficient and it would be more efficient to reflect on our own,
- // but it's complicated, error-prone code.
- buf, err := json.Marshal(i)
- if err != nil {
- return "", fmt.Errorf("failed to marshal input to JSON: %w", err)
- }
- var i2 interface{}
- err = json.Unmarshal(buf, &i2)
- if err != nil {
- return "", fmt.Errorf("failed to unmarshal JSON: %w", err)
- }
- fields, err := marshalDeepObject(i2, nil)
- if err != nil {
- return "", fmt.Errorf("error traversing JSON structure: %w", err)
- }
-
- // Prefix the param name to each subscripted field.
- for i := range fields {
- fields[i] = paramName + fields[i]
- }
- return strings.Join(fields, "&"), nil
-}
-
-type fieldOrValue struct {
- fields map[string]fieldOrValue
- value string
-}
-
-func (f *fieldOrValue) appendPathValue(path []string, value string) {
- fieldName := path[0]
- if len(path) == 1 {
- f.fields[fieldName] = fieldOrValue{value: value}
- return
- }
-
- pv, found := f.fields[fieldName]
- if !found {
- pv = fieldOrValue{
- fields: make(map[string]fieldOrValue),
- }
- f.fields[fieldName] = pv
- }
- pv.appendPathValue(path[1:], value)
-}
-
-func makeFieldOrValue(paths [][]string, values []string) fieldOrValue {
-
- f := fieldOrValue{
- fields: make(map[string]fieldOrValue),
- }
- for i := range paths {
- path := paths[i]
- value := values[i]
- f.appendPathValue(path, value)
- }
- return f
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#UnmarshalDeepObject
-func UnmarshalDeepObject(dst interface{}, paramName string, params url.Values) error {
- // Params are all the query args, so we need those that look like
- // "paramName["...
- var fieldNames []string
- var fieldValues []string
- searchStr := paramName + "["
- for pName, pValues := range params {
- if strings.HasPrefix(pName, searchStr) {
- // trim the parameter name from the full name.
- pName = pName[len(paramName):]
- fieldNames = append(fieldNames, pName)
- if len(pValues) != 1 {
- return fmt.Errorf("%s has multiple values", pName)
- }
- fieldValues = append(fieldValues, pValues[0])
- }
- }
-
- // Now, for each field, reconstruct its subscript path and value
- paths := make([][]string, len(fieldNames))
- for i, path := range fieldNames {
- path = strings.TrimLeft(path, "[")
- path = strings.TrimRight(path, "]")
- paths[i] = strings.Split(path, "][")
- }
-
- fieldPaths := makeFieldOrValue(paths, fieldValues)
- err := assignPathValues(dst, fieldPaths)
- if err != nil {
- return fmt.Errorf("error assigning value to destination: %w", err)
- }
-
- return nil
-}
-
-// This returns a field name, either using the variable name, or the json
-// annotation if that exists.
-func getFieldName(f reflect.StructField) string {
- n := f.Name
- tag, found := f.Tag.Lookup("json")
- if found {
- // If we have a json field, and the first part of it before the
- // first comma is non-empty, that's our field name.
- parts := strings.Split(tag, ",")
- if parts[0] != "" {
- n = parts[0]
- }
- }
- return n
-}
-
-// Create a map of field names that we'll see in the deepObject to reflect
-// field indices on the given type.
-func fieldIndicesByJsonTag(i interface{}) (map[string]int, error) {
- t := reflect.TypeOf(i)
- if t.Kind() != reflect.Struct {
- return nil, errors.New("expected a struct as input")
- }
-
- n := t.NumField()
- fieldMap := make(map[string]int)
- for i := 0; i < n; i++ {
- field := t.Field(i)
- fieldName := getFieldName(field)
- fieldMap[fieldName] = i
- }
- return fieldMap, nil
-}
-
-func assignPathValues(dst interface{}, pathValues fieldOrValue) error {
- //t := reflect.TypeOf(dst)
- v := reflect.ValueOf(dst)
-
- iv := reflect.Indirect(v)
- it := iv.Type()
-
- switch it.Kind() {
- case reflect.Map:
- dstMap := reflect.MakeMap(iv.Type())
- for key, value := range pathValues.fields {
- dstKey := reflect.ValueOf(key)
- dstVal := reflect.New(iv.Type().Elem())
- err := assignPathValues(dstVal.Interface(), value)
- if err != nil {
- return fmt.Errorf("error binding map: %w", err)
- }
- dstMap.SetMapIndex(dstKey, dstVal.Elem())
- }
- iv.Set(dstMap)
- return nil
- case reflect.Slice:
- sliceLength := len(pathValues.fields)
- dstSlice := reflect.MakeSlice(it, sliceLength, sliceLength)
- err := assignSlice(dstSlice, pathValues)
- if err != nil {
- return fmt.Errorf("error assigning slice: %w", err)
- }
- iv.Set(dstSlice)
- return nil
- case reflect.Struct:
- // Some special types we care about are structs. Handle them
- // here. They may be redefined, so we need to do some hoop
- // jumping. If the types are aliased, we need to type convert
- // the pointer, then set the value of the dereference pointer.
-
- // We check to see if the object implements the Binder interface first.
- if dst, isBinder := v.Interface().(Binder); isBinder {
- return dst.Bind(pathValues.value)
- }
- // Then check the legacy types
- if it.ConvertibleTo(reflect.TypeOf(types.Date{})) {
- var date types.Date
- var err error
- date.Time, err = time.Parse(types.DateFormat, pathValues.value)
- if err != nil {
- return fmt.Errorf("invalid date format: %w", err)
- }
- dst := iv
- if it != reflect.TypeOf(types.Date{}) {
- // Types are aliased, convert the pointers.
- ivPtr := iv.Addr()
- aPtr := ivPtr.Convert(reflect.TypeOf(&types.Date{}))
- dst = reflect.Indirect(aPtr)
- }
- dst.Set(reflect.ValueOf(date))
- }
- if it.ConvertibleTo(reflect.TypeOf(time.Time{})) {
- var tm time.Time
- var err error
- tm, err = time.Parse(time.RFC3339Nano, pathValues.value)
- if err != nil {
- // Fall back to parsing it as a date.
- // TODO: why is this marked as an ineffassign?
- tm, err = time.Parse(types.DateFormat, pathValues.value) //nolint:ineffassign,staticcheck
- if err != nil {
- return fmt.Errorf("error parsing '%s' as RFC3339 or 2006-01-02 time: %s", pathValues.value, err)
- }
- return fmt.Errorf("invalid date format: %w", err)
- }
- dst := iv
- if it != reflect.TypeOf(time.Time{}) {
- // Types are aliased, convert the pointers.
- ivPtr := iv.Addr()
- aPtr := ivPtr.Convert(reflect.TypeOf(&time.Time{}))
- dst = reflect.Indirect(aPtr)
- }
- dst.Set(reflect.ValueOf(tm))
- }
- fieldMap, err := fieldIndicesByJsonTag(iv.Interface())
- if err != nil {
- return fmt.Errorf("failed enumerating fields: %w", err)
- }
- for _, fieldName := range sortedFieldOrValueKeys(pathValues.fields) {
- fieldValue := pathValues.fields[fieldName]
- fieldIndex, found := fieldMap[fieldName]
- if !found {
- return fmt.Errorf("field [%s] is not present in destination object", fieldName)
- }
- field := iv.Field(fieldIndex)
- err = assignPathValues(field.Addr().Interface(), fieldValue)
- if err != nil {
- return fmt.Errorf("error assigning field [%s]: %w", fieldName, err)
- }
- }
- return nil
- case reflect.Ptr:
- // If we have a pointer after redirecting, it means we're dealing with
- // an optional field, such as *string, which was passed in as &foo. We
- // will allocate it if necessary, and call ourselves with a different
- // interface.
- dstVal := reflect.New(it.Elem())
- dstPtr := dstVal.Interface()
- err := assignPathValues(dstPtr, pathValues)
- iv.Set(dstVal)
- return err
- case reflect.Bool:
- val, err := strconv.ParseBool(pathValues.value)
- if err != nil {
- return fmt.Errorf("expected a valid bool, got %s", pathValues.value)
- }
- iv.SetBool(val)
- return nil
- case reflect.Float32:
- val, err := strconv.ParseFloat(pathValues.value, 32)
- if err != nil {
- return fmt.Errorf("expected a valid float, got %s", pathValues.value)
- }
- iv.SetFloat(val)
- return nil
- case reflect.Float64:
- val, err := strconv.ParseFloat(pathValues.value, 64)
- if err != nil {
- return fmt.Errorf("expected a valid float, got %s", pathValues.value)
- }
- iv.SetFloat(val)
- return nil
- case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
- val, err := strconv.ParseInt(pathValues.value, 10, 64)
- if err != nil {
- return fmt.Errorf("expected a valid int, got %s", pathValues.value)
- }
- iv.SetInt(val)
- return nil
- case reflect.String:
- iv.SetString(pathValues.value)
- return nil
- default:
- return errors.New("unhandled type: " + it.String())
- }
-}
-
-func assignSlice(dst reflect.Value, pathValues fieldOrValue) error {
- // Gather up the values
- nValues := len(pathValues.fields)
- values := make([]string, nValues)
- // We expect to have consecutive array indices in the map
- for i := 0; i < nValues; i++ {
- indexStr := strconv.Itoa(i)
- fv, found := pathValues.fields[indexStr]
- if !found {
- return errors.New("array deepObjects must have consecutive indices")
- }
- values[i] = fv.value
- }
-
- // This could be cleaner, but we can call into assignPathValues to
- // avoid recreating this logic.
- for i := 0; i < nValues; i++ {
- dstElem := dst.Index(i).Addr()
- err := assignPathValues(dstElem.Interface(), fieldOrValue{value: values[i]})
- if err != nil {
- return fmt.Errorf("error binding array: %w", err)
- }
- }
-
- return nil
-}
-
-func sortedFieldOrValueKeys(m map[string]fieldOrValue) []string {
- keys := make([]string, 0, len(m))
- for k := range m {
- keys = append(keys, k)
- }
- sort.Strings(keys)
- return keys
-}
diff --git a/pkg/runtime/deepobject_test.go b/pkg/runtime/deepobject_test.go
deleted file mode 100644
index 237673ad31..0000000000
--- a/pkg/runtime/deepobject_test.go
+++ /dev/null
@@ -1,86 +0,0 @@
-package runtime
-
-import (
- "net/url"
- "strings"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-type InnerObject struct {
- Name string
- ID int
-}
-
-// These are all possible field types, mandatory and optional.
-type AllFields struct {
- I int `json:"i"`
- Oi *int `json:"oi,omitempty"`
- F float32 `json:"f"`
- Of *float32 `json:"of,omitempty"`
- B bool `json:"b"`
- Ob *bool `json:"ob,omitempty"`
- As []string `json:"as"`
- Oas *[]string `json:"oas,omitempty"`
- O InnerObject `json:"o"`
- Oo *InnerObject `json:"oo,omitempty"`
- D MockBinder `json:"d"`
- Od *MockBinder `json:"od,omitempty"`
- M map[string]int `json:"m"`
- Om *map[string]int `json:"om,omitempty"`
-}
-
-func TestDeepObject(t *testing.T) {
- oi := int(5)
- of := float32(3.7)
- ob := true
- oas := []string{"foo", "bar"}
- oo := InnerObject{
- Name: "Marcin Romaszewicz",
- ID: 123,
- }
- om := map[string]int{
- "additional": 1,
- }
- d := MockBinder{Time: time.Date(2020, 2, 1, 0, 0, 0, 0, time.UTC)}
-
- srcObj := AllFields{
- I: 12,
- Oi: &oi,
- F: 4.2,
- Of: &of,
- B: true,
- Ob: &ob,
- As: []string{"hello", "world"},
- Oas: &oas,
- O: InnerObject{
- Name: "Joe Schmoe",
- ID: 456,
- },
- Oo: &oo,
- D: d,
- Od: &d,
- M: om,
- Om: &om,
- }
-
- marshaled, err := MarshalDeepObject(srcObj, "p")
- require.NoError(t, err)
- t.Log(marshaled)
-
- params := make(url.Values)
- marshaledParts := strings.Split(marshaled, "&")
- for _, p := range marshaledParts {
- parts := strings.Split(p, "=")
- require.Equal(t, 2, len(parts))
- params.Set(parts[0], parts[1])
- }
-
- var dstObj AllFields
- err = UnmarshalDeepObject(&dstObj, "p", params)
- require.NoError(t, err)
- assert.EqualValues(t, srcObj, dstObj)
-}
diff --git a/pkg/runtime/jsonmerge.go b/pkg/runtime/jsonmerge.go
deleted file mode 100644
index 3be61fcf0a..0000000000
--- a/pkg/runtime/jsonmerge.go
+++ /dev/null
@@ -1,28 +0,0 @@
-package runtime
-
-import (
- "encoding/json"
-
- "github.com/apapsch/go-jsonmerge/v2"
-)
-
-// JsonMerge merges two JSON representation into a single object. `data` is the
-// existing representation and `patch` is the new data to be merged in
-//
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#JsonMerge
-func JsonMerge(data, patch json.RawMessage) (json.RawMessage, error) {
- merger := jsonmerge.Merger{
- CopyNonexistent: true,
- }
- if data == nil {
- data = []byte(`{}`)
- }
- if patch == nil {
- patch = []byte(`{}`)
- }
- merged, err := merger.MergeBytes(data, patch)
- if err != nil {
- return nil, err
- }
- return merged, nil
-}
diff --git a/pkg/runtime/jsonmerge_test.go b/pkg/runtime/jsonmerge_test.go
deleted file mode 100644
index 8ec8dd7107..0000000000
--- a/pkg/runtime/jsonmerge_test.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package runtime
-
-import (
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestJsonMerge(t *testing.T) {
- t.Run("when object", func(t *testing.T) {
- t.Run("Merges properties defined in both objects", func(t *testing.T) {
- data := `{"foo": 1}`
- patch := `{"foo": null}`
- expected := `{"foo":null}`
-
- actual, err := JsonMerge([]byte(data), []byte(patch))
- assert.NoError(t, err)
- assert.Equal(t, expected, string(actual))
- })
-
- t.Run("Sets property defined in only src object", func(t *testing.T) {
- data := `{}`
- patch := `{"source":"merge-me"}`
- expected := `{"source":"merge-me"}`
-
- actual, err := JsonMerge([]byte(data), []byte(patch))
- assert.NoError(t, err)
- assert.Equal(t, expected, string(actual))
- })
-
- t.Run("Handles child objects", func(t *testing.T) {
- data := `{"channel":{"status":"valid"}}`
- patch := `{"channel":{"id":1}}`
- expected := `{"channel":{"id":1,"status":"valid"}}`
-
- actual, err := JsonMerge([]byte(data), []byte(patch))
- assert.NoError(t, err)
- assert.Equal(t, expected, string(actual))
- })
-
- t.Run("Handles empty objects", func(t *testing.T) {
- data := `{}`
- patch := `{}`
- expected := `{}`
-
- actual, err := JsonMerge([]byte(data), []byte(patch))
- assert.NoError(t, err)
- assert.Equal(t, expected, string(actual))
- })
-
- t.Run("Handles nil data", func(t *testing.T) {
- patch := `{"foo":"bar"}`
- expected := `{"foo":"bar"}`
-
- actual, err := JsonMerge(nil, []byte(patch))
- assert.NoError(t, err)
- assert.Equal(t, expected, string(actual))
- })
-
- t.Run("Handles nil patch", func(t *testing.T) {
- data := `{"foo":"bar"}`
- expected := `{"foo":"bar"}`
-
- actual, err := JsonMerge([]byte(data), nil)
- assert.NoError(t, err)
- assert.Equal(t, expected, string(actual))
- })
- })
- t.Run("when array", func(t *testing.T) {
- t.Run("it does not merge", func(t *testing.T) {
- data := `[{"foo": 1}]`
- patch := `[{"foo": null}]`
- expected := `[{"foo":1}]`
-
- actual, err := JsonMerge([]byte(data), []byte(patch))
- assert.NoError(t, err)
- assert.Equal(t, expected, string(actual))
- })
- })
-}
diff --git a/pkg/runtime/strictmiddleware.go b/pkg/runtime/strictmiddleware.go
deleted file mode 100644
index 894eba1e67..0000000000
--- a/pkg/runtime/strictmiddleware.go
+++ /dev/null
@@ -1,34 +0,0 @@
-package runtime
-
-import (
- "context"
- "net/http"
-
- "github.com/gin-gonic/gin"
- "github.com/kataras/iris/v12"
- "github.com/labstack/echo/v4"
-)
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/strictmiddleware/iris#StrictIrisHandlerFunc
-type StrictIrisHandlerFunc func(ctx iris.Context, request interface{}) (response interface{}, err error)
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/strictmiddleware/iris#StrictIrisMiddlewareFunc
-type StrictIrisMiddlewareFunc func(f StrictIrisHandlerFunc, operationID string) StrictIrisHandlerFunc
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/strictmiddleware/echo#StrictEchoHandlerFunc
-type StrictEchoHandlerFunc func(ctx echo.Context, request interface{}) (response interface{}, err error)
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/strictmiddleware/echo#StrictEchoMiddlewareFunc
-type StrictEchoMiddlewareFunc func(f StrictEchoHandlerFunc, operationID string) StrictEchoHandlerFunc
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/strictmiddleware/nethttp#StrictHttpHandlerFunc
-type StrictHttpHandlerFunc func(ctx context.Context, w http.ResponseWriter, r *http.Request, request interface{}) (response interface{}, err error)
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/strictmiddleware/nethttp#StrictHttpMiddlewareFunc
-type StrictHttpMiddlewareFunc func(f StrictHttpHandlerFunc, operationID string) StrictHttpHandlerFunc
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/strictmiddleware/gin#StrictGinHandlerFunc
-type StrictGinHandlerFunc func(ctx *gin.Context, request interface{}) (response interface{}, err error)
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/strictmiddleware/gin#StrictGinMiddlewareFunc
-type StrictGinMiddlewareFunc func(f StrictGinHandlerFunc, operationID string) StrictGinHandlerFunc
diff --git a/pkg/runtime/styleparam.go b/pkg/runtime/styleparam.go
deleted file mode 100644
index 3e2ed0ccc5..0000000000
--- a/pkg/runtime/styleparam.go
+++ /dev/null
@@ -1,483 +0,0 @@
-// Copyright 2019 DeepMap, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package runtime
-
-import (
- "bytes"
- "encoding"
- "encoding/json"
- "errors"
- "fmt"
- "net/url"
- "reflect"
- "sort"
- "strconv"
- "strings"
- "time"
-
- "github.com/deepmap/oapi-codegen/pkg/types"
- "github.com/google/uuid"
-)
-
-// Parameter escaping works differently based on where a header is found
-//
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#ParamLocation
-type ParamLocation int
-
-const (
- ParamLocationUndefined ParamLocation = iota
- ParamLocationQuery
- ParamLocationPath
- ParamLocationHeader
- ParamLocationCookie
-)
-
-// StyleParam is used by older generated code, and must remain compatible
-// with that code. It is not to be used in new templates. Please see the
-// function below, which can specialize its output based on the location of
-// the parameter.
-//
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#StyleParam
-func StyleParam(style string, explode bool, paramName string, value interface{}) (string, error) {
- return StyleParamWithLocation(style, explode, paramName, ParamLocationUndefined, value)
-}
-
-// Given an input value, such as a primitive type, array or object, turn it
-// into a parameter based on style/explode definition, performing whatever
-// escaping is necessary based on parameter location
-//
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime#StyleParam
-func StyleParamWithLocation(style string, explode bool, paramName string, paramLocation ParamLocation, value interface{}) (string, error) {
- t := reflect.TypeOf(value)
- v := reflect.ValueOf(value)
-
- // Things may be passed in by pointer, we need to dereference, so return
- // error on nil.
- if t.Kind() == reflect.Ptr {
- if v.IsNil() {
- return "", fmt.Errorf("value is a nil pointer")
- }
- v = reflect.Indirect(v)
- t = v.Type()
- }
-
- // If the value implements encoding.TextMarshaler we use it for marshaling
- // https://github.com/deepmap/oapi-codegen/issues/504
- if tu, ok := value.(encoding.TextMarshaler); ok {
- t := reflect.Indirect(reflect.ValueOf(value)).Type()
- convertableToTime := t.ConvertibleTo(reflect.TypeOf(time.Time{}))
- convertableToDate := t.ConvertibleTo(reflect.TypeOf(types.Date{}))
-
- // Since both time.Time and types.Date implement encoding.TextMarshaler
- // we should avoid calling theirs MarshalText()
- if !convertableToTime && !convertableToDate {
- b, err := tu.MarshalText()
- if err != nil {
- return "", fmt.Errorf("error marshaling '%s' as text: %s", value, err)
- }
-
- return stylePrimitive(style, explode, paramName, paramLocation, string(b))
- }
- }
-
- switch t.Kind() {
- case reflect.Slice:
- n := v.Len()
- sliceVal := make([]interface{}, n)
- for i := 0; i < n; i++ {
- sliceVal[i] = v.Index(i).Interface()
- }
- return styleSlice(style, explode, paramName, paramLocation, sliceVal)
- case reflect.Struct:
- return styleStruct(style, explode, paramName, paramLocation, value)
- case reflect.Map:
- return styleMap(style, explode, paramName, paramLocation, value)
- default:
- return stylePrimitive(style, explode, paramName, paramLocation, value)
- }
-}
-
-func styleSlice(style string, explode bool, paramName string, paramLocation ParamLocation, values []interface{}) (string, error) {
- if style == "deepObject" {
- if !explode {
- return "", errors.New("deepObjects must be exploded")
- }
- return MarshalDeepObject(values, paramName)
- }
-
- var prefix string
- var separator string
-
- switch style {
- case "simple":
- separator = ","
- case "label":
- prefix = "."
- if explode {
- separator = "."
- } else {
- separator = ","
- }
- case "matrix":
- prefix = fmt.Sprintf(";%s=", paramName)
- if explode {
- separator = prefix
- } else {
- separator = ","
- }
- case "form":
- prefix = fmt.Sprintf("%s=", paramName)
- if explode {
- separator = "&" + prefix
- } else {
- separator = ","
- }
- case "spaceDelimited":
- prefix = fmt.Sprintf("%s=", paramName)
- if explode {
- separator = "&" + prefix
- } else {
- separator = " "
- }
- case "pipeDelimited":
- prefix = fmt.Sprintf("%s=", paramName)
- if explode {
- separator = "&" + prefix
- } else {
- separator = "|"
- }
- default:
- return "", fmt.Errorf("unsupported style '%s'", style)
- }
-
- // We're going to assume here that the array is one of simple types.
- var err error
- var part string
- parts := make([]string, len(values))
- for i, v := range values {
- part, err = primitiveToString(v)
- part = escapeParameterString(part, paramLocation)
- parts[i] = part
- if err != nil {
- return "", fmt.Errorf("error formatting '%s': %s", paramName, err)
- }
- }
- return prefix + strings.Join(parts, separator), nil
-}
-
-func sortedKeys(strMap map[string]string) []string {
- keys := make([]string, len(strMap))
- i := 0
- for k := range strMap {
- keys[i] = k
- i++
- }
- sort.Strings(keys)
- return keys
-}
-
-// These are special cases. The value may be a date, time, or uuid,
-// in which case, marshal it into the correct format.
-func marshalKnownTypes(value interface{}) (string, bool) {
- v := reflect.Indirect(reflect.ValueOf(value))
- t := v.Type()
-
- if t.ConvertibleTo(reflect.TypeOf(time.Time{})) {
- tt := v.Convert(reflect.TypeOf(time.Time{}))
- timeVal := tt.Interface().(time.Time)
- return timeVal.Format(time.RFC3339Nano), true
- }
-
- if t.ConvertibleTo(reflect.TypeOf(types.Date{})) {
- d := v.Convert(reflect.TypeOf(types.Date{}))
- dateVal := d.Interface().(types.Date)
- return dateVal.Format(types.DateFormat), true
- }
-
- if t.ConvertibleTo(reflect.TypeOf(types.UUID{})) {
- u := v.Convert(reflect.TypeOf(types.UUID{}))
- uuidVal := u.Interface().(types.UUID)
- return uuidVal.String(), true
- }
-
- return "", false
-}
-
-func styleStruct(style string, explode bool, paramName string, paramLocation ParamLocation, value interface{}) (string, error) {
- if timeVal, ok := marshalKnownTypes(value); ok {
- styledVal, err := stylePrimitive(style, explode, paramName, paramLocation, timeVal)
- if err != nil {
- return "", fmt.Errorf("failed to style time: %w", err)
- }
- return styledVal, nil
- }
-
- if style == "deepObject" {
- if !explode {
- return "", errors.New("deepObjects must be exploded")
- }
- return MarshalDeepObject(value, paramName)
- }
-
- // If input has Marshaler, such as object has Additional Property or AnyOf,
- // We use this Marshaler and convert into interface{} before styling.
- if m, ok := value.(json.Marshaler); ok {
- buf, err := m.MarshalJSON()
- if err != nil {
- return "", fmt.Errorf("failed to marshal input to JSON: %w", err)
- }
- e := json.NewDecoder(bytes.NewReader(buf))
- e.UseNumber()
- var i2 interface{}
- err = e.Decode(&i2)
- if err != nil {
- return "", fmt.Errorf("failed to unmarshal JSON: %w", err)
- }
- s, err := StyleParamWithLocation(style, explode, paramName, paramLocation, i2)
- if err != nil {
- return "", fmt.Errorf("error style JSON structure: %w", err)
- }
- return s, nil
- }
-
- // Otherwise, we need to build a dictionary of the struct's fields. Each
- // field may only be a primitive value.
- v := reflect.ValueOf(value)
- t := reflect.TypeOf(value)
- fieldDict := make(map[string]string)
-
- for i := 0; i < t.NumField(); i++ {
- fieldT := t.Field(i)
- // Find the json annotation on the field, and use the json specified
- // name if available, otherwise, just the field name.
- tag := fieldT.Tag.Get("json")
- fieldName := fieldT.Name
- if tag != "" {
- tagParts := strings.Split(tag, ",")
- name := tagParts[0]
- if name != "" {
- fieldName = name
- }
- }
- f := v.Field(i)
-
- // Unset optional fields will be nil pointers, skip over those.
- if f.Type().Kind() == reflect.Ptr && f.IsNil() {
- continue
- }
- str, err := primitiveToString(f.Interface())
- if err != nil {
- return "", fmt.Errorf("error formatting '%s': %s", paramName, err)
- }
- fieldDict[fieldName] = str
- }
-
- return processFieldDict(style, explode, paramName, paramLocation, fieldDict)
-}
-
-func styleMap(style string, explode bool, paramName string, paramLocation ParamLocation, value interface{}) (string, error) {
- if style == "deepObject" {
- if !explode {
- return "", errors.New("deepObjects must be exploded")
- }
- return MarshalDeepObject(value, paramName)
- }
-
- dict, ok := value.(map[string]interface{})
- if !ok {
- return "", errors.New("map not of type map[string]interface{}")
- }
-
- fieldDict := make(map[string]string)
- for fieldName, value := range dict {
- str, err := primitiveToString(value)
- if err != nil {
- return "", fmt.Errorf("error formatting '%s': %s", paramName, err)
- }
- fieldDict[fieldName] = str
- }
- return processFieldDict(style, explode, paramName, paramLocation, fieldDict)
-}
-
-func processFieldDict(style string, explode bool, paramName string, paramLocation ParamLocation, fieldDict map[string]string) (string, error) {
- var parts []string
-
- // This works for everything except deepObject. We'll handle that one
- // separately.
- if style != "deepObject" {
- if explode {
- for _, k := range sortedKeys(fieldDict) {
- v := escapeParameterString(fieldDict[k], paramLocation)
- parts = append(parts, k+"="+v)
- }
- } else {
- for _, k := range sortedKeys(fieldDict) {
- v := escapeParameterString(fieldDict[k], paramLocation)
- parts = append(parts, k)
- parts = append(parts, v)
- }
- }
- }
-
- var prefix string
- var separator string
-
- switch style {
- case "simple":
- separator = ","
- case "label":
- prefix = "."
- if explode {
- separator = prefix
- } else {
- separator = ","
- }
- case "matrix":
- if explode {
- separator = ";"
- prefix = ";"
- } else {
- separator = ","
- prefix = fmt.Sprintf(";%s=", paramName)
- }
- case "form":
- if explode {
- separator = "&"
- } else {
- prefix = fmt.Sprintf("%s=", paramName)
- separator = ","
- }
- case "deepObject":
- {
- if !explode {
- return "", fmt.Errorf("deepObject parameters must be exploded")
- }
- for _, k := range sortedKeys(fieldDict) {
- v := fieldDict[k]
- part := fmt.Sprintf("%s[%s]=%s", paramName, k, v)
- parts = append(parts, part)
- }
- separator = "&"
- }
- default:
- return "", fmt.Errorf("unsupported style '%s'", style)
- }
-
- return prefix + strings.Join(parts, separator), nil
-}
-
-func stylePrimitive(style string, explode bool, paramName string, paramLocation ParamLocation, value interface{}) (string, error) {
- strVal, err := primitiveToString(value)
- if err != nil {
- return "", err
- }
-
- var prefix string
- switch style {
- case "simple":
- case "label":
- prefix = "."
- case "matrix":
- prefix = fmt.Sprintf(";%s=", paramName)
- case "form":
- prefix = fmt.Sprintf("%s=", paramName)
- default:
- return "", fmt.Errorf("unsupported style '%s'", style)
- }
- return prefix + escapeParameterString(strVal, paramLocation), nil
-}
-
-// Converts a primitive value to a string. We need to do this based on the
-// Kind of an interface, not the Type to work with aliased types.
-func primitiveToString(value interface{}) (string, error) {
- var output string
-
- // sometimes time and date used like primitive types
- // it can happen if paramether is object and has time or date as field
- if res, ok := marshalKnownTypes(value); ok {
- return res, nil
- }
-
- // Values may come in by pointer for optionals, so make sure to dereferene.
- v := reflect.Indirect(reflect.ValueOf(value))
- t := v.Type()
- kind := t.Kind()
-
- switch kind {
- case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int:
- output = strconv.FormatInt(v.Int(), 10)
- case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint:
- output = strconv.FormatUint(v.Uint(), 10)
- case reflect.Float64:
- output = strconv.FormatFloat(v.Float(), 'f', -1, 64)
- case reflect.Float32:
- output = strconv.FormatFloat(v.Float(), 'f', -1, 32)
- case reflect.Bool:
- if v.Bool() {
- output = "true"
- } else {
- output = "false"
- }
- case reflect.String:
- output = v.String()
- case reflect.Struct:
- // If input has Marshaler, such as object has Additional Property or AnyOf,
- // We use this Marshaler and convert into interface{} before styling.
- if v, ok := value.(uuid.UUID); ok {
- output = v.String()
- break
- }
- if m, ok := value.(json.Marshaler); ok {
- buf, err := m.MarshalJSON()
- if err != nil {
- return "", fmt.Errorf("failed to marshal input to JSON: %w", err)
- }
- e := json.NewDecoder(bytes.NewReader(buf))
- e.UseNumber()
- var i2 interface{}
- err = e.Decode(&i2)
- if err != nil {
- return "", fmt.Errorf("failed to unmarshal JSON: %w", err)
- }
- output, err = primitiveToString(i2)
- if err != nil {
- return "", fmt.Errorf("error convert JSON structure: %w", err)
- }
- break
- }
- fallthrough
- default:
- v, ok := value.(fmt.Stringer)
- if !ok {
- return "", fmt.Errorf("unsupported type %s", reflect.TypeOf(value).String())
- }
-
- output = v.String()
- }
- return output, nil
-}
-
-// escapeParameterString escapes a parameter value bas on the location of that parameter.
-// Query params and path params need different kinds of escaping, while header
-// and cookie params seem not to need escaping.
-func escapeParameterString(value string, paramLocation ParamLocation) string {
- switch paramLocation {
- case ParamLocationQuery:
- return url.QueryEscape(value)
- case ParamLocationPath:
- return url.PathEscape(value)
- default:
- return value
- }
-}
diff --git a/pkg/runtime/styleparam_test.go b/pkg/runtime/styleparam_test.go
deleted file mode 100644
index 1943ae0fcd..0000000000
--- a/pkg/runtime/styleparam_test.go
+++ /dev/null
@@ -1,692 +0,0 @@
-// Copyright 2019 DeepMap, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package runtime
-
-import (
- "testing"
- "time"
-
- "github.com/deepmap/oapi-codegen/pkg/types"
- "github.com/google/uuid"
- "github.com/stretchr/testify/assert"
-)
-
-func TestStyleParam(t *testing.T) {
- primitive := 5
- primitiveString := "123"
- primitiveStringWithReservedChar := "123;456"
- array := []int{3, 4, 5}
- type TestObject struct {
- FirstName string `json:"firstName"`
- Role string `json:"role"`
- }
- object := TestObject{
- FirstName: "Alex",
- Role: "admin",
- }
- dict := map[string]interface{}{}
- dict["firstName"] = "Alex"
- dict["role"] = "admin"
-
- type AliasedTime time.Time
- ti, _ := time.Parse(time.RFC3339, "2020-01-01T22:00:00+02:00")
- timestamp := AliasedTime(ti)
-
- type AliasedDate types.Date
- date := AliasedDate{Time: time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC)}
-
- type AliasedUUID types.UUID
- aUUID := AliasedUUID(uuid.MustParse("baa07328-452e-40bd-aa2e-fa823ec13605"))
-
- // ---------------------------- Simple Style -------------------------------
-
- result, err := StyleParamWithLocation("simple", false, "id", ParamLocationQuery, primitive)
- assert.NoError(t, err)
- assert.EqualValues(t, "5", result)
-
- result, err = StyleParamWithLocation("simple", true, "id", ParamLocationQuery, primitive)
- assert.NoError(t, err)
- assert.EqualValues(t, "5", result)
-
- result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, array)
- assert.NoError(t, err)
- assert.EqualValues(t, "3,4,5", result)
-
- result, err = StyleParamWithLocation("simple", true, "id", ParamLocationQuery, array)
- assert.NoError(t, err)
- assert.EqualValues(t, "3,4,5", result)
-
- result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, object)
- assert.NoError(t, err)
- assert.EqualValues(t, "firstName,Alex,role,admin", result)
-
- result, err = StyleParamWithLocation("simple", true, "id", ParamLocationQuery, object)
- assert.NoError(t, err)
- assert.EqualValues(t, "firstName=Alex,role=admin", result)
-
- result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, dict)
- assert.NoError(t, err)
- assert.EqualValues(t, "firstName,Alex,role,admin", result)
-
- result, err = StyleParamWithLocation("simple", true, "id", ParamLocationQuery, dict)
- assert.NoError(t, err)
- assert.EqualValues(t, "firstName=Alex,role=admin", result)
-
- result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, timestamp)
- assert.NoError(t, err)
- assert.EqualValues(t, "2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("simple", true, "id", ParamLocationQuery, timestamp)
- assert.NoError(t, err)
- assert.EqualValues(t, "2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, ×tamp)
- assert.NoError(t, err)
- assert.EqualValues(t, "2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("simple", true, "id", ParamLocationQuery, ×tamp)
- assert.NoError(t, err)
- assert.EqualValues(t, "2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, date)
- assert.NoError(t, err)
- assert.EqualValues(t, "2020-01-01", result)
-
- result, err = StyleParamWithLocation("simple", true, "id", ParamLocationQuery, date)
- assert.NoError(t, err)
- assert.EqualValues(t, "2020-01-01", result)
-
- result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, &date)
- assert.NoError(t, err)
- assert.EqualValues(t, "2020-01-01", result)
-
- result, err = StyleParamWithLocation("simple", true, "id", ParamLocationQuery, &date)
- assert.NoError(t, err)
- assert.EqualValues(t, "2020-01-01", result)
-
- result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, "baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- result, err = StyleParamWithLocation("simple", true, "id", ParamLocationQuery, aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, "baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, &aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, "baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- result, err = StyleParamWithLocation("simple", true, "id", ParamLocationQuery, &aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, "baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- // ----------------------------- Label Style -------------------------------
-
- result, err = StyleParamWithLocation("label", false, "id", ParamLocationQuery, primitive)
- assert.NoError(t, err)
- assert.EqualValues(t, ".5", result)
-
- result, err = StyleParamWithLocation("label", true, "id", ParamLocationQuery, primitive)
- assert.NoError(t, err)
- assert.EqualValues(t, ".5", result)
-
- result, err = StyleParamWithLocation("label", false, "id", ParamLocationQuery, array)
- assert.NoError(t, err)
- assert.EqualValues(t, ".3,4,5", result)
-
- result, err = StyleParamWithLocation("label", true, "id", ParamLocationQuery, array)
- assert.NoError(t, err)
- assert.EqualValues(t, ".3.4.5", result)
-
- result, err = StyleParamWithLocation("label", false, "id", ParamLocationQuery, object)
- assert.NoError(t, err)
- assert.EqualValues(t, ".firstName,Alex,role,admin", result)
-
- result, err = StyleParamWithLocation("label", true, "id", ParamLocationQuery, object)
- assert.NoError(t, err)
- assert.EqualValues(t, ".firstName=Alex.role=admin", result)
-
- result, err = StyleParamWithLocation("label", false, "id", ParamLocationQuery, dict)
- assert.NoError(t, err)
- assert.EqualValues(t, ".firstName,Alex,role,admin", result)
-
- result, err = StyleParamWithLocation("label", true, "id", ParamLocationQuery, dict)
- assert.NoError(t, err)
- assert.EqualValues(t, ".firstName=Alex.role=admin", result)
-
- result, err = StyleParamWithLocation("label", false, "id", ParamLocationQuery, timestamp)
- assert.NoError(t, err)
- assert.EqualValues(t, ".2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("label", true, "id", ParamLocationQuery, timestamp)
- assert.NoError(t, err)
- assert.EqualValues(t, ".2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("label", false, "id", ParamLocationQuery, ×tamp)
- assert.NoError(t, err)
- assert.EqualValues(t, ".2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("label", true, "id", ParamLocationQuery, ×tamp)
- assert.NoError(t, err)
- assert.EqualValues(t, ".2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("label", false, "id", ParamLocationQuery, date)
- assert.NoError(t, err)
- assert.EqualValues(t, ".2020-01-01", result)
-
- result, err = StyleParamWithLocation("label", true, "id", ParamLocationQuery, date)
- assert.NoError(t, err)
- assert.EqualValues(t, ".2020-01-01", result)
-
- result, err = StyleParamWithLocation("label", false, "id", ParamLocationQuery, &date)
- assert.NoError(t, err)
- assert.EqualValues(t, ".2020-01-01", result)
-
- result, err = StyleParamWithLocation("label", true, "id", ParamLocationQuery, &date)
- assert.NoError(t, err)
- assert.EqualValues(t, ".2020-01-01", result)
-
- result, err = StyleParamWithLocation("label", false, "id", ParamLocationQuery, aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, ".baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- result, err = StyleParamWithLocation("label", true, "id", ParamLocationQuery, aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, ".baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- result, err = StyleParamWithLocation("label", false, "id", ParamLocationQuery, &aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, ".baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- result, err = StyleParamWithLocation("label", true, "id", ParamLocationQuery, &aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, ".baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- // ----------------------------- Matrix Style ------------------------------
-
- result, err = StyleParamWithLocation("matrix", false, "id", ParamLocationQuery, primitive)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=5", result)
-
- result, err = StyleParamWithLocation("matrix", true, "id", ParamLocationQuery, primitive)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=5", result)
-
- result, err = StyleParamWithLocation("matrix", false, "id", ParamLocationQuery, array)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=3,4,5", result)
-
- result, err = StyleParamWithLocation("matrix", true, "id", ParamLocationQuery, array)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=3;id=4;id=5", result)
-
- result, err = StyleParamWithLocation("matrix", false, "id", ParamLocationQuery, object)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=firstName,Alex,role,admin", result)
-
- result, err = StyleParamWithLocation("matrix", true, "id", ParamLocationQuery, object)
- assert.NoError(t, err)
- assert.EqualValues(t, ";firstName=Alex;role=admin", result)
-
- result, err = StyleParamWithLocation("matrix", false, "id", ParamLocationQuery, dict)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=firstName,Alex,role,admin", result)
-
- result, err = StyleParamWithLocation("matrix", true, "id", ParamLocationQuery, dict)
- assert.NoError(t, err)
- assert.EqualValues(t, ";firstName=Alex;role=admin", result)
-
- result, err = StyleParamWithLocation("matrix", false, "id", ParamLocationQuery, timestamp)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("matrix", true, "id", ParamLocationQuery, timestamp)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("matrix", false, "id", ParamLocationQuery, ×tamp)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("matrix", true, "id", ParamLocationQuery, ×tamp)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("matrix", false, "id", ParamLocationQuery, date)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=2020-01-01", result)
-
- result, err = StyleParamWithLocation("matrix", true, "id", ParamLocationQuery, date)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=2020-01-01", result)
-
- result, err = StyleParamWithLocation("matrix", false, "id", ParamLocationQuery, &date)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=2020-01-01", result)
-
- result, err = StyleParamWithLocation("matrix", true, "id", ParamLocationQuery, &date)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=2020-01-01", result)
-
- result, err = StyleParamWithLocation("matrix", false, "id", ParamLocationQuery, aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- result, err = StyleParamWithLocation("matrix", true, "id", ParamLocationQuery, aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- result, err = StyleParamWithLocation("matrix", false, "id", ParamLocationQuery, &aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- result, err = StyleParamWithLocation("matrix", true, "id", ParamLocationQuery, &aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, ";id=baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- // ------------------------------ Form Style -------------------------------
- result, err = StyleParamWithLocation("form", false, "id", ParamLocationQuery, primitive)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=5", result)
-
- result, err = StyleParamWithLocation("form", true, "id", ParamLocationQuery, primitive)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=5", result)
-
- result, err = StyleParamWithLocation("form", false, "id", ParamLocationQuery, primitiveString)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=123", result)
-
- result, err = StyleParamWithLocation("form", true, "id", ParamLocationQuery, primitiveString)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=123", result)
-
- result, err = StyleParamWithLocation("form", false, "id", ParamLocationQuery, primitiveStringWithReservedChar)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=123%3B456", result)
-
- result, err = StyleParamWithLocation("form", true, "id", ParamLocationQuery, primitiveStringWithReservedChar)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=123%3B456", result)
-
- result, err = StyleParamWithLocation("form", false, "id", ParamLocationQuery, array)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=3,4,5", result)
-
- result, err = StyleParamWithLocation("form", true, "id", ParamLocationQuery, array)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=3&id=4&id=5", result)
-
- result, err = StyleParamWithLocation("form", false, "id", ParamLocationQuery, object)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=firstName,Alex,role,admin", result)
-
- result, err = StyleParamWithLocation("form", true, "id", ParamLocationQuery, object)
- assert.NoError(t, err)
- assert.EqualValues(t, "firstName=Alex&role=admin", result)
-
- result, err = StyleParamWithLocation("form", false, "id", ParamLocationQuery, dict)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=firstName,Alex,role,admin", result)
-
- result, err = StyleParamWithLocation("form", true, "id", ParamLocationQuery, dict)
- assert.NoError(t, err)
- assert.EqualValues(t, "firstName=Alex&role=admin", result)
-
- result, err = StyleParamWithLocation("form", false, "id", ParamLocationQuery, timestamp)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("form", true, "id", ParamLocationQuery, timestamp)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("form", false, "id", ParamLocationQuery, ×tamp)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("form", true, "id", ParamLocationQuery, ×tamp)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=2020-01-01T22%3A00%3A00%2B02%3A00", result)
-
- result, err = StyleParamWithLocation("form", false, "id", ParamLocationQuery, date)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=2020-01-01", result)
-
- result, err = StyleParamWithLocation("form", true, "id", ParamLocationQuery, date)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=2020-01-01", result)
-
- result, err = StyleParamWithLocation("form", false, "id", ParamLocationQuery, &date)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=2020-01-01", result)
-
- result, err = StyleParamWithLocation("form", true, "id", ParamLocationQuery, &date)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=2020-01-01", result)
-
- result, err = StyleParamWithLocation("form", false, "id", ParamLocationQuery, aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- result, err = StyleParamWithLocation("form", true, "id", ParamLocationQuery, aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- result, err = StyleParamWithLocation("form", false, "id", ParamLocationQuery, &aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- result, err = StyleParamWithLocation("form", true, "id", ParamLocationQuery, &aUUID)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- // ------------------------ spaceDelimited Style --------------------------
-
- _, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, primitive)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, primitive)
- assert.Error(t, err)
-
- result, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, array)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=3 4 5", result)
-
- result, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, array)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=3&id=4&id=5", result)
-
- _, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, object)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, object)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, dict)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, dict)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, timestamp)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, timestamp)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, ×tamp)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, ×tamp)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, date)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, date)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, &date)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, &date)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, aUUID)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, aUUID)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", false, "id", ParamLocationQuery, &aUUID)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("spaceDelimited", true, "id", ParamLocationQuery, &aUUID)
- assert.Error(t, err)
-
- // ------------------------- pipeDelimited Style --------------------------
-
- _, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, primitive)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, primitive)
- assert.Error(t, err)
-
- result, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, array)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=3|4|5", result)
-
- result, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, array)
- assert.NoError(t, err)
- assert.EqualValues(t, "id=3&id=4&id=5", result)
-
- _, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, object)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, object)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, dict)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, dict)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, timestamp)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, timestamp)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, ×tamp)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, ×tamp)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, date)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, date)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, &date)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, &date)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, aUUID)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, aUUID)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", false, "id", ParamLocationQuery, &aUUID)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("pipeDelimited", true, "id", ParamLocationQuery, &aUUID)
- assert.Error(t, err)
-
- // --------------------------- deepObject Style ---------------------------
- _, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, primitive)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, primitive)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, array)
- assert.Error(t, err)
-
- result, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, array)
- assert.NoError(t, err)
- assert.EqualValues(t, "id[0]=3&id[1]=4&id[2]=5", result)
-
- _, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, object)
- assert.Error(t, err)
-
- result, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, object)
- assert.NoError(t, err)
- assert.EqualValues(t, "id[firstName]=Alex&id[role]=admin", result)
-
- result, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, dict)
- assert.NoError(t, err)
- assert.EqualValues(t, "id[firstName]=Alex&id[role]=admin", result)
-
- _, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, timestamp)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, timestamp)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, ×tamp)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, ×tamp)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, date)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, date)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, &date)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, &date)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, aUUID)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, aUUID)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("deepObject", false, "id", ParamLocationQuery, &aUUID)
- assert.Error(t, err)
-
- _, err = StyleParamWithLocation("deepObject", true, "id", ParamLocationQuery, &aUUID)
- assert.Error(t, err)
-
- // Misc tests
- // Test type aliases
- type StrType string
- result, err = StyleParamWithLocation("simple", false, "foo", ParamLocationQuery, StrType("test"))
- assert.NoError(t, err)
- assert.EqualValues(t, "test", result)
-
- type IntType int32
- result, err = StyleParamWithLocation("simple", false, "foo", ParamLocationQuery, IntType(7))
- assert.NoError(t, err)
- assert.EqualValues(t, "7", result)
-
- type UintType uint
- result, err = StyleParamWithLocation("simple", false, "foo", ParamLocationQuery, UintType(9))
- assert.NoError(t, err)
- assert.EqualValues(t, "9", result)
-
- type Uint8Type uint8
- result, err = StyleParamWithLocation("simple", false, "foo", ParamLocationQuery, Uint8Type(9))
- assert.NoError(t, err)
- assert.EqualValues(t, "9", result)
-
- type Uint16Type uint16
- result, err = StyleParamWithLocation("simple", false, "foo", ParamLocationQuery, Uint16Type(9))
- assert.NoError(t, err)
- assert.EqualValues(t, "9", result)
-
- type Uint32Type uint32
- result, err = StyleParamWithLocation("simple", false, "foo", ParamLocationQuery, Uint32Type(9))
- assert.NoError(t, err)
- assert.EqualValues(t, "9", result)
-
- type Uint64Type uint64
- result, err = StyleParamWithLocation("simple", false, "foo", ParamLocationQuery, Uint64Type(9))
- assert.NoError(t, err)
- assert.EqualValues(t, "9", result)
-
- type FloatType64 float64
- result, err = StyleParamWithLocation("simple", false, "foo", ParamLocationQuery, FloatType64(7.5))
- assert.NoError(t, err)
- assert.EqualValues(t, "7.5", result)
-
- type FloatType32 float32
- result, err = StyleParamWithLocation("simple", false, "foo", ParamLocationQuery, FloatType32(1.05))
- assert.NoError(t, err)
- assert.EqualValues(t, "1.05", result)
-
- uuidValue := uuid.MustParse("c2d07ba4-5106-4eab-bcad-0bd6068dcb1a")
- result, err = StyleParamWithLocation("simple", false, "foo", ParamLocationQuery, types.UUID(uuidValue))
- assert.NoError(t, err)
- assert.EqualValues(t, "c2d07ba4-5106-4eab-bcad-0bd6068dcb1a", result)
-
- // Test that we handle optional fields
- type TestObject2 struct {
- FirstName *string `json:"firstName"`
- Role *string `json:"role"`
- }
- name := "Alex"
- role := "admin"
- object2 := TestObject2{
- FirstName: &name,
- Role: &role,
- }
- result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, object2)
- assert.NoError(t, err)
- assert.EqualValues(t, "firstName,Alex,role,admin", result)
-
- // Nullable fields need to be excluded when null
- object2.Role = nil
- result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, object2)
- assert.NoError(t, err)
- assert.EqualValues(t, "firstName,Alex", result)
-
- // Test handling of other known types inside objects
- type testObject3 struct {
- TimeField time.Time `json:"time_field"`
- DateField types.Date `json:"date_field"`
- UUIDField types.UUID `json:"uuid_field"`
- }
- timeVal := time.Date(1996, time.March, 19, 0, 0, 0, 0, time.UTC)
- dateVal := types.Date{
- Time: timeVal,
- }
- uuidVal := uuid.MustParse("baa07328-452e-40bd-aa2e-fa823ec13605")
-
- object3 := testObject3{
- TimeField: timeVal,
- DateField: dateVal,
- UUIDField: uuidVal,
- }
-
- result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, object3)
- assert.NoError(t, err)
- assert.EqualValues(t, "date_field,1996-03-19,time_field,1996-03-19T00%3A00%3A00Z,uuid_field,baa07328-452e-40bd-aa2e-fa823ec13605", result)
-
- // Test handling of struct that implement encoding.TextMarshaler
- timeVal = time.Date(1996, time.March, 19, 0, 0, 0, 0, time.UTC)
-
- result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, timeVal)
- assert.NoError(t, err)
- assert.EqualValues(t, "1996-03-19T00%3A00%3A00Z", result)
-
- uuidD := uuid.MustParse("972beb41-e5ea-4b31-a79a-96f4999d8769")
-
- result, err = StyleParamWithLocation("simple", false, "id", ParamLocationQuery, uuidD)
- assert.NoError(t, err)
- assert.EqualValues(t, "972beb41-e5ea-4b31-a79a-96f4999d8769", result)
-
-}
diff --git a/pkg/securityprovider/securityprovider.go b/pkg/securityprovider/securityprovider.go
index 940fc5b472..091c1765e1 100644
--- a/pkg/securityprovider/securityprovider.go
+++ b/pkg/securityprovider/securityprovider.go
@@ -47,7 +47,7 @@ func (s *SecurityProviderBasicAuth) Intercept(ctx context.Context, req *http.Req
}
// NewSecurityProviderBearerToken provides a SecurityProvider, which can solve
-// the Bearer Auth challende for api-calls.
+// the Bearer Auth challenge for api-calls.
func NewSecurityProviderBearerToken(token string) (*SecurityProviderBearerToken, error) {
return &SecurityProviderBearerToken{
token: token,
diff --git a/pkg/testutil/request_helpers.go b/pkg/testutil/request_helpers.go
deleted file mode 100644
index 91eb2fb459..0000000000
--- a/pkg/testutil/request_helpers.go
+++ /dev/null
@@ -1,218 +0,0 @@
-// Copyright 2019 DeepMap, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-package testutil
-
-// This is a set of fluent request builders for tests, which help us to
-// simplify constructing and unmarshaling test objects. For example, to post
-// a body and return a response, you would do something like:
-//
-// var body RequestBody
-// var response ResponseBody
-// t is *testing.T, from a unit test
-// e is *echo.Echo
-// response := NewRequest().Post("/path").WithJsonBody(body).Go(t, e)
-// err := response.UnmarshalBodyToObject(&response)
-import (
- "bytes"
- "encoding/json"
- "fmt"
- "io"
- "net/http"
- "net/http/httptest"
- "strings"
- "testing"
-
- "github.com/labstack/echo/v4"
-)
-
-func NewRequest() *RequestBuilder {
- return &RequestBuilder{
- Headers: make(map[string]string),
- }
-}
-
-// RequestBuilder caches request settings as we build up the request.
-type RequestBuilder struct {
- Method string
- Path string
- Headers map[string]string
- Body []byte
- Error error
- Cookies []*http.Cookie
-}
-
-// WithMethod sets the method and path
-func (r *RequestBuilder) WithMethod(method string, path string) *RequestBuilder {
- r.Method = method
- r.Path = path
- return r
-}
-
-func (r *RequestBuilder) Get(path string) *RequestBuilder {
- return r.WithMethod("GET", path)
-}
-
-func (r *RequestBuilder) Post(path string) *RequestBuilder {
- return r.WithMethod("POST", path)
-}
-
-func (r *RequestBuilder) Put(path string) *RequestBuilder {
- return r.WithMethod("PUT", path)
-}
-
-func (r *RequestBuilder) Patch(path string) *RequestBuilder {
- return r.WithMethod("PATCH", path)
-}
-
-func (r *RequestBuilder) Delete(path string) *RequestBuilder {
- return r.WithMethod("DELETE", path)
-}
-
-// WithHeader sets a header
-func (r *RequestBuilder) WithHeader(header, value string) *RequestBuilder {
- r.Headers[header] = value
- return r
-}
-
-func (r *RequestBuilder) WithJWSAuth(jws string) *RequestBuilder {
- r.Headers["Authorization"] = "Bearer " + jws
- return r
-}
-
-func (r *RequestBuilder) WithHost(value string) *RequestBuilder {
- return r.WithHeader("Host", value)
-}
-
-func (r *RequestBuilder) WithContentType(value string) *RequestBuilder {
- return r.WithHeader("Content-Type", value)
-}
-
-func (r *RequestBuilder) WithJsonContentType() *RequestBuilder {
- return r.WithContentType("application/json")
-}
-
-func (r *RequestBuilder) WithAccept(value string) *RequestBuilder {
- return r.WithHeader("Accept", value)
-}
-
-func (r *RequestBuilder) WithAcceptJson() *RequestBuilder {
- return r.WithAccept("application/json")
-}
-
-// Request body operations
-
-func (r *RequestBuilder) WithBody(body []byte) *RequestBuilder {
- r.Body = body
- return r
-}
-
-// WithJsonBody takes an object as input, marshals it to JSON, and sends it
-// as the body with Content-Type: application/json
-func (r *RequestBuilder) WithJsonBody(obj interface{}) *RequestBuilder {
- var err error
- r.Body, err = json.Marshal(obj)
- if err != nil {
- r.Error = fmt.Errorf("failed to marshal json object: %w", err)
- }
- return r.WithJsonContentType()
-}
-
-// WithCookie sets a cookie
-func (r *RequestBuilder) WithCookie(c *http.Cookie) *RequestBuilder {
- r.Cookies = append(r.Cookies, c)
- return r
-}
-
-func (r *RequestBuilder) WithCookieNameValue(name, value string) *RequestBuilder {
- return r.WithCookie(&http.Cookie{Name: name, Value: value})
-}
-
-// GoWithHTTPHandler performs the request, it takes a pointer to a testing context
-// to print messages, and a http handler for request handling.
-func (r *RequestBuilder) GoWithHTTPHandler(t *testing.T, handler http.Handler) *CompletedRequest {
- if r.Error != nil {
- // Fail the test if we had an error
- t.Errorf("error constructing request: %s", r.Error)
- return nil
- }
- var bodyReader io.Reader
- if r.Body != nil {
- bodyReader = bytes.NewReader(r.Body)
- }
-
- req := httptest.NewRequest(r.Method, r.Path, bodyReader)
- for h, v := range r.Headers {
- req.Header.Add(h, v)
- }
- if host, ok := r.Headers["Host"]; ok {
- req.Host = host
- }
- for _, c := range r.Cookies {
- req.AddCookie(c)
- }
-
- rec := httptest.NewRecorder()
- handler.ServeHTTP(rec, req)
-
- return &CompletedRequest{
- Recorder: rec,
- }
-}
-
-// Go performs the request, it takes a pointer to a testing context
-// to print messages, and a pointer to an echo context for request handling.
-func (r *RequestBuilder) Go(t *testing.T, e *echo.Echo) *CompletedRequest {
- return r.GoWithHTTPHandler(t, e)
-}
-
-// CompletedRequest is the result of calling Go() on the request builder. We're wrapping the
-// ResponseRecorder with some nice helper functions.
-type CompletedRequest struct {
- Recorder *httptest.ResponseRecorder
-
- // When set to true, decoders will be more strict. In the default JSON
- // recorder, unknown fields will cause errors.
- Strict bool
-}
-
-func (c *CompletedRequest) DisallowUnknownFields() {
- c.Strict = true
-}
-
-// UnmarshalBodyToObject takes a destination object as input, and unmarshals the object
-// in the response based on the Content-Type header.
-func (c *CompletedRequest) UnmarshalBodyToObject(obj interface{}) error {
- ctype := c.Recorder.Header().Get("Content-Type")
-
- // Content type can have an annotation after ;
- contentParts := strings.Split(ctype, ";")
- content := strings.TrimSpace(contentParts[0])
- handler := getHandler(content)
- if handler == nil {
- return fmt.Errorf("unhandled content: %s", content)
- }
-
- return handler(ctype, c.Recorder.Body, obj, c.Strict)
-}
-
-// UnmarshalJsonToObject assumes that the response contains JSON and unmarshals it
-// into the specified object.
-func (c *CompletedRequest) UnmarshalJsonToObject(obj interface{}) error {
- return json.Unmarshal(c.Recorder.Body.Bytes(), obj)
-}
-
-// Code is a shortcut for response code
-func (c *CompletedRequest) Code() int {
- return c.Recorder.Code
-}
diff --git a/pkg/testutil/response_handlers.go b/pkg/testutil/response_handlers.go
deleted file mode 100644
index c436f1965b..0000000000
--- a/pkg/testutil/response_handlers.go
+++ /dev/null
@@ -1,44 +0,0 @@
-package testutil
-
-import (
- "encoding/json"
- "io"
- "sync"
-)
-
-func init() {
- knownHandlers = make(map[string]ResponseHandler)
-
- RegisterResponseHandler("application/json", jsonHandler)
-}
-
-var (
- knownHandlersMu sync.Mutex
- knownHandlers map[string]ResponseHandler
-)
-
-type ResponseHandler func(contentType string, raw io.Reader, obj interface{}, strict bool) error
-
-func RegisterResponseHandler(mime string, handler ResponseHandler) {
- knownHandlersMu.Lock()
- defer knownHandlersMu.Unlock()
-
- knownHandlers[mime] = handler
-}
-
-func getHandler(mime string) ResponseHandler {
- knownHandlersMu.Lock()
- defer knownHandlersMu.Unlock()
-
- return knownHandlers[mime]
-}
-
-// jsonHandler assumes that the response contains JSON and unmarshals it
-// into the specified object.
-func jsonHandler(_ string, r io.Reader, obj interface{}, strict bool) error {
- d := json.NewDecoder(r)
- if strict {
- d.DisallowUnknownFields()
- }
- return d.Decode(obj)
-}
diff --git a/pkg/types/date.go b/pkg/types/date.go
deleted file mode 100644
index 089aa425e3..0000000000
--- a/pkg/types/date.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package types
-
-import (
- "encoding/json"
- "time"
-)
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#DateFormat
-const DateFormat = "2006-01-02"
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#Date
-type Date struct {
- time.Time
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#MarshalJSON
-func (d Date) MarshalJSON() ([]byte, error) {
- return json.Marshal(d.Time.Format(DateFormat))
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#UnmarshalJSON
-func (d *Date) UnmarshalJSON(data []byte) error {
- var dateStr string
- err := json.Unmarshal(data, &dateStr)
- if err != nil {
- return err
- }
- parsed, err := time.Parse(DateFormat, dateStr)
- if err != nil {
- return err
- }
- d.Time = parsed
- return nil
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#String
-func (d Date) String() string {
- return d.Time.Format(DateFormat)
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#UnmarshalText
-func (d *Date) UnmarshalText(data []byte) error {
- parsed, err := time.Parse(DateFormat, string(data))
- if err != nil {
- return err
- }
- d.Time = parsed
- return nil
-}
diff --git a/pkg/types/date_test.go b/pkg/types/date_test.go
deleted file mode 100644
index 211776522f..0000000000
--- a/pkg/types/date_test.go
+++ /dev/null
@@ -1,65 +0,0 @@
-package types
-
-import (
- "encoding/json"
- "fmt"
- "testing"
- "time"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestDate_MarshalJSON(t *testing.T) {
- testDate := time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC)
- b := struct {
- DateField Date `json:"date"`
- }{
- DateField: Date{testDate},
- }
- jsonBytes, err := json.Marshal(b)
- assert.NoError(t, err)
- assert.JSONEq(t, `{"date":"2019-04-01"}`, string(jsonBytes))
-}
-
-func TestDate_UnmarshalJSON(t *testing.T) {
- testDate := time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC)
- jsonStr := `{"date":"2019-04-01"}`
- b := struct {
- DateField Date `json:"date"`
- }{}
- err := json.Unmarshal([]byte(jsonStr), &b)
- assert.NoError(t, err)
- assert.Equal(t, testDate, b.DateField.Time)
-}
-
-func TestDate_Stringer(t *testing.T) {
- t.Run("nil date", func(t *testing.T) {
- var d *Date
- assert.Equal(t, "", fmt.Sprintf("%v", d))
- })
-
- t.Run("ptr date", func(t *testing.T) {
- d := &Date{
- Time: time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC),
- }
- assert.Equal(t, "2019-04-01", fmt.Sprintf("%v", d))
- })
-
- t.Run("value date", func(t *testing.T) {
- d := Date{
- Time: time.Date(2019, 4, 1, 0, 0, 0, 0, time.UTC),
- }
- assert.Equal(t, "2019-04-01", fmt.Sprintf("%v", d))
- })
-}
-
-func TestDate_UnmarshalText(t *testing.T) {
- testDate := time.Date(2022, 6, 14, 0, 0, 0, 0, time.UTC)
- value := []byte("2022-06-14")
-
- date := Date{}
- err := date.UnmarshalText(value)
-
- assert.NoError(t, err)
- assert.Equal(t, testDate, date.Time)
-}
diff --git a/pkg/types/email.go b/pkg/types/email.go
deleted file mode 100644
index 520f68a5a5..0000000000
--- a/pkg/types/email.go
+++ /dev/null
@@ -1,46 +0,0 @@
-package types
-
-import (
- "encoding/json"
- "errors"
-)
-
-// ErrValidationEmail is the sentinel error returned when an email fails validation
-//
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#ErrValidationEmail
-var ErrValidationEmail = errors.New("email: failed to pass regex validation")
-
-// Email represents an email address.
-// It is a string type that must pass regex validation before being marshalled
-// to JSON or unmarshalled from JSON.
-//
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#Email
-type Email string
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#MarshalJSON
-func (e Email) MarshalJSON() ([]byte, error) {
- if !emailRegex.MatchString(string(e)) {
- return nil, ErrValidationEmail
- }
-
- return json.Marshal(string(e))
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#UnmarshalJSON
-func (e *Email) UnmarshalJSON(data []byte) error {
- if e == nil {
- return nil
- }
-
- var s string
- if err := json.Unmarshal(data, &s); err != nil {
- return err
- }
-
- *e = Email(s)
- if !emailRegex.MatchString(s) {
- return ErrValidationEmail
- }
-
- return nil
-}
diff --git a/pkg/types/email_test.go b/pkg/types/email_test.go
deleted file mode 100644
index 736056b172..0000000000
--- a/pkg/types/email_test.go
+++ /dev/null
@@ -1,176 +0,0 @@
-package types
-
-import (
- "encoding/json"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-func TestEmail_MarshalJSON_Validation(t *testing.T) {
- type requiredEmail struct {
- EmailField Email `json:"email"`
- }
-
- testCases := map[string]struct {
- email Email
- expectedJSON []byte
- expectedError error
- }{
- "it should succeed marshalling a valid email and return valid JSON populated with the email": {
- email: Email("validemail@openapicodegen.com"),
- expectedJSON: []byte(`{"email":"validemail@openapicodegen.com"}`),
- expectedError: nil,
- },
- "it should fail marshalling an invalid email and return a validation error": {
- email: Email("invalidemail"),
- expectedJSON: nil,
- expectedError: ErrValidationEmail,
- },
- "it should fail marshalling an empty email and return a validation error": {
- email: Email(""),
- expectedJSON: nil,
- expectedError: ErrValidationEmail,
- },
- }
-
- for name, tc := range testCases {
- tc := tc
- t.Run(name, func(t *testing.T) {
- t.Parallel()
-
- jsonBytes, err := json.Marshal(requiredEmail{EmailField: tc.email})
-
- if tc.expectedError != nil {
- assert.ErrorIs(t, err, tc.expectedError)
- } else {
- assert.JSONEq(t, string(tc.expectedJSON), string(jsonBytes))
- }
- })
- }
-}
-
-func TestEmail_UnmarshalJSON_RequiredEmail_Validation(t *testing.T) {
- type requiredEmail struct {
- EmailField Email `json:"email"`
- }
-
- requiredEmailTestCases := map[string]struct {
- jsonStr string
- expectedEmail Email
- expectedError error
- }{
- "it should succeed validating a valid email during the unmarshal process": {
- jsonStr: `{"email":"gaben@valvesoftware.com"}`,
- expectedError: nil,
- expectedEmail: func() Email {
- e := Email("gaben@valvesoftware.com")
- return e
- }(),
- },
- "it should fail validating an invalid email": {
- jsonStr: `{"email":"not-an-email"}`,
- expectedError: ErrValidationEmail,
- expectedEmail: func() Email {
- e := Email("not-an-email")
- return e
- }(),
- },
- "it should fail validating an empty email": {
- jsonStr: `{"email":""}`,
- expectedEmail: func() Email {
- e := Email("")
- return e
- }(),
- expectedError: ErrValidationEmail,
- },
- "it should fail validating a null email": {
- jsonStr: `{"email":null}`,
- expectedEmail: func() Email {
- e := Email("")
- return e
- }(),
- expectedError: ErrValidationEmail,
- },
- }
-
- for name, tc := range requiredEmailTestCases {
- tc := tc
- t.Run(name, func(t *testing.T) {
- t.Parallel()
-
- b := requiredEmail{}
- err := json.Unmarshal([]byte(tc.jsonStr), &b)
- assert.Equal(t, tc.expectedEmail, b.EmailField)
- assert.ErrorIs(t, err, tc.expectedError)
- })
- }
-
-}
-
-func TestEmail_UnmarshalJSON_NullableEmail_Validation(t *testing.T) {
-
- type nullableEmail struct {
- EmailField *Email `json:"email,omitempty"`
- }
-
- nullableEmailTestCases := map[string]struct {
- body nullableEmail
- jsonStr string
- expectedEmail *Email
- expectedError error
- }{
- "it should succeed validating a valid email during the unmarshal process": {
- body: nullableEmail{},
- jsonStr: `{"email":"gaben@valvesoftware.com"}`,
- expectedError: nil,
- expectedEmail: func() *Email {
- e := Email("gaben@valvesoftware.com")
- return &e
- }(),
- },
- "it should fail validating an invalid email": {
- body: nullableEmail{},
- jsonStr: `{"email":"not-an-email"}`,
- expectedError: ErrValidationEmail,
- expectedEmail: func() *Email {
- e := Email("not-an-email")
- return &e
- }(),
- },
- "it should fail validating an empty email": {
- body: nullableEmail{},
- jsonStr: `{"email":""}`,
- expectedError: ErrValidationEmail,
- expectedEmail: func() *Email {
- e := Email("")
- return &e
- }(),
- },
- "it should succeed validating a null email": {
- body: nullableEmail{},
- jsonStr: `{"email":null}`,
- expectedEmail: nil,
- expectedError: nil,
- },
- "it should succeed validating a missing email": {
- body: nullableEmail{},
- jsonStr: `{}`,
- expectedEmail: nil,
- expectedError: nil,
- },
- }
-
- for name, tc := range nullableEmailTestCases {
- tc := tc
- t.Run(name, func(t *testing.T) {
- t.Parallel()
-
- err := json.Unmarshal([]byte(tc.jsonStr), &tc.body)
- assert.Equal(t, tc.expectedEmail, tc.body.EmailField)
- if tc.expectedError != nil {
- assert.ErrorIs(t, err, tc.expectedError)
- }
- })
- }
-}
diff --git a/pkg/types/file.go b/pkg/types/file.go
deleted file mode 100644
index 653ea87522..0000000000
--- a/pkg/types/file.go
+++ /dev/null
@@ -1,80 +0,0 @@
-package types
-
-import (
- "bytes"
- "encoding/json"
- "io"
- "mime/multipart"
-)
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#File
-type File struct {
- multipart *multipart.FileHeader
- data []byte
- filename string
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#InitFromMultipart
-func (file *File) InitFromMultipart(header *multipart.FileHeader) {
- file.multipart = header
- file.data = nil
- file.filename = ""
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#InitFromBytes
-func (file *File) InitFromBytes(data []byte, filename string) {
- file.data = data
- file.filename = filename
- file.multipart = nil
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#MarshalJSON
-func (file File) MarshalJSON() ([]byte, error) {
- b, err := file.Bytes()
- if err != nil {
- return nil, err
- }
- return json.Marshal(b)
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#UnmarshalJSON
-func (file *File) UnmarshalJSON(data []byte) error {
- return json.Unmarshal(data, &file.data)
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#Bytes
-func (file File) Bytes() ([]byte, error) {
- if file.multipart != nil {
- f, err := file.multipart.Open()
- if err != nil {
- return nil, err
- }
- defer func() { _ = f.Close() }()
- return io.ReadAll(f)
- }
- return file.data, nil
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#Reader
-func (file File) Reader() (io.ReadCloser, error) {
- if file.multipart != nil {
- return file.multipart.Open()
- }
- return io.NopCloser(bytes.NewReader(file.data)), nil
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#Filename
-func (file File) Filename() string {
- if file.multipart != nil {
- return file.multipart.Filename
- }
- return file.filename
-}
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#FileSize
-func (file File) FileSize() int64 {
- if file.multipart != nil {
- return file.multipart.Size
- }
- return int64(len(file.data))
-}
diff --git a/pkg/types/file_test.go b/pkg/types/file_test.go
deleted file mode 100644
index fb4ce98ae1..0000000000
--- a/pkg/types/file_test.go
+++ /dev/null
@@ -1,54 +0,0 @@
-package types
-
-import (
- "encoding/json"
- "testing"
-
- "github.com/stretchr/testify/assert"
- "github.com/stretchr/testify/require"
-)
-
-var _ json.Marshaler = (*File)(nil)
-var _ json.Unmarshaler = (*File)(nil)
-
-func TestFileJSON(t *testing.T) {
- type Object struct {
- BinaryField File `json:"binary_field"`
- }
-
- // Check whether we encode JSON properly.
- var o Object
- o.BinaryField.InitFromBytes([]byte("hello"), "")
- buf, err := json.Marshal(o)
- require.NoError(t, err)
- t.Log(string(buf))
-
- // Decode the same object back into File, ensure result is correct.
- var o2 Object
- err = json.Unmarshal(buf, &o2)
- require.NoError(t, err)
- o2Bytes, err := o2.BinaryField.Bytes()
- require.NoError(t, err)
- assert.Equal(t, []byte("hello"), o2Bytes)
-
- // Ensure it also works via pointer.
- type Object2 struct {
- BinaryFieldPtr *File `json:"binary_field"`
- }
-
- var o3 Object2
- var f File
- f.InitFromBytes([]byte("hello"), "")
- o3.BinaryFieldPtr = &f
- buf, err = json.Marshal(o)
- require.NoError(t, err)
- t.Log(string(buf))
-
- var o4 Object2
- err = json.Unmarshal(buf, &o4)
- require.NoError(t, err)
- o4Bytes, err := o4.BinaryFieldPtr.Bytes()
- require.NoError(t, err)
- assert.Equal(t, []byte("hello"), o4Bytes)
-
-}
diff --git a/pkg/types/regexes.go b/pkg/types/regexes.go
deleted file mode 100644
index 94f17df58e..0000000000
--- a/pkg/types/regexes.go
+++ /dev/null
@@ -1,11 +0,0 @@
-package types
-
-import "regexp"
-
-const (
- emailRegexString = "^(?:(?:(?:(?:[a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+(?:\\.([a-zA-Z]|\\d|[!#\\$%&'\\*\\+\\-\\/=\\?\\^_`{\\|}~]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])+)*)|(?:(?:\\x22)(?:(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(?:\\x20|\\x09)+)?(?:(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x7f]|\\x21|[\\x23-\\x5b]|[\\x5d-\\x7e]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[\\x01-\\x09\\x0b\\x0c\\x0d-\\x7f]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}]))))*(?:(?:(?:\\x20|\\x09)*(?:\\x0d\\x0a))?(\\x20|\\x09)+)?(?:\\x22))))@(?:(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|\\d|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.)+(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])|(?:(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])(?:[a-zA-Z]|\\d|-|\\.|~|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])*(?:[a-zA-Z]|[\\x{00A0}-\\x{D7FF}\\x{F900}-\\x{FDCF}\\x{FDF0}-\\x{FFEF}])))\\.?$"
-)
-
-var (
- emailRegex = regexp.MustCompile(emailRegexString)
-)
diff --git a/pkg/types/uuid.go b/pkg/types/uuid.go
deleted file mode 100644
index 56b443ea83..0000000000
--- a/pkg/types/uuid.go
+++ /dev/null
@@ -1,8 +0,0 @@
-package types
-
-import (
- "github.com/google/uuid"
-)
-
-// Deprecated: This has been replaced by github.com/oapi-codegen/runtime/types#UUID
-type UUID = uuid.UUID
diff --git a/pkg/types/uuid_test.go b/pkg/types/uuid_test.go
deleted file mode 100644
index bb62040b6c..0000000000
--- a/pkg/types/uuid_test.go
+++ /dev/null
@@ -1,53 +0,0 @@
-package types
-
-import (
- "encoding/json"
- "testing"
-
- "github.com/google/uuid"
- "github.com/stretchr/testify/assert"
-)
-
-func TestUUID_MarshalJSON_Zero(t *testing.T) {
- var testUUID UUID
- b := struct {
- UUIDField UUID `json:"uuid"`
- }{
- UUIDField: testUUID,
- }
- marshaled, err := json.Marshal(b)
- assert.NoError(t, err)
- assert.JSONEq(t, `{"uuid":"00000000-0000-0000-0000-000000000000"}`, string(marshaled))
-}
-
-func TestUUID_MarshalJSON_Pass(t *testing.T) {
- testUUID := uuid.MustParse("9cb14230-b640-11ec-b909-0242ac120002")
- b := struct {
- UUIDField UUID `json:"uuid"`
- }{
- UUIDField: testUUID,
- }
- jsonBytes, err := json.Marshal(b)
- assert.NoError(t, err)
- assert.JSONEq(t, `{"uuid":"9cb14230-b640-11ec-b909-0242ac120002"}`, string(jsonBytes))
-}
-
-func TestUUID_UnmarshalJSON_Fail(t *testing.T) {
- jsonStr := `{"uuid":"this-is-not-a-uuid"}`
- b := struct {
- UUIDField UUID `json:"uuid"`
- }{}
- err := json.Unmarshal([]byte(jsonStr), &b)
- assert.Error(t, err)
-}
-
-func TestUUID_UnmarshalJSON_Pass(t *testing.T) {
- testUUID := uuid.MustParse("9cb14230-b640-11ec-b909-0242ac120002")
- jsonStr := `{"uuid":"9cb14230-b640-11ec-b909-0242ac120002"}`
- b := struct {
- UUIDField UUID `json:"uuid"`
- }{}
- err := json.Unmarshal([]byte(jsonStr), &b)
- assert.NoError(t, err)
- assert.Equal(t, testUUID, b.UUIDField)
-}
diff --git a/pkg/util/isjson.go b/pkg/util/isjson.go
index 63f63729b8..5013ba7a74 100644
--- a/pkg/util/isjson.go
+++ b/pkg/util/isjson.go
@@ -1,7 +1,14 @@
package util
-import "strings"
+import (
+ "mime"
+ "strings"
+)
func IsMediaTypeJson(mediaType string) bool {
- return mediaType == "application/json" || strings.HasSuffix(mediaType, "+json")
+ parsed, _, err := mime.ParseMediaType(mediaType)
+ if err != nil {
+ return false
+ }
+ return parsed == "application/json" || strings.HasSuffix(parsed, "+json")
}
diff --git a/pkg/util/isjson_test.go b/pkg/util/isjson_test.go
index be3cd2463c..8271aef49b 100644
--- a/pkg/util/isjson_test.go
+++ b/pkg/util/isjson_test.go
@@ -41,6 +41,18 @@ func TestIsMediaTypeJson(t *testing.T) {
mediaType: "application/vnd.api+json",
want: true,
},
+ {
+ // NOTE that this _technically_ isn't a standard extension to JSON https://www.iana.org/assignments/media-types/application/json but due to the fact that several APIs do use it, we should support it
+ name: "When MediaType is application/json;v=1, returns true",
+ mediaType: "application/json;v=1",
+ want: true,
+ },
+ {
+ // NOTE that this _technically_ isn't a standard extension to JSON https://www.iana.org/assignments/media-types/application/json but due to the fact that several APIs do use it, we should support it
+ name: "When MediaType is application/json;version=1, returns true",
+ mediaType: "application/json;version=1",
+ want: true,
+ },
}
for _, test := range suite {
t.Run(test.name, func(t *testing.T) {
diff --git a/pkg/util/loader.go b/pkg/util/loader.go
index c3ab6d2865..3a3264e832 100644
--- a/pkg/util/loader.go
+++ b/pkg/util/loader.go
@@ -1,9 +1,15 @@
package util
import (
+ "bytes"
+ "fmt"
"net/url"
+ "path/filepath"
+ "strings"
"github.com/getkin/kin-openapi/openapi3"
+ "github.com/speakeasy-api/openapi/overlay/loader"
+ "gopkg.in/yaml.v3"
)
func LoadSwagger(filePath string) (swagger *openapi3.T, err error) {
@@ -19,19 +25,80 @@ func LoadSwagger(filePath string) (swagger *openapi3.T, err error) {
}
}
-func LoadSwaggerWithCircularReferenceCount(filePath string, circularReferenceCount int) (swagger *openapi3.T, err error) {
- // get a copy of the existing count
- existingCircularReferenceCount := openapi3.CircularReferenceCounter
- if circularReferenceCount > 0 {
- openapi3.CircularReferenceCounter = circularReferenceCount
+// Deprecated: In kin-openapi v0.126.0 (https://github.com/getkin/kin-openapi/tree/v0.126.0?tab=readme-ov-file#v01260) the Circular Reference Counter functionality was removed, instead resolving all references with backtracking, to avoid needing to provide a limit to reference counts.
+//
+// This is now identital in method as `LoadSwagger`.
+func LoadSwaggerWithCircularReferenceCount(filePath string, _ int) (swagger *openapi3.T, err error) {
+ return LoadSwagger(filePath)
+}
+
+type LoadSwaggerWithOverlayOpts struct {
+ Path string
+ Strict bool
+}
+
+func LoadSwaggerWithOverlay(filePath string, opts LoadSwaggerWithOverlayOpts) (swagger *openapi3.T, err error) {
+ spec, err := LoadSwagger(filePath)
+ if err != nil {
+ return nil, fmt.Errorf("failed to load OpenAPI specification: %w", err)
+ }
+
+ if opts.Path == "" {
+ return spec, nil
}
- swagger, err = LoadSwagger(filePath)
+ // parse out the yaml.Node, which is required by the overlay library
+ buf := &bytes.Buffer{}
+ enc := yaml.NewEncoder(buf)
+ // set to 2 to work around https://github.com/yaml/go-yaml/issues/76
+ enc.SetIndent(2)
+ err = enc.Encode(spec)
+ if err != nil {
+ return nil, fmt.Errorf("failed to marshal spec from %#v as YAML: %w", filePath, err)
+ }
+
+ var node yaml.Node
+ err = yaml.NewDecoder(buf).Decode(&node)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse spec from %#v: %w", filePath, err)
+ }
+
+ overlay, err := loader.LoadOverlay(opts.Path)
+ if err != nil {
+ return nil, fmt.Errorf("failed to load Overlay from %#v: %v", opts.Path, err)
+ }
+
+ err = overlay.Validate()
+ if err != nil {
+ return nil, fmt.Errorf("the Overlay in %#v was not valid: %v", opts.Path, err)
+ }
+
+ if opts.Strict {
+ vs, err := overlay.ApplyToStrict(&node)
+ if err != nil {
+ return nil, fmt.Errorf("failed to apply Overlay %#v to specification %#v: %v\nAdditionally, the following validation errors were found:\n- %s", opts.Path, filePath, err, strings.Join(vs, "\n- "))
+ }
+ } else {
+ err = overlay.ApplyTo(&node)
+ if err != nil {
+ return nil, fmt.Errorf("failed to apply Overlay %#v to specification %#v: %v", opts.Path, filePath, err)
+ }
+ }
+
+ b, err := yaml.Marshal(&node)
+ if err != nil {
+ return nil, fmt.Errorf("failed to serialize Overlay'd specification %#v: %v", opts.Path, err)
+ }
+
+ loader := openapi3.NewLoader()
+ loader.IsExternalRefsAllowed = true
- if circularReferenceCount > 0 {
- // and make sure to reset it
- openapi3.CircularReferenceCounter = existingCircularReferenceCount
+ swagger, err = loader.LoadFromDataWithPath(b, &url.URL{
+ Path: filepath.ToSlash(filePath),
+ })
+ if err != nil {
+ return nil, fmt.Errorf("failed to serialize Overlay'd specification %#v: %v", opts.Path, err)
}
- return swagger, err
+ return swagger, nil
}
diff --git a/renovate.json b/renovate.json
index cf87ba3dd6..fd7d48d244 100644
--- a/renovate.json
+++ b/renovate.json
@@ -2,5 +2,87 @@
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"extends": [
"local>oapi-codegen/renovate-config"
+ ],
+ "gomod": {
+ "ignorePaths": []
+ },
+ "vulnerabilityAlerts": {
+ "commitMessageSuffix": "{{#if isGroup }}{{ else }} ({{#if packageFileDir}}{{packageFileDir}}{{else}}{{packageFile}}{{/if}}){{/if}} [SECURITY]"
+ },
+ "packageRules": [
+ {
+ "description": "Ensure that each directory has their own set of dependency updates, split by the parent directory of the package file (`packageFileDir`). Groups will be unaffected.",
+ "matchFileNames": [
+ "**/*"
+ ],
+ "additionalBranchPrefix": "{{#if isGroup }}{{ else }}{{#if packageFileDir}}{{packageFileDir}}/{{else}}{{packageFile}}/{{/if}}{{/if}}",
+ "commitMessageSuffix": "{{#if isGroup }}{{ else }} ({{#if packageFileDir}}{{packageFileDir}}{{else}}{{packageFile}}{{/if}}){{/if}}"
+ },
+ {
+ "description": "Label example/test code separately",
+ "matchFileNames": [
+ "internal/test/**/*",
+ "examples/**/*"
+ ],
+ "labels": [
+ "dependencies-test-only"
+ ]
+ },
+ {
+ "description": "Don't attempt to bump dependencies if they're only used in example code, but allow manually forcing them via Dependency Dashboard",
+ "matchFileNames": [
+ "internal/test/**/*",
+ "examples/**/*"
+ ],
+ "dependencyDashboardApproval": true
+ },
+ {
+ "description": "Don't attempt to bump `replace` statements for internal modules",
+ "matchDepNames": [
+ "github.com/oapi-codegen/oapi-codegen/v2"
+ ],
+ "matchCurrentVersion": "v2.0.0-00010101000000-000000000000",
+ "enabled": false
+ },
+ {
+ "description": "Don't attempt to bump `replace` statements for internal modules",
+ "matchDepNames": [
+ "github.com/oapi-codegen/oapi-codegen/v2/internal/test"
+ ],
+ "matchCurrentVersion": "v0.0.0-00010101000000-000000000000",
+ "enabled": false
+ },
+ {
+ "description": "Run `make tidy` after updates to Go modules",
+ "matchFileNames": [
+ "go.mod",
+ "go.sum",
+ "**/*/go.mod",
+ "**/*/go.sum"
+ ],
+ "postUpgradeTasks": {
+ "commands": [
+ "make tidy"
+ ],
+ "fileFilters": [
+ "**/*/go.mod",
+ "**/*/go.sum"
+ ],
+ "executionMode": "branch"
+ }
+ }
+ ],
+ "customManagers": [
+ {
+ "customType": "regex",
+ "managerFilePatterns": [
+ "README.md"
+ ],
+ "matchStrings": [
+ "# yaml-language-server: \\$schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/(?[^/]+)/configuration-schema.json"
+ ],
+ "depNameTemplate": "github.com/oapi-codegen/oapi-codegen/v2",
+ "datasourceTemplate": "go"
+ }
]
}