-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 46a81612c6..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:
version:
- - "1.20"
- - "1.21"
- - "1.22"
+ - "1.26"
+ - "1.25"
steps:
- name: Check out source code
- uses: actions/checkout@v4
+ uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up Go
- uses: actions/setup-go@v5
+ uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
with:
go-version: ${{ matrix.version }}
- - name: Test
- run: make test
+ - 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
-
- - name: Build
- run: go build ./cmd/oapi-codegen
diff --git a/.github/workflows/generate.yml b/.github/workflows/generate.yml
deleted file mode 100644
index a05186cd50..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:
- version:
- - "1.20"
- - "1.21"
- - "1.22"
- steps:
- - name: Check out source code
- uses: actions/checkout@v4
-
- - name: Set up Go
- uses: actions/setup-go@v5
- with:
- go-version: ${{ matrix.version }}
-
- - name: Run `make generate`
- run: make generate
- 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
-
- - 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 f560f5e6e4..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:
- version:
- - "1.20"
- - "1.21"
- - "1.22"
- steps:
- - name: Check out source code
- uses: actions/checkout@v4
-
- - name: Set up Go
- uses: actions/setup-go@v5
- with:
- go-version: ${{ matrix.version }}
-
- - name: Run `make lint-ci`
- run: make lint-ci
- 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/release-drafter.yml b/.github/workflows/release-drafter.yml
index 9e02696343..4a05c48b70 100644
--- a/.github/workflows/release-drafter.yml
+++ b/.github/workflows/release-drafter.yml
@@ -16,7 +16,7 @@ jobs:
pull-requests: write
runs-on: ubuntu-latest
steps:
- - uses: release-drafter/release-drafter@v6
+ - uses: release-drafter/release-drafter@c2e2804cc59f45f57076a99af580d0fedb697927 # v7.3.0
with:
name: next
tag: next
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 687320a100..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:
- version:
- - "1.20"
- - "1.21"
- - "1.22"
- steps:
- - name: Check out source code
- uses: actions/checkout@v4
-
- - name: Set up Go
- uses: actions/setup-go@v5
- with:
- go-version: ${{ matrix.version }}
-
- - name: Install `tidied`
- run: go install gitlab.com/jamietanna/tidied@latest
-
- - name: Check for no untracked files
- run: make tidy-ci
- 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/.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
index 137f45c25f..9790225376 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -26,7 +26,7 @@ This may get converted into a feature request if we don't deem it a bug, but a m
### 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/deepmap/oapi-codegen/discussions) which allow the community to answer them more easily.
+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
@@ -35,7 +35,7 @@ If you are making changes to the codebase that affects the code that gets genera
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 likely 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.
+> 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.
@@ -51,6 +51,8 @@ Features that amend the way existing codegen works should - ideally - be behind
> [!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:
@@ -86,6 +88,11 @@ 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.
diff --git a/Makefile b/Makefile
index 7732fbc244..5b72cd3840 100644
--- a/Makefile
+++ b/Makefile
@@ -10,7 +10,7 @@ help:
@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.59.1
+ 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
@@ -23,7 +23,7 @@ lint: tools
lint-ci: tools
# for the root module, explicitly run the step, to prevent recursive calls
- $(GOBIN)/golangci-lint run ./... --out-format=colored-line-number --timeout=5m
+ $(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'
diff --git a/README.md b/README.md
index 38d6671ce1..c8d3d770ef 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,7 @@
# `oapi-codegen`
+[](https://www.bestpractices.dev/projects/9450)
+
`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).
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.
@@ -40,25 +42,19 @@ go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
## Install
-It is recommended to follow [the `tools.go` pattern](https://www.jvt.me/posts/2022/06/15/go-tools-dependency-management/) for managing the dependency of `oapi-codegen` alongside your core application.
-
-This would give you a `tools/tools.go`:
-
-```go
-//go:build tools
-// +build tools
+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.
-package main
+To do this, you run `go get -tool`:
-import (
- _ "github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen"
-)
+```sh
+$ go get -tool github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@latest
+# this will then modify your `go.mod`
```
-Then, each invocation of `oapi-codegen` would be used like so:
+From there, each invocation of `oapi-codegen` would be used like so:
```go
-//go:generate go run github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config=config.yaml ../../api.yaml
+//go:generate go tool oapi-codegen -config cfg.yaml ../../api.yaml
```
Alternatively, you can install it as a binary with:
@@ -74,9 +70,11 @@ Which then means you can invoke it like so:
//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/deepmap/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.
+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.
@@ -89,7 +87,7 @@ 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/deepmap/oapi-codegen/commit/71e916c59688a6379b5774dfe5904ec222b9a537
+# 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
```
@@ -114,11 +112,13 @@ For full details of what is supported, it's worth checking out [the GoDoc for `c
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/deepmap/oapi-codegen/HEAD/configuration-schema.json
+# 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/).
@@ -370,7 +370,9 @@ We can see that this provides the best means to focus on the implementation of t
- 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/deepmap/oapi-codegen/issues/373)
+ - 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))
@@ -398,6 +400,9 @@ Server
generate flag to enable code generation
+Required Go Version
+
+
Example usage
@@ -412,6 +417,9 @@ Example usage
chi-server
+1.22+
+
+
For a Chi server, you will want a configuration file such as:
@@ -440,6 +448,9 @@ To implement this, check out [the Chi docs](#impl-chi).
echo-server
+1.22+
+
+
For an Echo server, you will want a configuration file such as:
@@ -466,7 +477,9 @@ To implement this, check out [the Echo docs](#impl-echo).
fiber-server
-
+
+1.24+
+
For a Fiber server, you will want a configuration file such as:
@@ -496,6 +509,9 @@ To implement this, check out [the Fiber docs](#impl-fiber).
gin-server
+1.22+
+
+
For a Gin server, you will want a configuration file such as:
@@ -523,7 +539,9 @@ To implement this, check out [the Gin docs](#impl-gin).
gorilla-server
-
+
+1.22+
+
For a gorilla/mux server, you will want a configuration file such as:
@@ -551,7 +569,9 @@ To implement this, check out [the gorilla/mux docs](#impl-gorillamux).
iris-server
-
+
+1.22+
+
For a Iris server, you will want a configuration file such as:
@@ -579,7 +599,9 @@ To implement this, check out [the Iris docs](#impl-iris).
std-http-server
-
+
+1.22+
+
To use purely `net/http` (for Go 1.22+), you will want a configuration file such as:
@@ -650,7 +672,7 @@ type ServerInterface interface {
GetPing(w http.ResponseWriter, r *http.Request)
}
-func HandlerFromMux(si ServerInterface, m *http.ServeMux) http.Handler {
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
return HandlerWithOptions(si, StdHTTPServerOptions{
BaseRouter: m,
})
@@ -1500,7 +1522,7 @@ You can see a little more detail of the generated code in the ["What does it loo
> 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/deepmap/oapi-codegen/HEAD/configuration-schema.json
+# 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!
@@ -1512,6 +1534,9 @@ 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.
@@ -1575,7 +1600,7 @@ components:
And a `cfg.yaml`:
```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
package: client
output: client.gen.go
generate:
@@ -1708,6 +1733,168 @@ func TestClient_canCall() {
}
```
+### 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.
@@ -1742,7 +1929,7 @@ paths:
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/deepmap/oapi-codegen/issues/1512
+ # See https://github.com/oapi-codegen/oapi-codegen/issues/1512
schema:
type: object
properties:
@@ -1775,7 +1962,7 @@ components:
And a `cfg.yaml`:
```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
package: onlymodels
output: only-models.gen.go
generate:
@@ -1804,7 +1991,7 @@ type Client struct {
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/deepmap/oapi-codegen/HEAD/configuration-schema.json
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
package: onlymodels
output: only-models.gen.go
generate:
@@ -1822,10 +2009,13 @@ For a complete example see [`examples/only-models`](examples/only-models).
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
-components:
- schemas:
- User:
- $ref: '../common/api.yaml#/components/schemas/User'
+ 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".
@@ -1867,11 +2057,7 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/User'
-components:
- schemas:
- User:
- $ref: '../common/api.yaml#/components/schemas/User'
+ $ref: '../common/api.yaml#/components/schemas/User'
```
This references the common spec:
@@ -1890,10 +2076,78 @@ components:
- name
```
-And finally we have our configuration file:
+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/deepmap/oapi-codegen/HEAD/configuration-schema.json
+# 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
@@ -1912,10 +2166,10 @@ 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:
+This is because `oapi-codegen` requires the `import-mapping`:
```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
package: admin
output: server.gen.go
generate:
@@ -1943,9 +2197,107 @@ import (
type User = externalRef0.User
```
-If you don't want to do this, an alternate option is to [bundle your multiple OpenAPI files](https://www.jvt.me/posts/2022/02/10/bundle-openapi/) into a single spec.
+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.
-Check out [the import-mapping example](examples/import-mapping/) for the full code.
+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
@@ -1977,7 +2329,7 @@ However, you lose the ability to understand the three cases, as there's no way t
- 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/deepmap/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).
+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:
@@ -1999,6 +2351,8 @@ type S struct {
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:
+
@@ -2008,9 +2362,6 @@ Extension
Description
-
-Example usage
-
@@ -2023,38 +2374,163 @@ Example usage
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.
+`x-go-type-skip-optional-pointer`
-We can see this at play with the following schemas:
+
+
+Do not add a pointer type for optional fields in structs
+
+
-```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:
+
+
+
+`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:
@@ -2083,21 +2559,14 @@ type ClientWithExtension struct {
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
-`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.
@@ -2147,21 +2616,7 @@ type ClientWithExtension struct {
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
-
-
-
+### `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.
@@ -2218,21 +2673,7 @@ type ClientRenamedByExtension struct {
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
-
-
-
+### `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.
@@ -2294,21 +2735,7 @@ type ClientRenamedByExtension struct {
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
-
-
-
+### `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.
@@ -2359,25 +2786,64 @@ type ClientWithExtension struct {
}
```
-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/xomitempty/).
-You can see this in more detail in [the example code](examples/extensions/xgojsonignore/).
+### `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.
-`x-go-json-ignore`
+We can see this at play with the following schemas:
-
-
-When (un)marshaling JSON, ignore field(s)
-
-
-
+```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.
@@ -2451,21 +2917,7 @@ Notice that the `ComplexField` is still generated in full, but the type will the
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
-
-
-
+### `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.
@@ -2522,21 +2974,7 @@ type ClientWithExtension struct {
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
-
-
-
+### `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.
@@ -2581,36 +3019,31 @@ const (
EXP ClientType = "EXP"
)
-// ClientType defines model for ClientType.
-type ClientType string
-
-// Defines values for ClientTypeWithExtension.
+// Defines values for ClientTypeWithNamesExtension.
const (
- Active ClientTypeWithExtension = "ACT"
- Expired ClientTypeWithExtension = "EXP"
+ ClientTypeWithNamesExtensionActive ClientTypeWithNamesExtension = "ACT"
+ ClientTypeWithNamesExtensionExpired ClientTypeWithNamesExtension = "EXP"
)
-// ClientTypeWithExtension defines model for ClientTypeWithExtension.
-type ClientTypeWithExtension string
-```
+// Defines values for ClientTypeWithVarNamesExtension.
+const (
+ ClientTypeWithVarNamesExtensionActive ClientTypeWithVarNamesExtension = "ACT"
+ ClientTypeWithVarNamesExtensionExpired ClientTypeWithVarNamesExtension = "EXP"
+)
-You can see this in more detail in [the example code](examples/extensions/xenumvarnames/).
+// ClientType defines model for ClientType.
+type ClientType string
-
-
-
+// ClientTypeWithNamesExtension defines model for ClientTypeWithNamesExtension.
+type ClientTypeWithNamesExtension string
-
-
+// ClientTypeWithVarNamesExtension defines model for ClientTypeWithVarNamesExtension.
+type ClientTypeWithVarNamesExtension string
+```
-`x-deprecated-reason`
+You can see this in more detail in [the example code](examples/extensions/xenumnames/).
-
-
-Add a GoDoc deprecation warning to a type
-
-
-
+### `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`.
@@ -2668,28 +3101,12 @@ Notice that because we've not set `deprecated: true` to the `name` field, it doe
You can see this in more detail in [the example code](examples/extensions/xdeprecatedreason/).
-
-
-
-
-
-
-
-`x-order`
-
-
-
-Explicitly order struct fields
-
-
-
+### `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.
-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
@@ -2739,21 +3156,8 @@ type ClientWithExtension struct {
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
-
-
-
-`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.
@@ -2797,12 +3201,6 @@ type TypeWithUnexportedField struct {
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.
@@ -2918,10 +3316,24 @@ Middleware library
+
+
+
+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/deepmap/oapi-codegen/issues/1038) to validate the HTTP response with a middleware.
+> 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
@@ -2935,9 +3347,9 @@ If you're using a specification with [Security Schemes](https://spec.openapis.or
> [!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](#request-response-validation-middleware).
+> 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/deepmap/oapi-codegen/issues/1524)
+> 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).
@@ -2991,7 +3403,7 @@ You can specify, through your configuration file, the `output-options.user-templ
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/deepmap/oapi-codegen/HEAD/configuration-schema.json
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
# ...
output-options:
user-templates:
@@ -3000,7 +3412,7 @@ output-options:
typedef.tmpl: no-prefix.tmpl
```
-> [!WARN]
+> [!WARNING]
> We do not interpolate `~` or `$HOME` (or other environment variables) in paths given
### HTTPS paths
@@ -3012,23 +3424,25 @@ It is also possible to use HTTPS URLs.
>
> 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
>
-> This will be disabled by default (but possible to turn back on via configuration) [in the future](https://github.com/deepmap/oapi-codegen/issues/1564)
+> 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/deepmap/oapi-codegen/HEAD/configuration-schema.json
+# 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/deepmap/oapi-codegen/ad5eada4f3ccc28a88477cef62ea21c17fc8aa01/pkg/codegen/templates/client-with-responses.tmpl
+ 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/deepmap/oapi-codegen/v2.1.0/pkg/codegen/templates/client-with-responses.tmpl
+ 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/deepmap/oapi-codegen/master/pkg/codegen/templates/client-with-responses.tmpl
+ client-with-responses.tmpl: https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/master/pkg/codegen/templates/client-with-responses.tmpl
```
> [!WARNING]
@@ -3039,7 +3453,7 @@ output-options:
It's also possible to set the templates inline in the configuration file:
```yaml
-# yaml-language-server: $schema=https://raw.githubusercontent.com/deepmap/oapi-codegen/HEAD/configuration-schema.json
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
# ...
output-options:
user-templates:
@@ -3057,7 +3471,7 @@ output-options:
### Using the Go package
-Alternatively, you are able to use the underlying code generation as a package, which [will be documented in the future](https://github.com/deepmap/oapi-codegen/issues/1487).
+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).
## Additional Properties (`additionalProperties`)
@@ -3066,7 +3480,7 @@ Alternatively, you are able to use the underlying code generation as a package,
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.
> [!NOTE]
-> In the future [this will be possible](https://github.com/deepmap/oapi-codegen/issues/1514) to disable this functionality, and honour the implicit `additionalProperties: true`
+> 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`
Below you can see some examples of how `additionalProperties` affects the generated code.
@@ -3421,6 +3835,88 @@ func (a Thing) MarshalJSON() ([]byte, error) {
+## Globally skipping the "optional pointer"
+
+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.
+
+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.
+
+As of `oapi-codegen` v2.5.0, this can be tuned in two specific ways, via the following `output-options:`:
+
+- `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+**
+
+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).
+
+For example, when combining both options:
+
+```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
+```
+
+When we have the following spec:
+
+```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
+```
+
+We then generate the following Go code:
+
+```go
+// ...
+
+// 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
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.
@@ -3643,11 +4139,20 @@ Here are a few we've found around the Web:
- [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)
Got one to add? Please raise a PR!
## Frequently Asked Questions (FAQs)
+### Does `oapi-codegen` support OpenAPI 3.1?
+
+No, we don't currently.
+
+OpenAPI 3.1 support is [awaiting upstream support](https://github.com/oapi-codegen/oapi-codegen/issues/373).
+
+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.
+
### How does `oapi-codegen` handle `anyOf`, `allOf` and `oneOf`?
`oapi-codegen` supports `anyOf`, `allOf` and `oneOf` for generated code.
@@ -3689,7 +4194,7 @@ components:
- 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/deepmap/oapi-codegen/issues/1569
+ # https://github.com/oapi-codegen/oapi-codegen/issues/1569
IdentityWithDuplicateField:
allOf:
# `issuer` will be ignored
@@ -3924,7 +4429,7 @@ By default, `oapi-codegen` will generate everything from the specification.
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/deepmap/oapi-codegen/HEAD/configuration-schema.json
+# yaml-language-server: $schema=https://raw.githubusercontent.com/oapi-codegen/oapi-codegen/HEAD/configuration-schema.json
output-options:
include-tags: []
exclude-tags: []
@@ -3959,17 +4464,23 @@ This may lead to breakage in your consuming code, and if so, sorry that's happen
We'll be aware of the issue, and will work to update both the core `oapi-codegen` and the middlewares accordingly.
-## Sponsors
+## Contributors
-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/deepmap/oapi-codegen/discussions/1606), we're looking to make this a more sustainable project in the future.
+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 💜
-We're very appreciative of [the many contributors over the years](https://github.com/deepmap/oapi-codegen/graphs/contributors) and the ongoing use of the project 💜
+
+
+
+
+## Sponsors
+
+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.
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.
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.
-We are currently generously sponsored by the following folks, each of whom provide sponsorship for 1 hour of work a month:
+We are also generously sponsored by the following folks, each of whom provide sponsorship for 1 hour of work a month:
@@ -3982,22 +4493,8 @@ We are currently generously sponsored by the following folks, each of whom provi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
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 22e147c6de..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,13 @@ import (
"runtime/debug"
"strings"
- "gopkg.in/yaml.v2"
+ "go.yaml.in/yaml/v3"
"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"
}
@@ -58,7 +59,6 @@ var (
flagExcludeSchemas string
flagResponseTypeSuffix string
flagAliasTypes bool
- flagInitialismOverrides bool
)
type configuration struct {
@@ -111,8 +111,7 @@ func main() {
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(&flagInitialismOverrides, "initialism-overrides", false, "Use initialism overrides.")
+ flag.BoolVar(&flagAliasTypes, "alias-types", false, "Alias type declarations if possible.")
flag.Parse()
@@ -158,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.
@@ -271,41 +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.LoadSwagger(flag.Arg(0))
+ overlayOpts := util.LoadSwaggerWithOverlayOpts{
+ Path: opts.OutputOptions.Overlay.Path,
+ // default to strict, but can be overridden
+ Strict: true,
+ }
+
+ if opts.OutputOptions.Overlay.Strict != nil {
+ overlayOpts.Strict = *opts.OutputOptions.Overlay.Strict
+ }
+
+ swagger, err := util.LoadSwaggerWithOverlay(flag.Arg(0), overlayOpts)
if err != nil {
errExit("error loading swagger spec in %s\n: %s\n", flag.Arg(0), err)
}
if strings.HasPrefix(swagger.OpenAPI, "3.1.") {
- fmt.Println("WARNING: You are using an OpenAPI 3.1.x specification, which is not yet supported by oapi-codegen (https://github.com/deepmap/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")
+ 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.Configuration.NoVCSVersionOverride = &noVCSVersionOverride
+ opts.NoVCSVersionOverride = &noVCSVersionOverride
}
- code, err := codegen.Generate(swagger, opts.Configuration)
- if err != nil {
- errExit("error generating code: %s\n", err)
- }
+ code, genErr := codegen.Generate(swagger, opts.Configuration)
- if opts.OutputFile != "" {
- err = os.WriteFile(opts.OutputFile, []byte(code), 0o644)
- if err != nil {
- errExit("error writing generated code to file: %s\n", err)
+ // 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)
}
}
@@ -436,8 +471,6 @@ func updateConfigFromFlags(cfg *configuration) error {
cfg.OutputFile = flagOutputFile
}
- cfg.OutputOptions.InitialismOverrides = flagInitialismOverrides
-
return nil
}
@@ -489,6 +522,8 @@ 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":
diff --git a/cmd/oapi-codegen/oapi-codegen_test.go b/cmd/oapi-codegen/oapi-codegen_test.go
index 9d9f06c204..f60dbb9afb 100644
--- a/cmd/oapi-codegen/oapi-codegen_test.go
+++ b/cmd/oapi-codegen/oapi-codegen_test.go
@@ -10,7 +10,7 @@ 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
index 836d48ad61..9290cc121a 100644
--- a/configuration-schema.json
+++ b/configuration-schema.json
@@ -29,6 +29,10 @@
"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"
@@ -56,6 +60,10 @@
"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"
}
}
},
@@ -66,15 +74,19 @@
"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/deepmap/oapi-codegen/issues/531"
+ "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/deepmap/oapi-codegen/issues/549"
+ "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/deepmap/oapi-codegen/issues/549"
+ "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",
@@ -82,7 +94,7 @@
},
"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/deepmap/oapi-codegen/issues/604"
+ "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",
@@ -90,11 +102,11 @@
},
"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/deepmap/oapi-codegen/issues/786"
+ "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/deepmap/oapi-codegen/issues/841"
+ "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",
@@ -103,6 +115,14 @@
"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"
}
}
},
@@ -119,6 +139,10 @@
"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.",
@@ -169,9 +193,19 @@
"type": "string",
"description": "Override the default generated client type with the value"
},
- "initialism-overrides": {
- "type": "boolean",
- "description": "Whether to use the initialism overrides"
+ "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",
@@ -182,9 +216,7 @@
"description": "DisableTypeAliasesForType allows defining which OpenAPI `type`s will explicitly not use type aliases",
"items": {
"type": "string",
- "enum": [
- "array"
- ]
+ "enum": ["array"]
}
},
"name-normalizer": {
@@ -196,6 +228,77 @@
"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"
+ }
+ }
}
}
},
@@ -203,7 +306,7 @@
"type": "object",
"additionalProperties": {
"type": "string",
- "description": "ImportMapping specifies the golang package path for each external reference"
+ "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": {
@@ -219,9 +322,7 @@
"type": "string"
}
},
- "required": [
- "package"
- ]
+ "required": ["package"]
},
"description": "AdditionalImports defines any additional Go imports to add to the generated code"
},
@@ -233,5 +334,43 @@
"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
index 93a6cdb16f..41d1778de8 100644
--- a/examples/Makefile
+++ b/examples/Makefile
@@ -2,8 +2,9 @@ lint:
$(GOBIN)/golangci-lint run ./...
lint-ci:
- $(GOBIN)/golangci-lint run ./... --out-format=colored-line-number --timeout=5m
+ $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m
+.PHONY: generate
generate:
go generate ./...
diff --git a/examples/anyof-allof-oneof/api.yaml b/examples/anyof-allof-oneof/api.yaml
index 493d61b663..61c6a494f1 100644
--- a/examples/anyof-allof-oneof/api.yaml
+++ b/examples/anyof-allof-oneof/api.yaml
@@ -32,7 +32,7 @@ components:
- 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/deepmap/oapi-codegen/issues/1569
+ # https://github.com/oapi-codegen/oapi-codegen/issues/1569
IdentityWithDuplicateField:
allOf:
# `issuer` will be ignored
diff --git a/examples/authenticated-api/echo/api/api.gen.go b/examples/authenticated-api/echo/api/api.gen.go
index 383ab5dc25..e3c5d2591a 100644
--- a/examples/authenticated-api/echo/api/api.gen.go
+++ b/examples/authenticated-api/echo/api/api.gen.go
@@ -5,7 +5,7 @@ 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/main.go b/examples/authenticated-api/echo/main.go
index 905f8d8aeb..dc4b42c45a 100644
--- a/examples/authenticated-api/echo/main.go
+++ b/examples/authenticated-api/echo/main.go
@@ -6,7 +6,6 @@ import (
"net"
"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"
)
@@ -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 6eb3067d86..ce18dded1a 100644
--- a/examples/authenticated-api/echo/server/fake_jws.go
+++ b/examples/authenticated-api/echo/server/fake_jws.go
@@ -4,10 +4,10 @@ import (
"crypto/ecdsa"
"fmt"
- "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"
)
@@ -46,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)
}
@@ -63,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
}
@@ -78,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 {
@@ -87,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 5346b77e28..fbd9bd1598 100644
--- a/examples/authenticated-api/echo/server/server.go
+++ b/examples/authenticated-api/echo/server/server.go
@@ -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/stdhttp/Makefile b/examples/authenticated-api/stdhttp/Makefile
deleted file mode 100644
index dac22331f7..0000000000
--- a/examples/authenticated-api/stdhttp/Makefile
+++ /dev/null
@@ -1,36 +0,0 @@
-SHELL:=/bin/bash
-
-YELLOW := \e[0;33m
-RESET := \e[0;0m
-
-GOVER := $(shell go env GOVERSION)
-GOMINOR := $(shell bash -c "cut -f2 -d. <<< $(GOVER)")
-
-define execute-if-go-122
-@{ \
-if [[ 22 -le $(GOMINOR) ]]; then \
- $1; \
-else \
- echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.22, which this module requires$(RESET)"; \
-fi \
-}
-endef
-
-lint:
- $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./...)
-
-lint-ci:
-
- $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --out-format=github-actions --timeout=5m)
-
-generate:
- $(call execute-if-go-122,go generate ./...)
-
-test:
- $(call execute-if-go-122,go test -cover ./...)
-
-tidy:
- $(call execute-if-go-122,go mod tidy)
-
-tidy-ci:
- $(call execute-if-go-122,tidied -verbose)
diff --git a/examples/authenticated-api/stdhttp/api/api.gen.go b/examples/authenticated-api/stdhttp/api/api.gen.go
index a631cdd8c4..979cd32020 100644
--- a/examples/authenticated-api/stdhttp/api/api.gen.go
+++ b/examples/authenticated-api/stdhttp/api/api.gen.go
@@ -7,7 +7,7 @@ package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -22,7 +22,7 @@ import (
)
const (
- BearerAuthScopes = "BearerAuth.Scopes"
+ BearerAuthScopes bearerAuthContextKey = "BearerAuth.Scopes"
)
// Error defines model for Error.
@@ -45,6 +45,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
@@ -185,7 +188,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
}
@@ -223,7 +226,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
}
@@ -291,6 +294,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 {
@@ -307,12 +320,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 {
@@ -329,6 +360,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...)
@@ -540,21 +579,27 @@ 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 *http.ServeMux
+ 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 *http.ServeMux) http.Handler {
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
return HandlerWithOptions(si, StdHTTPServerOptions{
BaseRouter: m,
})
}
-func HandlerFromMuxWithBaseURL(si ServerInterface, m *http.ServeMux, baseURL string) http.Handler {
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
return HandlerWithOptions(si, StdHTTPServerOptions{
BaseURL: baseURL,
BaseRouter: m,
@@ -580,43 +625,45 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
- m.HandleFunc("GET "+options.BaseURL+"/things", wrapper.ListThings)
- m.HandleFunc("POST "+options.BaseURL+"/things", wrapper.AddThing)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/things", wrapper.ListThings)
+ m.HandleFunc(http.MethodPost+" "+options.BaseURL+"/things", wrapper.AddThing)
return m
}
-// 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
@@ -624,7 +671,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) {
@@ -642,12 +689,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()
@@ -673,3 +720,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/stdhttp/go.mod b/examples/authenticated-api/stdhttp/go.mod
deleted file mode 100644
index 9c835ddfaf..0000000000
--- a/examples/authenticated-api/stdhttp/go.mod
+++ /dev/null
@@ -1,41 +0,0 @@
-module github.com/oapi-codegen/oapi-codegen/v2/examples/authenticated-api/stdhttp
-
-go 1.22
-
-replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../
-
-require (
- github.com/getkin/kin-openapi v0.126.0
- github.com/lestrrat-go/jwx v1.2.29
- github.com/oapi-codegen/nethttp-middleware v1.0.2
- github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000
- github.com/oapi-codegen/testutil v1.1.0
- github.com/stretchr/testify v1.9.0
-)
-
-require (
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect
- github.com/go-openapi/jsonpointer v0.21.0 // indirect
- github.com/go-openapi/swag v0.23.0 // indirect
- github.com/goccy/go-json v0.10.2 // indirect
- github.com/gorilla/mux v1.8.1 // indirect
- github.com/invopop/yaml v0.3.1 // indirect
- github.com/josharian/intern v1.0.0 // indirect
- github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect
- github.com/lestrrat-go/blackmagic v1.0.2 // 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/mailru/easyjson v0.7.7 // indirect
- github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // 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
- golang.org/x/crypto v0.22.0 // indirect
- golang.org/x/mod v0.17.0 // indirect
- golang.org/x/text v0.15.0 // indirect
- golang.org/x/tools v0.21.0 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
-)
diff --git a/examples/authenticated-api/stdhttp/go.sum b/examples/authenticated-api/stdhttp/go.sum
deleted file mode 100644
index fdfd5b7273..0000000000
--- a/examples/authenticated-api/stdhttp/go.sum
+++ /dev/null
@@ -1,127 +0,0 @@
-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/getkin/kin-openapi v0.126.0 h1:c2cSgLnAsS0xYfKsgt5oBV6MYRM/giU8/RtwUY4wyfY=
-github.com/getkin/kin-openapi v0.126.0/go.mod h1:7mONz8IwmSRg6RttPu6v8U/OJ+gr+J99qSFNjPGSQqw=
-github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
-github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
-github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
-github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
-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/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
-github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
-github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
-github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
-github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
-github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
-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/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-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.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k=
-github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU=
-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.29 h1:QT0utmUJ4/12rmsVQrJ3u55bycPkKqGYuGT4tyRhxSQ=
-github.com/lestrrat-go/jwx v1.2.29/go.mod h1:hU8k2l6WF0ncx20uQdOmik/Gjg6E3/wIRtXSNFeZuB8=
-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/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
-github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-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/oapi-codegen/nethttp-middleware v1.0.2 h1:A5tfAcKJhWIbIPnlQH+l/DtfVE1i5TFgPlQAiW+l1vQ=
-github.com/oapi-codegen/nethttp-middleware v1.0.2/go.mod h1:DfDalonSO+eRQ3RTb8kYoWZByCCPFRxm9WKq1UbY0E4=
-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/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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
-github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
-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.6.1/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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-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/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
-golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
-golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
-golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
-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.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-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-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.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
-golang.org/x/sync v0.0.0-20190423024810-112230192c58/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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/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-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.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-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/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
-golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
-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.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.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
-golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-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.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.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
-golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
-golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/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-20200313102051-9f266ea9e77c/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=
diff --git a/examples/authenticated-api/stdhttp/server/fake_jws.go b/examples/authenticated-api/stdhttp/server/fake_jws.go
index 6eb3067d86..ce18dded1a 100644
--- a/examples/authenticated-api/stdhttp/server/fake_jws.go
+++ b/examples/authenticated-api/stdhttp/server/fake_jws.go
@@ -4,10 +4,10 @@ import (
"crypto/ecdsa"
"fmt"
- "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"
)
@@ -46,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)
}
@@ -63,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
}
@@ -78,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 {
@@ -87,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/stdhttp/server/jwt_authenticator.go b/examples/authenticated-api/stdhttp/server/jwt_authenticator.go
index 0cecccf04d..163827e24b 100644
--- a/examples/authenticated-api/stdhttp/server/jwt_authenticator.go
+++ b/examples/authenticated-api/stdhttp/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"
)
// JWSValidator is used to validate JWS payloads and return a JWT if they're
@@ -20,9 +20,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
@@ -88,30 +88,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/stdhttp/server/server.go b/examples/authenticated-api/stdhttp/server/server.go
index ddcabaa737..6ed2da28e9 100644
--- a/examples/authenticated-api/stdhttp/server/server.go
+++ b/examples/authenticated-api/stdhttp/server/server.go
@@ -27,7 +27,7 @@ func NewServer() *server {
}
func CreateMiddleware(v JWSValidator) (func(next http.Handler) http.Handler, error) {
- spec, err := api.GetSwagger()
+ spec, err := api.GetSpec()
if err != nil {
return nil, fmt.Errorf("loading spec: %w", err)
}
diff --git a/examples/client/client.gen.go b/examples/client/client.gen.go
index 8ef6b78564..430496de89 100644
--- a/examples/client/client.gen.go
+++ b/examples/client/client.gen.go
@@ -141,7 +141,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
}
@@ -168,7 +168,7 @@ func NewUpdateClientRequest(server string) (*http.Request, error) {
return nil, err
}
- req, err := http.NewRequest("PUT", queryURL.String(), nil)
+ req, err := http.NewRequest(http.MethodPut, queryURL.String(), nil)
if err != nil {
return nil, err
}
@@ -232,6 +232,16 @@ type GetClientResponse struct {
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 {
@@ -248,6 +258,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 ""
+}
+
type UpdateClientResponse struct {
Body []byte
HTTPResponse *http.Response
@@ -256,6 +274,18 @@ type UpdateClientResponse struct {
}
}
+// 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 {
@@ -272,6 +302,14 @@ func (r UpdateClientResponse) StatusCode() int {
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...)
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/import-mapping/common/generate.go b/examples/clienttypenameclash/generate.go
similarity index 87%
rename from examples/import-mapping/common/generate.go
rename to examples/clienttypenameclash/generate.go
index 4e7fe60ec4..e9c9a42f86 100644
--- a/examples/import-mapping/common/generate.go
+++ b/examples/clienttypenameclash/generate.go
@@ -1,3 +1,3 @@
-package common
+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/custom-client-type.gen.go b/examples/custom-client-type/custom-client-type.gen.go
index 6dd2ef0195..adbb290453 100644
--- a/examples/custom-client-type/custom-client-type.gen.go
+++ b/examples/custom-client-type/custom-client-type.gen.go
@@ -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 778f8a210a..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/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
index d1ca870f1f..c5056dd207 100644
--- a/examples/extensions/xdeprecatedreason/api.yaml
+++ b/examples/extensions/xdeprecatedreason/api.yaml
@@ -26,3 +26,7 @@ components:
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/gen.go b/examples/extensions/xdeprecatedreason/gen.go
index aa36e0387e..3855905f92 100644
--- a/examples/extensions/xdeprecatedreason/gen.go
+++ b/examples/extensions/xdeprecatedreason/gen.go
@@ -11,7 +11,9 @@ type Client struct {
// ClientWithExtension defines model for ClientWithExtension.
type ClientWithExtension struct {
- Id *float32 `json:"id,omitempty"`
+ // 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/xenumnames/gen.go b/examples/extensions/xenumnames/gen.go
index 73ebfa656c..7d9596d6b4 100644
--- a/examples/extensions/xenumnames/gen.go
+++ b/examples/extensions/xenumnames/gen.go
@@ -9,18 +9,54 @@ const (
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
diff --git a/examples/extensions/xgotypename/api.yaml b/examples/extensions/xgotypename/api.yaml
index 17b83cb0f0..6c1146a5c8 100644
--- a/examples/extensions/xgotypename/api.yaml
+++ b/examples/extensions/xgotypename/api.yaml
@@ -25,3 +25,18 @@ components:
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/gen.go b/examples/extensions/xgotypename/gen.go
index cc0c9c2bf5..aa3fe0b762 100644
--- a/examples/extensions/xgotypename/gen.go
+++ b/examples/extensions/xgotypename/gen.go
@@ -17,3 +17,8 @@ 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/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/petstore-expanded/stdhttp/tools/tools.go b/examples/extensions/xomitzero/tools/tools.go
similarity index 100%
rename from examples/petstore-expanded/stdhttp/tools/tools.go
rename to examples/extensions/xomitzero/tools/tools.go
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/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 922b6db6cd..909480902e 100644
--- a/examples/go.mod
+++ b/examples/go.mod
@@ -1,116 +1,129 @@
module github.com/oapi-codegen/oapi-codegen/v2/examples
-go 1.20
+go 1.25.9
replace github.com/oapi-codegen/oapi-codegen/v2 => ../
require (
- github.com/getkin/kin-openapi v0.126.0
- github.com/gin-gonic/gin v1.10.0
- github.com/go-chi/chi/v5 v5.0.10
- github.com/gofiber/fiber/v2 v2.52.4
- github.com/google/uuid v1.5.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.6-0.20230908161203-24ba4e8933b9
- github.com/labstack/echo/v4 v4.12.0
- github.com/lestrrat-go/jwx v1.2.26
+ 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.0.2
+ 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.1.0
- github.com/oapi-codegen/testutil v1.0.0
- github.com/stretchr/testify v1.9.0
- golang.org/x/lint v0.0.0-20210508222113-6edffad5e616
+ 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.11.6 // indirect
- github.com/bytedance/sonic/loader v0.1.1 // indirect
- github.com/cloudwego/base64x v0.1.4 // indirect
- github.com/cloudwego/iasm v0.2.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.3 // indirect
- github.com/gin-contrib/sse v0.1.0 // indirect
- github.com/go-openapi/jsonpointer v0.21.0 // indirect
- github.com/go-openapi/swag v0.23.0 // 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.20.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/invopop/yaml v0.3.1 // 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.17.0 // indirect
- github.com/klauspost/cpuid/v2 v2.2.7 // indirect
- github.com/labstack/gommon v0.4.2 // 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/backoff/v2 v2.0.8 // indirect
- github.com/lestrrat-go/blackmagic v1.0.1 // 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.20 // 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.2.2 // 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/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.12 // indirect
+ github.com/ugorji/go/codec v1.3.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
- github.com/valyala/fasthttp v1.51.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.8.0 // indirect
- golang.org/x/crypto v0.23.0 // indirect
- golang.org/x/mod v0.17.0 // indirect
- golang.org/x/net v0.25.0 // indirect
- golang.org/x/sys v0.20.0 // indirect
- golang.org/x/text v0.15.0 // indirect
- golang.org/x/time v0.5.0 // indirect
- golang.org/x/tools v0.21.0 // indirect
- google.golang.org/protobuf v1.34.1 // 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 3ecc5f9e88..0468e46daf 100644
--- a/examples/go.sum
+++ b/examples/go.sum
@@ -1,90 +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.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
-github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
-github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
-github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
-github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
-github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
-github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
-github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
+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.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
-github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
-github.com/getkin/kin-openapi v0.126.0 h1:c2cSgLnAsS0xYfKsgt5oBV6MYRM/giU8/RtwUY4wyfY=
-github.com/getkin/kin-openapi v0.126.0/go.mod h1:7mONz8IwmSRg6RttPu6v8U/OJ+gr+J99qSFNjPGSQqw=
-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.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
-github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
-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.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
-github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
-github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
-github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
+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.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
-github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
-github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
+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.52.4 h1:P+T+4iK7VaqUsq2PALYEfBBo6bJZ4q3FP8cZ84EggTM=
-github.com/gofiber/fiber/v2 v2.52.4/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
-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/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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+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/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.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
-github.com/google/uuid v1.5.0/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/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.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+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.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
-github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
+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=
@@ -92,69 +132,75 @@ 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.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
-github.com/klauspost/compress v1.17.0/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.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
-github.com/klauspost/cpuid/v2 v2.2.7/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.12.0 h1:IKpw49IMryVB2p1a4dzwlhP1O2Tf2E0Ir/450lH+kI0=
-github.com/labstack/echo/v4 v4.12.0/go.mod h1:UP9Cr2DJXbOK3Kr9ONYzNowSh7HP0aG0ShAyycHSJvM=
-github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
-github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
+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/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/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.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
-github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-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.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
-github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
-github.com/mattn/go-isatty v0.0.20/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/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=
@@ -163,32 +209,60 @@ github.com/oapi-codegen/gin-middleware v1.0.2 h1:/H99UzvHQAUxXK8pzdcGAZgjCVeXdFD
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.0.2 h1:A5tfAcKJhWIbIPnlQH+l/DtfVE1i5TFgPlQAiW+l1vQ=
-github.com/oapi-codegen/nethttp-middleware v1.0.2/go.mod h1:DfDalonSO+eRQ3RTb8kYoWZByCCPFRxm9WKq1UbY0E4=
-github.com/oapi-codegen/runtime v1.1.0 h1:rJpoNUawn5XTvekgfkvSZr0RqEnoYpFkyvrzfWeFKWM=
-github.com/oapi-codegen/runtime v1.1.0/go.mod h1:BeSfBkWWWnAnGdyS+S/GnlbmHKzf8/hwkvelJZDeKA8=
-github.com/oapi-codegen/testutil v1.0.0 h1:1GI2IiMMLh2vDHr1OkNacaYU/VaApKdcmfgl4aeXAa8=
-github.com/oapi-codegen/testutil v1.0.0/go.mod h1:ttCaYbHvJtHuiyeBF0tPIX+4uhEPTeizXKx28okijLw=
-github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
-github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
-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/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.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+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=
@@ -196,130 +270,165 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
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.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-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/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
-github.com/ugorji/go/codec v1.2.12/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.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1SqA=
-github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
+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.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
-golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
+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.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
-golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
-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.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
-golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+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-20211019181941-9d821ace8654/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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
-golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+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.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
-golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
-golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
+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.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
-golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+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=
-google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
-google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
+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.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-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.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
index 10dd0cdd45..aeec72f407 100644
--- a/examples/import-mapping/admin/api.yaml
+++ b/examples/import-mapping/admin/api.yaml
@@ -29,8 +29,4 @@ paths:
content:
application/json:
schema:
- $ref: '#/components/schemas/User'
-components:
- schemas:
- User:
- $ref: '../common/api.yaml#/components/schemas/User'
+ $ref: '../common/api.yaml#/components/schemas/User'
diff --git a/examples/import-mapping/admin/cfg.yaml b/examples/import-mapping/multiplepackages/admin/cfg.yaml
similarity index 87%
rename from examples/import-mapping/admin/cfg.yaml
rename to examples/import-mapping/multiplepackages/admin/cfg.yaml
index a888e035a0..65ca92f1b7 100644
--- a/examples/import-mapping/admin/cfg.yaml
+++ b/examples/import-mapping/multiplepackages/admin/cfg.yaml
@@ -8,4 +8,4 @@ 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/common
+ ../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/admin/server.gen.go b/examples/import-mapping/multiplepackages/admin/server.gen.go
similarity index 96%
rename from examples/import-mapping/admin/server.gen.go
rename to examples/import-mapping/multiplepackages/admin/server.gen.go
index 84f881f102..3235142110 100644
--- a/examples/import-mapping/admin/server.gen.go
+++ b/examples/import-mapping/multiplepackages/admin/server.gen.go
@@ -8,14 +8,10 @@ import (
"net/http"
"github.com/go-chi/chi/v5"
- externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/examples/import-mapping/common"
"github.com/oapi-codegen/runtime"
openapi_types "github.com/oapi-codegen/runtime/types"
)
-// User defines model for User.
-type User = externalRef0.User
-
// ServerInterface represents all server handlers.
type ServerInterface interface {
// Get a user's details
@@ -46,11 +42,12 @@ type MiddlewareFunc func(http.Handler) http.Handler
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})
+ 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
diff --git a/examples/import-mapping/common/cfg.yaml b/examples/import-mapping/multiplepackages/common/cfg.yaml
similarity index 100%
rename from examples/import-mapping/common/cfg.yaml
rename to examples/import-mapping/multiplepackages/common/cfg.yaml
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/common/types.gen.go b/examples/import-mapping/multiplepackages/common/types.gen.go
similarity index 100%
rename from examples/import-mapping/common/types.gen.go
rename to examples/import-mapping/multiplepackages/common/types.gen.go
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/echo/api/ping.gen.go b/examples/minimal-server/echo/api/ping.gen.go
index bd78f8f2ad..e376e807d2 100644
--- a/examples/minimal-server/echo/api/ping.gen.go
+++ b/examples/minimal-server/echo/api/ping.gen.go
@@ -48,19 +48,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+"/ping", wrapper.GetPing)
+ router.GET(options.BaseURL+"/ping", wrapper.GetPing, options.OperationMiddlewares["GetPing"]...)
}
diff --git a/examples/minimal-server/fiber/api/ping.gen.go b/examples/minimal-server/fiber/api/ping.gen.go
index a21e6fa956..b926f841bb 100644
--- a/examples/minimal-server/fiber/api/ping.gen.go
+++ b/examples/minimal-server/fiber/api/ping.gen.go
@@ -21,21 +21,36 @@ 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
// GetPing operation middleware
func (siw *ServerInterfaceWrapper) GetPing(c *fiber.Ctx) error {
- return siw.Handler.GetPing(c)
+ 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
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ HandlerMiddlewares []HandlerMiddlewareFunc
}
// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
@@ -46,7 +61,8 @@ 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 {
diff --git a/examples/minimal-server/gorillamux/api/ping.gen.go b/examples/minimal-server/gorillamux/api/ping.gen.go
index 9445d02b53..82ec6ebb5d 100644
--- a/examples/minimal-server/gorillamux/api/ping.gen.go
+++ b/examples/minimal-server/gorillamux/api/ping.gen.go
@@ -158,7 +158,7 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
- r.HandleFunc(options.BaseURL+"/ping", wrapper.GetPing).Methods("GET")
+ r.HandleFunc(options.BaseURL+"/ping", wrapper.GetPing).Methods(http.MethodGet)
return r
}
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/Makefile b/examples/minimal-server/stdhttp/Makefile
deleted file mode 100644
index 66f60e4a23..0000000000
--- a/examples/minimal-server/stdhttp/Makefile
+++ /dev/null
@@ -1,36 +0,0 @@
-SHELL:=/bin/bash
-
-YELLOW := \e[0;33m
-RESET := \e[0;0m
-
-GOVER := $(shell go env GOVERSION)
-GOMINOR := $(shell bash -c "cut -f2 -d. <<< $(GOVER)")
-
-define execute-if-go-122
-@{ \
-if [[ 22 -le $(GOMINOR) ]]; then \
- $1; \
-else \
- echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.22, which this module requires$(RESET)"; \
-fi \
-}
-endef
-
-lint:
- $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./...)
-
-lint-ci:
-
- $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --out-format=colored-line-number --timeout=5m)
-
-generate:
- $(call execute-if-go-122,go generate ./...)
-
-test:
- $(call execute-if-go-122,go test -cover ./...)
-
-tidy:
- $(call execute-if-go-122,go mod tidy)
-
-tidy-ci:
- $(call execute-if-go-122,tidied -verbose)
diff --git a/examples/minimal-server/stdhttp/api/ping.gen.go b/examples/minimal-server/stdhttp/api/ping.gen.go
index 3ce4c5e3e1..0d4ab7751a 100644
--- a/examples/minimal-server/stdhttp/api/ping.gen.go
+++ b/examples/minimal-server/stdhttp/api/ping.gen.go
@@ -119,21 +119,27 @@ 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 *http.ServeMux
+ 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 *http.ServeMux) http.Handler {
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
return HandlerWithOptions(si, StdHTTPServerOptions{
BaseRouter: m,
})
}
-func HandlerFromMuxWithBaseURL(si ServerInterface, m *http.ServeMux, baseURL string) http.Handler {
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
return HandlerWithOptions(si, StdHTTPServerOptions{
BaseURL: baseURL,
BaseRouter: m,
@@ -159,7 +165,7 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
- m.HandleFunc("GET "+options.BaseURL+"/ping", wrapper.GetPing)
+ m.HandleFunc(http.MethodGet+" "+options.BaseURL+"/ping", wrapper.GetPing)
return m
}
diff --git a/examples/minimal-server/stdhttp/go.mod b/examples/minimal-server/stdhttp/go.mod
deleted file mode 100644
index 03570cb92c..0000000000
--- a/examples/minimal-server/stdhttp/go.mod
+++ /dev/null
@@ -1,23 +0,0 @@
-module github.com/oapi-codegen/oapi-codegen/v2/examples/minimal-server/stdhttp
-
-go 1.22
-
-replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../
-
-require github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000
-
-require (
- github.com/getkin/kin-openapi v0.126.0 // indirect
- github.com/go-openapi/jsonpointer v0.21.0 // indirect
- github.com/go-openapi/swag v0.23.0 // indirect
- github.com/invopop/yaml v0.3.1 // indirect
- github.com/josharian/intern v1.0.0 // indirect
- github.com/mailru/easyjson v0.7.7 // indirect
- github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
- github.com/perimeterx/marshmallow v1.1.5 // indirect
- golang.org/x/mod v0.17.0 // indirect
- golang.org/x/text v0.15.0 // indirect
- golang.org/x/tools v0.21.0 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
-)
diff --git a/examples/minimal-server/stdhttp/go.sum b/examples/minimal-server/stdhttp/go.sum
deleted file mode 100644
index b4c574d348..0000000000
--- a/examples/minimal-server/stdhttp/go.sum
+++ /dev/null
@@ -1,47 +0,0 @@
-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/getkin/kin-openapi v0.126.0 h1:c2cSgLnAsS0xYfKsgt5oBV6MYRM/giU8/RtwUY4wyfY=
-github.com/getkin/kin-openapi v0.126.0/go.mod h1:7mONz8IwmSRg6RttPu6v8U/OJ+gr+J99qSFNjPGSQqw=
-github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
-github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
-github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
-github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
-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/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
-github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
-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/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
-github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-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/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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
-github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
-github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
-golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
-golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
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 e95391fd13..0d70421505 100644
--- a/examples/no-vcs-version-override/echo/api/api.gen.go
+++ b/examples/no-vcs-version-override/echo/api/api.gen.go
@@ -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/only-models/api.yaml b/examples/only-models/api.yaml
index 4e3d820663..33820e8f0b 100644
--- a/examples/only-models/api.yaml
+++ b/examples/only-models/api.yaml
@@ -20,7 +20,7 @@ paths:
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/deepmap/oapi-codegen/issues/1512
+ # See https://github.com/oapi-codegen/oapi-codegen/issues/1512
schema:
type: object
properties:
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/internal/test/parameters/config.yaml b/examples/overlay/api/cfg.yaml
similarity index 51%
rename from internal/test/parameters/config.yaml
rename to examples/overlay/api/cfg.yaml
index 64850f5de5..b506fc5679 100644
--- a/internal/test/parameters/config.yaml
+++ b/examples/overlay/api/cfg.yaml
@@ -1,8 +1,10 @@
# yaml-language-server: $schema=../../../configuration-schema.json
-package: parameters
+package: api
+output: ping.gen.go
generate:
- echo-server: true
- client: true
models: true
+ gorilla-server: true
embedded-spec: true
-output: parameters.gen.go
+output-options:
+ overlay:
+ path: overlay.yaml
diff --git a/examples/import-mapping/admin/generate.go b/examples/overlay/api/generate.go
similarity index 88%
rename from examples/import-mapping/admin/generate.go
rename to examples/overlay/api/generate.go
index 0cc4cece11..c025a4570d 100644
--- a/examples/import-mapping/admin/generate.go
+++ b/examples/overlay/api/generate.go
@@ -1,3 +1,3 @@
-package admin
+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/petstore.gen.go b/examples/petstore-expanded/chi/api/petstore.gen.go
index 88b246f37b..338c39e73f 100644
--- a/examples/petstore-expanded/chi/api/petstore.gen.go
+++ b/examples/petstore-expanded/chi/api/petstore.gen.go
@@ -5,8 +5,9 @@ package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
+ "errors"
"fmt"
"net/http"
"net/url"
@@ -117,23 +118,34 @@ type MiddlewareFunc func(http.Handler) http.Handler
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.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
}
@@ -166,11 +178,12 @@ func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request
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", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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
@@ -191,11 +204,12 @@ func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Requ
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", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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
@@ -341,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
@@ -396,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) {
@@ -414,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()
@@ -445,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/petstore.go b/examples/petstore-expanded/chi/petstore.go
index b525fa5763..644b4920ea 100644
--- a/examples/petstore-expanded/chi/petstore.go
+++ b/examples/petstore-expanded/chi/petstore.go
@@ -21,7 +21,7 @@ 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 e9d7662b45..86a9e2cd34 100644
--- a/examples/petstore-expanded/chi/petstore_test.go
+++ b/examples/petstore-expanded/chi/petstore_test.go
@@ -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/petstore-server.gen.go b/examples/petstore-expanded/echo/api/petstore-server.gen.go
index 8767c17a14..8a65c64304 100644
--- a/examples/petstore-expanded/echo/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/echo/api/petstore-server.gen.go
@@ -5,7 +5,7 @@ package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/http"
@@ -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.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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.BindStyledParameterWithOptions("simple", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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/petstore.go b/examples/petstore-expanded/echo/petstore.go
index 5ea0250507..a764f00b04 100644
--- a/examples/petstore-expanded/echo/petstore.go
+++ b/examples/petstore-expanded/echo/petstore.go
@@ -12,7 +12,6 @@ import (
"os"
"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"
)
@@ -21,7 +20,7 @@ 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 5fc058da94..eb3b8c1652 100644
--- a/examples/petstore-expanded/echo/petstore_test.go
+++ b/examples/petstore-expanded/echo/petstore_test.go
@@ -20,7 +20,6 @@ import (
"testing"
"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"
@@ -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)
diff --git a/examples/petstore-expanded/echo/pkg_codegen_petstore_test.go b/examples/petstore-expanded/echo/pkg_codegen_petstore_test.go
index de651ec54f..1f13ce4784 100644
--- a/examples/petstore-expanded/echo/pkg_codegen_petstore_test.go
+++ b/examples/petstore-expanded/echo/pkg_codegen_petstore_test.go
@@ -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 5b01b84a07..fe76a2fba4 100644
--- a/examples/petstore-expanded/fiber/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/fiber/api/petstore-server.gen.go
@@ -5,7 +5,7 @@ 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.BindStyledParameterWithOptions("simple", "id", c.Params("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true})
+ 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.BindStyledParameterWithOptions("simple", "id", c.Params("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true})
+ 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,7 +177,8 @@ 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 {
@@ -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/petstore.go b/examples/petstore-expanded/fiber/petstore.go
index 6332ff8866..eb6ddac31c 100644
--- a/examples/petstore-expanded/fiber/petstore.go
+++ b/examples/petstore-expanded/fiber/petstore.go
@@ -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 dac1d58bf0..7ddc14e426 100644
--- a/examples/petstore-expanded/fiber/petstore_test.go
+++ b/examples/petstore-expanded/fiber/petstore_test.go
@@ -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 02499fcc18..4a2d6f9e5c 100644
--- a/examples/petstore-expanded/gin/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/gin/api/petstore-server.gen.go
@@ -5,7 +5,7 @@ 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.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true})
+ 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.BindStyledParameterWithOptions("simple", "id", c.Param("id"), &id, runtime.BindStyledParameterOptions{Explode: false, Required: true})
+ 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/petstore.go b/examples/petstore-expanded/gin/petstore.go
index 8b0717a4c8..0c0a7e1589 100644
--- a/examples/petstore-expanded/gin/petstore.go
+++ b/examples/petstore-expanded/gin/petstore.go
@@ -19,7 +19,7 @@ import (
)
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/gorilla/api/petstore.gen.go b/examples/petstore-expanded/gorilla/api/petstore.gen.go
index 0ccc7da0b5..3ed8b4c27e 100644
--- a/examples/petstore-expanded/gorilla/api/petstore.gen.go
+++ b/examples/petstore-expanded/gorilla/api/petstore.gen.go
@@ -5,8 +5,9 @@ package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
+ "errors"
"fmt"
"net/http"
"net/url"
@@ -89,23 +90,34 @@ type MiddlewareFunc func(http.Handler) http.Handler
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.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
}
@@ -138,11 +150,12 @@ func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request
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", mux.Vars(r)["id"], &id, runtime.BindStyledParameterOptions{Explode: false, Required: true})
+ 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
@@ -163,11 +176,12 @@ func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Requ
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", mux.Vars(r)["id"], &id, runtime.BindStyledParameterOptions{Explode: false, Required: true})
+ 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
@@ -297,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
@@ -363,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) {
@@ -381,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()
@@ -412,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/petstore.go b/examples/petstore-expanded/gorilla/petstore.go
index d1675f1ae3..8a6eac558c 100644
--- a/examples/petstore-expanded/gorilla/petstore.go
+++ b/examples/petstore-expanded/gorilla/petstore.go
@@ -21,7 +21,7 @@ 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 a6cfedecd8..c3dc320f0b 100644
--- a/examples/petstore-expanded/gorilla/petstore_test.go
+++ b/examples/petstore-expanded/gorilla/petstore_test.go
@@ -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/iris/api/petstore-server.gen.go b/examples/petstore-expanded/iris/api/petstore-server.gen.go
index a559c238d5..f5bcd2cb29 100644
--- a/examples/petstore-expanded/iris/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/iris/api/petstore-server.gen.go
@@ -5,7 +5,7 @@ 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.BindStyledParameterWithOptions("simple", "id", ctx.Params().Get("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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.BindStyledParameterWithOptions("simple", "id", ctx.Params().Get("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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/petstore.go b/examples/petstore-expanded/iris/petstore.go
index 2b2dea37f7..b97b95c5c6 100644
--- a/examples/petstore-expanded/iris/petstore.go
+++ b/examples/petstore-expanded/iris/petstore.go
@@ -17,7 +17,7 @@ import (
)
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/petstore-client.gen.go b/examples/petstore-expanded/petstore-client.gen.go
index 9bd928f497..0b77852791 100644
--- a/examples/petstore-expanded/petstore-client.gen.go
+++ b/examples/petstore-expanded/petstore-client.gen.go
@@ -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/Makefile b/examples/petstore-expanded/stdhttp/Makefile
deleted file mode 100644
index 66f60e4a23..0000000000
--- a/examples/petstore-expanded/stdhttp/Makefile
+++ /dev/null
@@ -1,36 +0,0 @@
-SHELL:=/bin/bash
-
-YELLOW := \e[0;33m
-RESET := \e[0;0m
-
-GOVER := $(shell go env GOVERSION)
-GOMINOR := $(shell bash -c "cut -f2 -d. <<< $(GOVER)")
-
-define execute-if-go-122
-@{ \
-if [[ 22 -le $(GOMINOR) ]]; then \
- $1; \
-else \
- echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.22, which this module requires$(RESET)"; \
-fi \
-}
-endef
-
-lint:
- $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./...)
-
-lint-ci:
-
- $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --out-format=colored-line-number --timeout=5m)
-
-generate:
- $(call execute-if-go-122,go generate ./...)
-
-test:
- $(call execute-if-go-122,go test -cover ./...)
-
-tidy:
- $(call execute-if-go-122,go mod tidy)
-
-tidy-ci:
- $(call execute-if-go-122,tidied -verbose)
diff --git a/examples/petstore-expanded/stdhttp/api/petstore.gen.go b/examples/petstore-expanded/stdhttp/api/petstore.gen.go
index 733981ff92..9ae158e3fd 100644
--- a/examples/petstore-expanded/stdhttp/api/petstore.gen.go
+++ b/examples/petstore-expanded/stdhttp/api/petstore.gen.go
@@ -7,8 +7,9 @@ package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
+ "errors"
"fmt"
"net/http"
"net/url"
@@ -90,23 +91,34 @@ type MiddlewareFunc func(http.Handler) http.Handler
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.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
}
@@ -139,11 +151,12 @@ func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request
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})
+ 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
@@ -164,11 +177,12 @@ func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Requ
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})
+ 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
@@ -259,21 +273,27 @@ 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 *http.ServeMux
+ 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 *http.ServeMux) http.Handler {
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
return HandlerWithOptions(si, StdHTTPServerOptions{
BaseRouter: m,
})
}
-func HandlerFromMuxWithBaseURL(si ServerInterface, m *http.ServeMux, baseURL string) http.Handler {
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
return HandlerWithOptions(si, StdHTTPServerOptions{
BaseURL: baseURL,
BaseRouter: m,
@@ -299,62 +319,63 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
- m.HandleFunc("GET "+options.BaseURL+"/pets", wrapper.FindPets)
- m.HandleFunc("POST "+options.BaseURL+"/pets", wrapper.AddPet)
- m.HandleFunc("DELETE "+options.BaseURL+"/pets/{id}", wrapper.DeletePet)
- m.HandleFunc("GET "+options.BaseURL+"/pets/{id}", wrapper.FindPetByID)
+ 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, 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
@@ -362,7 +383,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) {
@@ -380,12 +401,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()
@@ -411,3 +432,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/stdhttp/go.mod b/examples/petstore-expanded/stdhttp/go.mod
deleted file mode 100644
index 77f95539f5..0000000000
--- a/examples/petstore-expanded/stdhttp/go.mod
+++ /dev/null
@@ -1,34 +0,0 @@
-module github.com/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded/stdhttp
-
-go 1.22
-
-replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../
-
-require (
- github.com/getkin/kin-openapi v0.126.0
- github.com/oapi-codegen/nethttp-middleware v1.0.2
- github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000
- github.com/oapi-codegen/runtime v1.1.0
- github.com/oapi-codegen/testutil v1.0.0
- github.com/stretchr/testify v1.9.0
-)
-
-require (
- github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/go-openapi/jsonpointer v0.21.0 // indirect
- github.com/go-openapi/swag v0.23.0 // indirect
- github.com/google/uuid v1.4.0 // indirect
- github.com/gorilla/mux v1.8.1 // indirect
- github.com/invopop/yaml v0.3.1 // indirect
- github.com/josharian/intern v1.0.0 // indirect
- github.com/mailru/easyjson v0.7.7 // indirect
- github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
- github.com/perimeterx/marshmallow v1.1.5 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- golang.org/x/mod v0.17.0 // indirect
- golang.org/x/text v0.15.0 // indirect
- golang.org/x/tools v0.21.0 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
-)
diff --git a/examples/petstore-expanded/stdhttp/go.sum b/examples/petstore-expanded/stdhttp/go.sum
deleted file mode 100644
index 1527625659..0000000000
--- a/examples/petstore-expanded/stdhttp/go.sum
+++ /dev/null
@@ -1,66 +0,0 @@
-github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
-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/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
-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/getkin/kin-openapi v0.126.0 h1:c2cSgLnAsS0xYfKsgt5oBV6MYRM/giU8/RtwUY4wyfY=
-github.com/getkin/kin-openapi v0.126.0/go.mod h1:7mONz8IwmSRg6RttPu6v8U/OJ+gr+J99qSFNjPGSQqw=
-github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
-github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
-github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
-github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
-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/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
-github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
-github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
-github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
-github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
-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/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
-github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
-github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-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/oapi-codegen/nethttp-middleware v1.0.2 h1:A5tfAcKJhWIbIPnlQH+l/DtfVE1i5TFgPlQAiW+l1vQ=
-github.com/oapi-codegen/nethttp-middleware v1.0.2/go.mod h1:DfDalonSO+eRQ3RTb8kYoWZByCCPFRxm9WKq1UbY0E4=
-github.com/oapi-codegen/runtime v1.1.0 h1:rJpoNUawn5XTvekgfkvSZr0RqEnoYpFkyvrzfWeFKWM=
-github.com/oapi-codegen/runtime v1.1.0/go.mod h1:BeSfBkWWWnAnGdyS+S/GnlbmHKzf8/hwkvelJZDeKA8=
-github.com/oapi-codegen/testutil v1.0.0 h1:1GI2IiMMLh2vDHr1OkNacaYU/VaApKdcmfgl4aeXAa8=
-github.com/oapi-codegen/testutil v1.0.0/go.mod h1:ttCaYbHvJtHuiyeBF0tPIX+4uhEPTeizXKx28okijLw=
-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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
-github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
-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/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
-github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
-golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
-golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/examples/petstore-expanded/stdhttp/petstore.go b/examples/petstore-expanded/stdhttp/petstore.go
index 68e45cc1d7..043e60b841 100644
--- a/examples/petstore-expanded/stdhttp/petstore.go
+++ b/examples/petstore-expanded/stdhttp/petstore.go
@@ -22,7 +22,7 @@ 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/stdhttp/petstore_test.go b/examples/petstore-expanded/stdhttp/petstore_test.go
index bf3df022d2..ce6322c946 100644
--- a/examples/petstore-expanded/stdhttp/petstore_test.go
+++ b/examples/petstore-expanded/stdhttp/petstore_test.go
@@ -25,7 +25,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/strict/api/petstore-server.gen.go b/examples/petstore-expanded/strict/api/petstore-server.gen.go
index f1ba3d6d44..e35edad725 100644
--- a/examples/petstore-expanded/strict/api/petstore-server.gen.go
+++ b/examples/petstore-expanded/strict/api/petstore-server.gen.go
@@ -5,10 +5,11 @@ 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.
@@ -78,23 +78,34 @@ type MiddlewareFunc func(http.Handler) http.Handler
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.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
}
@@ -127,11 +138,12 @@ func (siw *ServerInterfaceWrapper) AddPet(w http.ResponseWriter, r *http.Request
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", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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
@@ -152,11 +164,12 @@ func (siw *ServerInterfaceWrapper) DeletePet(w http.ResponseWriter, r *http.Requ
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", chi.URLParam(r, "id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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
@@ -313,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 {
@@ -325,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 {
@@ -342,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 {
@@ -354,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 {
@@ -382,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 {
@@ -399,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 {
@@ -411,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.
@@ -433,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)
@@ -571,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
@@ -626,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) {
@@ -644,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()
@@ -675,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/petstore.go b/examples/petstore-expanded/strict/petstore.go
index 363caf7e1a..e7dc41a97f 100644
--- a/examples/petstore-expanded/strict/petstore.go
+++ b/examples/petstore-expanded/strict/petstore.go
@@ -21,7 +21,7 @@ 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 208b65ea3e..1ec6a76ea4 100644
--- a/examples/petstore-expanded/strict/petstore_test.go
+++ b/examples/petstore-expanded/strict/petstore_test.go
@@ -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/go.mod b/go.mod
index f3acdd1612..c28ff81291 100644
--- a/go.mod
+++ b/go.mod
@@ -1,26 +1,28 @@
module github.com/oapi-codegen/oapi-codegen/v2
-go 1.20
+go 1.25.9
require (
- github.com/getkin/kin-openapi v0.126.0
- github.com/stretchr/testify v1.9.0
- golang.org/x/text v0.15.0
- golang.org/x/tools v0.21.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/davecgh/go-spew v1.1.1 // indirect
- github.com/go-openapi/jsonpointer v0.21.0 // indirect
- github.com/go-openapi/swag v0.23.0 // indirect
- github.com/invopop/yaml v0.3.1 // indirect
- github.com/josharian/intern v1.0.0 // indirect
- github.com/mailru/easyjson v0.7.7 // indirect
- github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
- github.com/perimeterx/marshmallow v1.1.5 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/ugorji/go/codec v1.2.11 // indirect
- golang.org/x/mod v0.17.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 d932d898bd..7637121b6a 100644
--- a/go.sum
+++ b/go.sum
@@ -1,41 +1,169 @@
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+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/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/getkin/kin-openapi v0.126.0 h1:c2cSgLnAsS0xYfKsgt5oBV6MYRM/giU8/RtwUY4wyfY=
-github.com/getkin/kin-openapi v0.126.0/go.mod h1:7mONz8IwmSRg6RttPu6v8U/OJ+gr+J99qSFNjPGSQqw=
-github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
-github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
-github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
-github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
-github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
-github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
-github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
-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/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/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-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/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
-github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-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/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/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/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
-github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
-golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
-golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+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/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.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-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-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-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-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.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-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/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.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-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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/internal/test/Makefile b/internal/test/Makefile
index 93a6cdb16f..5ec0edd058 100644
--- a/internal/test/Makefile
+++ b/internal/test/Makefile
@@ -2,7 +2,7 @@ lint:
$(GOBIN)/golangci-lint run ./...
lint-ci:
- $(GOBIN)/golangci-lint run ./... --out-format=colored-line-number --timeout=5m
+ $(GOBIN)/golangci-lint run ./... --output.text.path=stdout --timeout=5m
generate:
go generate ./...
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 db5fd302cd..2f16c10b84 100644
--- a/internal/test/all_of/v1/openapi.gen.go
+++ b/internal/test/all_of/v1/openapi.gen.go
@@ -5,7 +5,7 @@ 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 ab430340d6..965051eec5 100644
--- a/internal/test/all_of/v2/openapi.gen.go
+++ b/internal/test/all_of/v2/openapi.gen.go
@@ -5,7 +5,7 @@ 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/param.gen.go b/internal/test/any_of/param/param.gen.go
index 3378ae3da1..69e50dd32e 100644
--- a/internal/test/any_of/param/param.gen.go
+++ b/internal/test/any_of/param/param.gen.go
@@ -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/client/client.gen.go b/internal/test/client/client.gen.go
index 275c72cf0f..aa6d0a4c7d 100644
--- a/internal/test/client/client.gen.go
+++ b/internal/test/client/client.gen.go
@@ -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/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 95257707b1..85680e232c 100644
--- a/internal/test/components/components.gen.go
+++ b/internal/test/components/components.gen.go
@@ -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
}
@@ -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
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/externalref/externalref.cfg.yaml b/internal/test/externalref/externalref.cfg.yaml
index 22a76c3ffd..56ecbbc41c 100644
--- a/internal/test/externalref/externalref.cfg.yaml
+++ b/internal/test/externalref/externalref.cfg.yaml
@@ -5,8 +5,8 @@ generate:
embedded-spec: true
import-mapping:
./packageA/spec.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageA
- ./packageB/spec.yaml: github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageB
- https://petstore3.swagger.io/api/v3/openapi.json: github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/petstore
+ ./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 eee3f68f71..808391ca48 100644
--- a/internal/test/externalref/externalref.gen.go
+++ b/internal/test/externalref/externalref.gen.go
@@ -5,7 +5,7 @@ package externalref
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/url"
@@ -14,46 +14,49 @@ import (
"github.com/getkin/kin-openapi/openapi3"
externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageA"
- externalRef1 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/packageB"
- externalRef2 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/externalref/petstore"
+ 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 *externalRef2.Pet `json:"pet,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/6RUTW/bMAz9KwG3o9Bk6LCDb213Xw7bqSgMRmYcbbakSUzWoNB/Hyg1jROnSLJdDJof",
- "D+890n4B7XrvLFmOUL1A1CvqMYcPzjIaS0FefHCeAhvKJbf4SZprlPhjoCVU8GG6B5q+okw96l/Y0l0d",
- "Pen6W566g6R2AIsLAe6HAPcDAH0O4K0vKfDE59rRm3pzWztPVsI5MaSUFBzlH5CpdWE7dsY08qRn7H1H",
- "UH1SsHShR4YKjOUvn0EBbz2VV2opCDGLPR2MwVfXxn1r5GBsC0LkNVNkgYLnvpPJggB6x+sE53lRf0hX",
- "D4Rc4cub/qRGimf/KLlxbWtoLFqBXzl2P0JXDGbqc3DYduzEbmZoGoaA233nn4DeUwMVhzVJW2TkdcZu",
- "KOpgPBtnBYt4UmoTYye8oklkF4Qq2XUP1SPgBk2Hi05ynmxTGEXXNfB0QhBje6jlCuu/Y4G4RFJSEOj3",
- "2gRJPRZrhnY+nbsnn+9/dErC4Z3Lv2L11x43Y+kafvrYNEa2hN18QEbUH6PJHZ38G42EvMPvv39aaU/h",
- "qHQphZQxjF26XDScPxxQsKEQy61mnmVNUMHtzexmJitHXglwSn8DAAD//xIv2MTwBQAA",
+ "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
@@ -61,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) {
@@ -76,21 +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 externalRef1.PathToRawSpec(path.Join(pathPrefix, "./packageB/spec.yaml")) {
+ 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 externalRef2.PathToRawSpec(path.Join(pathPrefix, "https://petstore3.swagger.io/api/v3/openapi.json")) {
+ 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
}
@@ -99,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()
@@ -130,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 34fd0ec11e..7b84c6d0ef 100644
--- a/internal/test/externalref/imports_test.go
+++ b/internal/test/externalref/imports_test.go
@@ -18,15 +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 = petstore.GetSwagger()
+ _, err = petstore.GetSpec()
require.Nil(t, err)
- _, err = GetSwagger()
+ _, err = GetSpec()
require.Nil(t, err)
}
diff --git a/internal/test/externalref/packageA/externalref.gen.go b/internal/test/externalref/packageA/externalref.gen.go
index c95790d770..1738872708 100644
--- a/internal/test/externalref/packageA/externalref.gen.go
+++ b/internal/test/externalref/packageA/externalref.gen.go
@@ -5,7 +5,7 @@ package packagea
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/url"
@@ -16,35 +16,54 @@ import (
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/4yOMcrDMAxG7/L9/xjI7q25QI8QHKMkbhNZ2OpQgu5e7BS6dOikBw896UBIuyQm1gJ3",
- "oISVdt/wOt0o6KWi5CSUNVIT7HeqU59CcCiaIy+wDqltjFOV/5lmOPz1n37/jvfiw90vNIxFKIznnQFm",
- "1uG7+vUFa43Ic4Ljx7Z1SELsJcIBNa5rOY29AgAA//84dUj5+QAAAA==",
+// 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/externalref.gen.go b/internal/test/externalref/packageB/externalref.gen.go
index c3f879cfda..c02df37aac 100644
--- a/internal/test/externalref/packageB/externalref.gen.go
+++ b/internal/test/externalref/packageB/externalref.gen.go
@@ -5,7 +5,7 @@ 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/externalref.gen.go b/internal/test/externalref/petstore/externalref.gen.go
index c1d5d3e10d..d70f4bec71 100644
--- a/internal/test/externalref/petstore/externalref.gen.go
+++ b/internal/test/externalref/petstore/externalref.gen.go
@@ -5,7 +5,7 @@ package packagea
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"encoding/base64"
"fmt"
"net/url"
@@ -18,8 +18,8 @@ import (
)
const (
- Api_keyScopes = "api_key.Scopes"
- Petstore_authScopes = "petstore_auth.Scopes"
+ Api_keyScopes apiKeyContextKey = "api_key.Scopes"
+ Petstore_authScopes petstoreAuthContextKey = "petstore_auth.Scopes"
)
// Defines values for OrderStatus.
@@ -29,6 +29,20 @@ const (
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"
@@ -36,6 +50,20 @@ const (
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"
@@ -43,6 +71,20 @@ const (
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"`
@@ -124,6 +166,12 @@ type User struct {
// 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
@@ -204,78 +252,80 @@ type UpdateUserJSONRequestBody = User
// UpdateUserFormdataRequestBody defines body for UpdateUser for application/x-www-form-urlencoded ContentType.
type UpdateUserFormdataRequestBody = User
-// 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/+xb/2/jNrL/V/jUB/QVcCwn2b69Gjig2c22yF26GzS7dz0kQUFLY4ldiVRJyo4b5H8/",
- "DEnJ+mrLTpy7ot0fdrUSyRnOfOYr6QcvEGkmOHCtvOmDJ+HXHJR+I0IG5sUVaPwnEFwDN480yxIWUM0E",
- "939RguM7FcSQUnz6Xwlzb+p94a/X9e1X5eNaj4+j2gr3abLrAo8jLwQVSJbhCt4UeSRi9gsEmuiYasIB",
- "QkW0IDMgNAwhxGcdA1FaSPAeR94nBfJMSrraaW9MQ6q28YhLIwm9ysCbetRQ6WD6kilNxJzkCqTj3gjH",
- "rYNkzsJQgjKPmRQZSO2UEjBtOId7mmYJkrmiiSBniRZeSVlpyXiErChNNdTHvz3rHijB6ns98tXpa3K5",
- "0lrwrhm/saw+/JtXp5Pj9si1QNxWR57TPKepkZPbK448y9iPoDLBFXTsXYTm7VzIlGpv6jGuT0/WFBnX",
- "EFkVpKAUjczoFuP2xcPOfH7xRQhzmidWWW+phkjIVZtNFtbkcjyqMfz/rzoZtjSq4jwXkdpDmkHBl2Ey",
- "V1qkINtM0jXABmG7AGQT3j3KBGR9KWmWQehNtcwB2WlKZoJ/BokHTaUtojnEUb7aR0iFXHDoBxl2SQiF",
- "kICuQmUmRAKUe11bGbSNDPRFY+I3f3n9+mTQ5F9zynXT/F+PhpiDill27jxBOTykGo40S6HPceRGDnXf",
- "ZYRFru3XkQc8T73pjZclNIDQMw5eioV5DCFhC5AQenejitIqI3ZVmzCawnEuNjU0VjHJTVguTXdvPbah",
- "GIooYp2SzGKhxSeZ1G2tPqy50WJOVSYNe2sZV5/GMtDEfiOMV2LhWnl0QVlCZwm+y4CHliMlEqO5tv+k",
- "0XC/8ZFG3tA9PI5MEsIQMtMbK4uq/O624SNzWQYS7XHLOyh3V3RqakeZNKBFHlLKkjpmfhEx/9a8Hwci",
- "7cLOnEml37fA9jcRd4bk/cCc0E4aNAXViWeq1FLIOinv+OT01dc98OcwcCx6+eseGKNUK36nJ7r2+L/u",
- "8KFjMLra3RHlJtMzVgdBLpleXSPeXWjN2M+fwXghhpzHQENDpQiR7vvaKjL2d1i5+GCM82ea69jANRFL",
- "i94U01NmU9Vcx0Ky30yyil5i6sVaZ2rq+8UCp2O1pFEEcsyEL3CCX8xCm1KByMBl/TSc4ixvap7JSuSS",
- "mBcYwJmG4msqQjZfmU/oSMw4GgQi5y4zL0SGhE7sK7jXKPjkXAQdKv2O8ZCIXJNUSCB0ho/Xlm1v5OXl",
- "xqa+v96NwTmfiyJ9p4GumBfKUgNNv61PqNP9GDNFmCKUKAMFglXENYqNXINcgCQzqiAkwrrLDxnws6sL",
- "cjqeEJVBwOauThgT8i+Rk4ByMm9v5Za7vRCqyU1rH3f/13r11ZhcWJI6ZjIkTIM0hLBYwNfWlQsJI7KE",
- "LxdA1JLpIF5XOSEoFiE3UmliAi0N4v+55QWbXCxJDElGMBikJg6bebi9ZQw6BkmY/lKR2Yqk9DPjEQli",
- "yiNQawpzxplhimkFyZwIWXzD/Hx8yz9iIbakqxFZMh0TzDCQX8NAkyjjJAIOkiYjQnlI4D4TCogSKRSb",
- "5rAkc6A6l2CA9+Hs+nR8y2/5NQ7KFczzhCSMf1bTW35Ebj7GVYVKyIRiWsiVFTgaScR0nM/Q5xbCP6IZ",
- "K58LG/qqXE6JXAaW4cr+57jzKrGdKfizRMz8lCoN0lcy8FPKuC/B0lO+yIDTjI1XNE2+8kZewgJwlZHz",
- "JWcZDWIgJ+NJ02KWy+WYmq9jISPfTVX+5cXbd++v3x2djCfjWKeJic4gU/VhjuBnAXRZnW+G+OizmDbO",
- "swD3ldsLOaoaijfyFiCVtbfj8WR8/BoJuQ15U+90PBmjr86ojo1rQNdloqZQuu0qzsKQUAMFtIFaTW9W",
- "tXaCuTUOxexwVGlorA7bxzhaLpdHGIWOcpkARzMI//OtkbcSqIaK1BrZ3zrVMtkXvrCFt1HHyWTyX9/8",
- "uc6DAJRC+y8hgCh7Nfm6jaALvqAJCwnjWe7aLS50e9Obh2bkvanGvlElSt493o08lacpxTpjMy5tonxj",
- "0tI7jO55B7I/ZaFREydwz5RGl4tLzVbkImxh2w7+E95tuQHXfzSQT/pBfnFOVI6MQGjHvmqPxbDFhSZz",
- "kfOw12z+gevZJATuA7Cvn8t6urHfspzHkYkOPiZZb1brAiGCDnv6IU80w6TO1bwLmuSgTPIxA4LZBwsh",
- "tKlJINKUEgUZlVRDSGz+r1pmh4kqxrmSOMYtSVPQIJURQENnNdJlY9r1pQPBFQtBQmhSiDlLtEl44T5L",
- "TIcToTqytcOvOcjVunRQBfk1pIqe5LRWxu9V2qNynmQfgzoCBuetJvkWw3nCyi2LUvtYVBVNz4Z/xJUy",
- "GRT6+1K5m9D/0TVfNmMfV9gJ8mPySZlpxyP8+8T8fWpTXDCWOd5gFYapLTaBY9AALNzJbDUM8dou3YGE",
- "nr5+qfc/wdwLZk2jgyLZKa0bxw+mCf5ouSsa7HVknZv3Ns1pgGpLR2Ut5FZLpyv+MeOTHRsOgFiRrJe2",
- "HftmIlEltLXD1kLiRt1gEvO8urHSVIR2BtdRtyv5EXQuuemRMB4l4ObW9fQ96CvQb1ZGQhut/+Icy3mX",
- "I0uz9svJ+/eQ5qkXSvOamCqblTd3aCJPMP+ybDnvKn1cVd9TzvyT6fg7IdMdYNQ87c/NWuHhUNVyIO+p",
- "bVINYacR1dzRxg7eyqWU+5HrSBu3pX4vWENbFDj/VCvgbMqCqiEh1XRbSPHzLBE0vEjdyX8f6HDQd8zm",
- "xIOdlpXwC8LrLAxNn5Em5AfQ1AmgS720HFkZuEXVQ3oHItCgj5SWQNO6gyu3M2Ocyq4T+MdD1trVWyKD",
- "fekzodViTBHTzEagdYHSdncZXwDX7kB6S5RNaYZgc2VGIELbcndn/gxUV/C9KAk8UdhrBF3VDi0HHK3V",
- "D8r21kY1DtXkXYjI+ga7XwbdBZPt+lRVIMq7HZ1t5auEBkWL1Axt9o/qIjfD7XWRw/TfPpQXHJ6xA9ez",
- "6C5JS7HEQa26JDI8NxoWo0osOXVzp2usbptJcQ+E/AfzT6tuaRxoCkks9UJIRMsVcdZCLs6VjWgmvye3",
- "+WRyGpDjyWQyJmd8pWPGI0JnYgHmJRGScMHdbJyaJO60TNvDKJBSyLZnsAl/gdMBIQ4Rb0XSSizsVnvS",
- "KieTlyyPhqS89o5SI+ltlEMky2UQU1VsvJm4FjjoKY/20fRfydeoUvMf1PCYfDAHrq5NWFdv2WxV4y7P",
- "b7Y4vPDqUe4czOnxSyr3EA7jORzbi9Vjm8FpC6lh0EQXlatN4c1cdAjQ3/FkZaxZcDANmhhIIqII0E+a",
- "e8htlNnzQ3dB5hDBzl6Xft5Y173mLoj4pLoBYcUR1i9tN8Bd9uIPKqHn2E1/UlZC0Z0f5+6GlAOf+e8a",
- "e35gRmH9fsnUhgN8u5oiSeXuu/OREVsAt/GaFBcE+6CoCkoXJrzvD8wnXeg/ZBZ0OJ33nSRWULsnSAar",
- "tQ9FiYgYr1RJdfVf4lfniDafMcQWrwRDmEnv7MLdZXN5KXCnRgzSKK5ArkmgGw0SoJJouNc9BMubk7s0",
- "YnbFVvsq40Ygter2QZ5i5FrwhsOfjt7dZ0yCOjqbaxuO6kuYQ17GyaePb8kyBk60+AycgJ3ldSYUGy6n",
- "P468n45+xO+XLGUduA1okmDBKElsLikmiVhCWMQ959C6k5jOItdIZWPgL6Dkl8hY5wE1e7kUkbIQZby4",
- "LbJSGtLNxiHszZE+6xC5LuN0dzja2bANoyLXJMilBK4b6QJRoJRFQh/bD4VQNpZMT0pRbCo/1DMYp7Bb",
- "gVNxEf1J8PZW6gDkbE8czQXoLUVNd7AedQPnezCoebN67y7a7ydAV0TYE2SkeFw7NiYHlOzvI+7uVUo8",
- "Ey6+B23tdbZaR8YuhHTeTXuScdq2/hDjrOPqsHb5Ry9jOq7NuXBU/5nsswUSR7CnjDBtYLkocGFvMPs0",
- "Y/7i1EONuQlNwu8WINcNs1zbnyNc2d79Dr862Pw7g+rPitrnM2briNbyCrSp13fkwPGP7BdN5+0cFWpq",
- "NRcKJSi3rBN77Wcrd4//DgAA///gocX++z0AAA==",
+ "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==",
}
-// 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
@@ -283,7 +333,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) {
@@ -298,9 +348,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
}
@@ -309,12 +357,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()
@@ -340,3 +388,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/spec.yaml b/internal/test/externalref/spec.yaml
index 8f924b75c4..a0540389f9 100644
--- a/internal/test/externalref/spec.yaml
+++ b/internal/test/externalref/spec.yaml
@@ -12,4 +12,4 @@ components:
object_c:
$ref: ./object_c.json
pet:
- $ref: https://petstore3.swagger.io/api/v3/openapi.json#/components/schemas/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/operations/server.gen.go b/internal/test/filter/operations/server.gen.go
index 49fc69b5e5..157483ed85 100644
--- a/internal/test/filter/operations/server.gen.go
+++ b/internal/test/filter/operations/server.gen.go
@@ -55,20 +55,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+"/included1", wrapper.IncludedOperation1)
- router.GET(baseURL+"/included2", wrapper.IncludedOperation2)
+ 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.gen.go b/internal/test/filter/tags/server.gen.go
index 8137c0f39c..59f4dd8b03 100644
--- a/internal/test/filter/tags/server.gen.go
+++ b/internal/test/filter/tags/server.gen.go
@@ -55,20 +55,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+"/included1", wrapper.IncludedOperation1)
- router.GET(baseURL+"/included2", wrapper.IncludedOperation2)
+ 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/go.mod b/internal/test/go.mod
index ebc261e697..8d111ae94d 100644
--- a/internal/test/go.mod
+++ b/internal/test/go.mod
@@ -1,103 +1,113 @@
module github.com/oapi-codegen/oapi-codegen/v2/internal/test
-go 1.20
+go 1.25.9
replace github.com/oapi-codegen/oapi-codegen/v2 => ../../
require (
- github.com/getkin/kin-openapi v0.126.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/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.6-0.20230908161203-24ba4e8933b9
- github.com/labstack/echo/v4 v4.11.3
- github.com/oapi-codegen/nullable v1.0.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.1.0
- github.com/oapi-codegen/testutil v1.0.0
- github.com/stretchr/testify v1.9.0
- gopkg.in/yaml.v2 v2.4.0
+ 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.21.0 // indirect
- github.com/go-openapi/swag v0.23.0 // 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.4.0 // indirect
- github.com/gorilla/css v1.0.0 // indirect
- github.com/invopop/yaml v0.3.1 // 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/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/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.12.9 // indirect
- github.com/tdewolff/parse/v2 v2.6.8 // 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.23.0 // indirect
- golang.org/x/mod v0.17.0 // indirect
- golang.org/x/net v0.25.0 // indirect
- golang.org/x/sys v0.20.0 // indirect
- golang.org/x/text v0.15.0 // indirect
- golang.org/x/time v0.3.0 // indirect
- golang.org/x/tools v0.21.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 030525494c..e6cb669a55 100644
--- a/internal/test/go.sum
+++ b/internal/test/go.sum
@@ -1,91 +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.126.0 h1:c2cSgLnAsS0xYfKsgt5oBV6MYRM/giU8/RtwUY4wyfY=
-github.com/getkin/kin-openapi v0.126.0/go.mod h1:7mONz8IwmSRg6RttPu6v8U/OJ+gr+J99qSFNjPGSQqw=
-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.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
-github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
-github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
-github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
+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-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/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.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+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.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
-github.com/google/uuid v1.4.0/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/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.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
+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.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
-github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
+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=
@@ -93,82 +130,111 @@ 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.3 h1:Upyu3olaqSHkCjs1EJJwQ3WId8b8b1hxbogyommKktM=
-github.com/labstack/echo/v4 v4.11.3/go.mod h1:UcGuQ8V6ZNRmSweBIJkPvGfwCMIlFmiqrPqiEBfPYws=
-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.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/nullable v1.0.1 h1:/g+R1Kl1qVYhXlVTg+YT4UnHeYqW+cDh9rfzr+pAV/0=
-github.com/oapi-codegen/nullable v1.0.1/go.mod h1:KUZ3vUzkmEKY90ksAmit2+5juDIhIZhfDl+0PwOQlFY=
-github.com/oapi-codegen/runtime v1.1.0 h1:rJpoNUawn5XTvekgfkvSZr0RqEnoYpFkyvrzfWeFKWM=
-github.com/oapi-codegen/runtime v1.1.0/go.mod h1:BeSfBkWWWnAnGdyS+S/GnlbmHKzf8/hwkvelJZDeKA8=
-github.com/oapi-codegen/testutil v1.0.0 h1:1GI2IiMMLh2vDHr1OkNacaYU/VaApKdcmfgl4aeXAa8=
-github.com/oapi-codegen/testutil v1.0.0/go.mod h1:ttCaYbHvJtHuiyeBF0tPIX+4uhEPTeizXKx28okijLw=
-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.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.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
+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=
@@ -177,111 +243,159 @@ 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/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-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/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.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
-golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+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.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+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.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
-golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+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.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+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.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
-golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+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.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
-golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-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.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
-golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
+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=
+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-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.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.gen.go b/internal/test/issues/issue-1039/client.gen.go
index 3114f29862..9e9696094e 100644
--- a/internal/test/issues/issue-1039/client.gen.go
+++ b/internal/test/issues/issue-1039/client.gen.go
@@ -147,7 +147,7 @@ func NewExamplePatchRequestWithBody(server string, contentType string, body io.R
return nil, err
}
- req, err := http.NewRequest("PATCH", queryURL.String(), body)
+ req, err := http.NewRequest(http.MethodPatch, queryURL.String(), body)
if err != nil {
return nil, err
}
@@ -211,6 +211,11 @@ type ExamplePatchResponse struct {
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 {
@@ -227,6 +232,14 @@ func (r ExamplePatchResponse) StatusCode() int {
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...)
diff --git a/internal/test/issues/issue-1039/defaultbehaviour/types.gen.go b/internal/test/issues/issue-1039/defaultbehaviour/types.gen.go
index b148f37830..5ed98d88f1 100644
--- a/internal/test/issues/issue-1039/defaultbehaviour/types.gen.go
+++ b/internal/test/issues/issue-1039/defaultbehaviour/types.gen.go
@@ -6,7 +6,7 @@ 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"`
+ ComplexOptionalNullable *ComplexOptionalNullable `json:"complex_optional_nullable,omitempty"`
// ComplexRequiredNullable Complex required and nullable
ComplexRequiredNullable *ComplexRequiredNullable `json:"complex_required_nullable"`
@@ -15,7 +15,7 @@ type PatchRequest struct {
SimpleOptionalNonNullable *SimpleOptionalNonNullable `json:"simple_optional_non_nullable,omitempty"`
// SimpleOptionalNullable Simple optional and nullable
- SimpleOptionalNullable *SimpleOptionalNullable `json:"simple_optional_nullable"`
+ SimpleOptionalNullable *SimpleOptionalNullable `json:"simple_optional_nullable,omitempty"`
// SimpleRequiredNullable Simple required and nullable
SimpleRequiredNullable *SimpleRequiredNullable `json:"simple_required_nullable"`
@@ -24,7 +24,7 @@ type PatchRequest struct {
// ComplexOptionalNullable Complex, optional and nullable
type ComplexOptionalNullable struct {
// AliasName Optional and nullable
- AliasName *string `json:"alias_name"`
+ AliasName *string `json:"alias_name,omitempty"`
// Name Optional and non nullable
Name *string `json:"name,omitempty"`
diff --git a/internal/test/issues/issue-1087/api.gen.go b/internal/test/issues/issue-1087/api.gen.go
index 3c408cc8f9..527ceb2e45 100644
--- a/internal/test/issues/issue-1087/api.gen.go
+++ b/internal/test/issues/issue-1087/api.gen.go
@@ -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...)
diff --git a/internal/test/issues/issue-1087/deps/deps.gen.go b/internal/test/issues/issue-1087/deps/deps.gen.go
index 8066ab2b57..3661be9d81 100644
--- a/internal/test/issues/issue-1087/deps/deps.gen.go
+++ b/internal/test/issues/issue-1087/deps/deps.gen.go
@@ -5,7 +5,7 @@ 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-1093/api/child/child.gen.go b/internal/test/issues/issue-1093/api/child/child.gen.go
index 21e57fe8f7..1275e1b202 100644
--- a/internal/test/issues/issue-1093/api/child/child.gen.go
+++ b/internal/test/issues/issue-1093/api/child/child.gen.go
@@ -5,7 +5,7 @@ package api
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"
externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1093/api/parent"
- strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin"
)
// 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/2xRwW7bMAz9FYHb0Yi97aYfGHYLht7SoFBlOlZgSyxJFwgC/3tBuUEaoCeR9uPj43tX",
- "iGWmkjGrgL+CxBHnUEsKjFlf9qi140LImrD+y2FGe/VCCB5EOeUTrA1oOH3zfW2A8W1JjD34wzZ9bG6o",
- "8nrGqLAaLOWhGEGPEjmRppLBw9OYxMUxTb0TwujSTIVV3Fx6nMQNXGanI7pNcsVAA5p0Mv46CA28I8vG",
- "92vXmdhCmAMl8PBn1+06aICCjvXAlnAz5LSd/6jnP+rCWRyh3pfLRRStDFr7RZDdGMSFGFHEaXnOUJdy",
- "MJ5/PXj4i7q3TWaQUMmy+fu76+yJJSvmKiAQTSnWwfYspuIWllU/GQfw8KO9p9l+Rtl+ybFa/HhKcLJU",
- "fcMyuZsGAxpUkM008IcrLDyBh3Yzcz2uHwEAAP//SKTQrDoCAAA=",
+ "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 916772b07d..d1696c0068 100644
--- a/internal/test/issues/issue-1093/api/parent/parent.gen.go
+++ b/internal/test/issues/issue-1093/api/parent/parent.gen.go
@@ -5,7 +5,7 @@ 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/doc.go b/internal/test/issues/issue-1093/doc.go
index 7916b330b7..6996cdd2d8 100644
--- a/internal/test/issues/issue-1093/doc.go
+++ b/internal/test/issues/issue-1093/doc.go
@@ -1,5 +1,5 @@
// 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/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen --config parent.cfg.yaml parent.api.yaml
diff --git a/internal/test/issues/issue-1180/issue.gen.go b/internal/test/issues/issue-1180/issue.gen.go
index cc675b96da..11fe0948f7 100644
--- a/internal/test/issues/issue-1180/issue.gen.go
+++ b/internal/test/issues/issue-1180/issue.gen.go
@@ -5,7 +5,7 @@ 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.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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/pkg1.gen.go b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go
index 7be0da44a6..e02ca358c2 100644
--- a/internal/test/issues/issue-1182/pkg1/pkg1.gen.go
+++ b/internal/test/issues/issue-1182/pkg1/pkg1.gen.go
@@ -5,7 +5,7 @@ package pkg1
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"fmt"
@@ -18,7 +18,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/labstack/echo/v4"
externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1182/pkg2"
- strictecho "github.com/oapi-codegen/runtime/strictmiddleware/echo"
)
// 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/3yQMU/DMBCF/4r1YIyStGzemFAHllKJASFknJfGtLEt+1qEqvx35LQUsTCdz3fv7r53",
- "gg1jDJ5eMvQJiTkGnzkncbddvq0vP89OhjV7JnrLUu2YbXJRXPDQuFc/UhXeP2hFfQ7ODspllYoqsVMS",
- "VJ/CqIwPMjCpaOzObIlpmio434cydu8sfZ43eDMSGo+rDaYK4mRf0g2zqCemIxMqHJny+YJF3dZtaQyR",
- "3kQHjbu6rReoEI0MM1EjzFIeW84hRCZTCFbdZfIDBdVfG5ZtW8JtYg+Nm+bXseba1/zjVaHLh3E06Qu6",
- "bFbliqtfZ/w8A2XolxMOaQ+NQSTqprnQFEndkXE0sTYO0+v0HQAA//9bF49xvAEAAA==",
+ "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/pkg2.gen.go b/internal/test/issues/issue-1182/pkg2/pkg2.gen.go
index 51eece40aa..21ba74e586 100644
--- a/internal/test/issues/issue-1182/pkg2/pkg2.gen.go
+++ b/internal/test/issues/issue-1182/pkg2/pkg2.gen.go
@@ -5,7 +5,7 @@ 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/issue1189.gen.go b/internal/test/issues/issue-1189/issue1189.gen.go
index c1a869ad98..0296cf0d90 100644
--- a/internal/test/issues/issue-1189/issue1189.gen.go
+++ b/internal/test/issues/issue-1189/issue1189.gen.go
@@ -5,7 +5,7 @@ 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"`
@@ -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/issue-multi-json.gen.go b/internal/test/issues/issue-1208-1209/issue-multi-json.gen.go
index 780d45e6a7..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
@@ -5,7 +5,7 @@ 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-1212/pkg1/pkg1.gen.go b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go
index f817ec8376..23d6c7db96 100644
--- a/internal/test/issues/issue-1212/pkg1/pkg1.gen.go
+++ b/internal/test/issues/issue-1212/pkg1/pkg1.gen.go
@@ -5,7 +5,7 @@ package pkg1
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"fmt"
@@ -20,7 +20,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/gin-gonic/gin"
externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1212/pkg2"
- strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin"
)
// RequestEditorFn is the function signature for the RequestEditor callback function
@@ -131,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
}
@@ -191,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 {
@@ -207,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...)
@@ -302,6 +314,7 @@ type Test200MultipartResponse externalRef0.TestMultipartResponse
func (response Test200MultipartResponse) VisitTestResponse(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)
@@ -316,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
@@ -342,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/4yRMU/DMBCF/8uDMapD2DwyILGzIze5pAbnzrKvA6r635FtaFSpSM2SO9vfe6d3J4yy",
- "RmFizbAnJMpROFNt4tcyfChlLc0orMS1XI9BfXRJTaLglKZymMcDra5iSSIl9U3kMwu/uFTKx0QzLB7M",
- "5mkalk312ruEc1eRV5G7kFkE5/Z1vzNss++b7/VAs6cwDaXS70iwyJo8L6gKF83b2NNNrICeZ4HlYwgd",
- "JBK76GHxvOt3PTpEp4eqYv7iXKj+ioNTL/w2weK9XHbXSxj6/r8gLu/MtqkWxU8AAAD//+WESHLXAQAA",
+ "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
@@ -384,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) {
@@ -399,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
}
@@ -410,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()
@@ -441,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/pkg2.gen.go b/internal/test/issues/issue-1212/pkg2/pkg2.gen.go
index 5a994ed06f..778ed9cbfd 100644
--- a/internal/test/issues/issue-1212/pkg2/pkg2.gen.go
+++ b/internal/test/issues/issue-1212/pkg2/pkg2.gen.go
@@ -5,7 +5,7 @@ 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-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/issue1298.gen.go b/internal/test/issues/issue-1298/issue1298.gen.go
index 94734a5772..a3229d9c86 100644
--- a/internal/test/issues/issue-1298/issue1298.gen.go
+++ b/internal/test/issues/issue-1298/issue1298.gen.go
@@ -7,6 +7,7 @@ import (
"bytes"
"context"
"encoding/json"
+ "errors"
"fmt"
"io"
"net/http"
@@ -14,7 +15,6 @@ import (
"strings"
"github.com/gin-gonic/gin"
- strictgin "github.com/oapi-codegen/runtime/strictmiddleware/gin"
)
// Test defines model for Test.
@@ -159,7 +159,7 @@ func NewTestRequestWithBody(server string, contentType string, body io.Reader) (
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
}
@@ -223,6 +223,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 {
@@ -239,6 +244,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 ""
+}
+
// 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...)
@@ -354,16 +367,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
@@ -372,11 +430,13 @@ func (sh *strictHandler) Test(ctx *gin.Context) {
var body TestApplicationTestPlusJSONRequestBody
if err := ctx.ShouldBindJSON(&body); err != nil {
- ctx.Status(http.StatusBadRequest)
- ctx.Error(err)
- return
+ 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.Test(ctx, request.(TestRequestObject))
@@ -388,13 +448,12 @@ 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))
}
}
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/bionicle.gen.go b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go
index 9f6ffc8809..f1f561ce10 100644
--- a/internal/test/issues/issue-1378/bionicle/bionicle.gen.go
+++ b/internal/test/issues/issue-1378/bionicle/bionicle.gen.go
@@ -5,7 +5,7 @@ package bionicle
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -19,7 +19,6 @@ import (
"github.com/gorilla/mux"
externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-1378/common"
"github.com/oapi-codegen/runtime"
- strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"
)
// Bionicle defines model for Bionicle.
@@ -30,6 +29,47 @@ type Bionicle struct {
// 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 {
@@ -50,11 +90,12 @@ type MiddlewareFunc func(http.Handler) http.Handler
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{Explode: false, Required: true})
+ 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
@@ -184,7 +225,7 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
- r.HandleFunc(options.BaseURL+"/bionicle/{name}", wrapper.GetBionicleName).Methods("GET")
+ r.HandleFunc(options.BaseURL+"/bionicle/{name}", wrapper.GetBionicleName).Methods(http.MethodGet)
return r
}
@@ -200,21 +241,29 @@ type GetBionicleNameResponseObject interface {
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)
-
- return json.NewEncoder(w).Encode(response)
+ _, err := buf.WriteTo(w)
+ return err
}
-type GetBionicleName400JSONResponse struct {
- union json.RawMessage
-}
+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)
-
- return json.NewEncoder(w).Encode(response.union)
+ _, err := buf.WriteTo(w)
+ return err
}
// StrictServerInterface represents all server handlers.
@@ -224,8 +273,8 @@ type StrictServerInterface interface {
GetBionicleName(ctx context.Context, request GetBionicleNameRequestObject) (GetBionicleNameResponseObject, 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)
@@ -279,32 +328,34 @@ func (sh *strictHandler) GetBionicleName(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/5SRMU8zMQyG/0rl7xujyxWYbuyCWGBhqzqkqa+XqpcEx0VCp/x35FyPXikMZLEcO3n8",
- "+h3Ahj4Gj54TNANEQ6ZHRirZ1gXv7BGfTY+S7zBZcpFd8NCA3C5Cu+AOF7YzZCwjgQInxWi4AwW+vByD",
- "AsK3kyPcQcN0QgXJdtgb+Zk/ovQlJuf3kHOeimWO1XmOMiGFiMQOS8WfJ/v+fs5aj10bNXWF7QEtjxTn",
- "23Ar7RUTgwJ2LNApfUdKY31Z1VUNWUGI6E100MB9VVdLUEV4GU1P29OD8LPc7ZEliAIjqKcdNPCIvJov",
- "Wl25sB7gP2ELDfzTF6/0pUVfuZQ3Ij3F4NO4obu6lmCDZ/SFbmI8Olv4+pBEzzBz4ifY2Qr95UMuu3v4",
- "49fB40v7q6JbyCZP5zMAAP//9Jg3p6cCAAA=",
+ "lJExTzMxDIb/SuXvG6PLFZhu7IJYYGGrOqSpr5eqlwTHRUKn/HfkXI9eKQxksRw7efz6HcCGPgaPnhM0",
+ "A0RDpkdGKtnWBe/sEZ9Nj5LvMFlykV3w0IDcLkK74A4XtjNkLCOBAifFaLgDBb68HIMCwreTI9xBw3RC",
+ "Bcl22Bv5mT+i9CUm5/eQc56KZY7VeY4yIYWIxA5LxZ8n+/5+zlqPXRs1dYXtAS2PFOfbcCvtFRODAnYs",
+ "0Cl9R0pjfVnVVQ1ZQYjoTXTQwH1VV0tQRXgZTU/b04Pws9ztkSWIAiOopx008Ii8mi9aXbmwHuA/YQsN",
+ "/NMXr/SlRV+5lDciPcXg07ihu7qWYINn9IVuYjw6W/j6kETPMHPiJ9jZCv3lQy67e/jj18HjS/urolvI",
+ "Jk/nMwAA//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
@@ -312,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) {
@@ -327,9 +378,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, "common.yaml")) {
+ 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
}
@@ -338,12 +387,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()
@@ -369,3 +418,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-1378/common/common.gen.go b/internal/test/issues/issue-1378/common/common.gen.go
index d1747783e0..91da73aeb9 100644
--- a/internal/test/issues/issue-1378/common/common.gen.go
+++ b/internal/test/issues/issue-1378/common/common.gen.go
@@ -5,7 +5,8 @@ package common
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
+ "context"
"encoding/base64"
"fmt"
"net/http"
@@ -15,7 +16,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/gorilla/mux"
- strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"
)
// ErrTracingIdNotSent defines model for ErrTracingIdNotSent.
@@ -151,8 +151,8 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H
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)
@@ -180,30 +180,31 @@ type strictHandler struct {
options StrictHTTPServerOptions
}
-// 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/0TMP08DMQwF8O/y5uh0FVt2BhYWuiGGkJjW6Gobx0VCVb47Sk+IyX/eT++GqhdTIYmO",
- "fEOvZ7qU+/rofvRSWU5P7VnjhSTm21yNPJjuqGqjOePHCBk9nOWEMRKcvq7s1JBfd/WW/pS+f1INjMlY",
- "PnQWNOrV2YJVkHGkHkgIjo3+z2/yvueHZV1WjAQ1kmKMjIdlXQ5IsBLnjizXbRu/AQAA//9/cprb3gAA",
- "AA==",
+ "RMw/TwMxDAXw7/Lm6HQVW3YGFha6IYaQmNboahvHRUJVvjtKT4jJf95P74aqF1MhiY58Q69nupT7+uh+",
+ "9FJZTk/tWeOFJObbXI08mO6oaqM548cIGT2c5YQxEpy+ruzUkF939Zb+lL5/Ug2MyVg+dBY06tXZglWQ",
+ "caQeSAiOjf7Pb/K+54dlXVaMBDWSYoyMh2VdDkiwEueOLNdtG78BAAD//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
@@ -211,7 +212,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) {
@@ -229,12 +230,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()
@@ -260,3 +261,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-1378/fooservice/fooservice.gen.go b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go
index c0542b6a55..8b38f2010a 100644
--- a/internal/test/issues/issue-1378/fooservice/fooservice.gen.go
+++ b/internal/test/issues/issue-1378/fooservice/fooservice.gen.go
@@ -5,7 +5,7 @@ package fooservice
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -20,7 +20,6 @@ import (
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"
- strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"
)
// ServerInterface represents all server handlers.
@@ -43,11 +42,12 @@ type MiddlewareFunc func(http.Handler) http.Handler
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{Explode: false, Required: true})
+ 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
@@ -177,7 +177,7 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
- r.HandleFunc(options.BaseURL+"/bionicle/{name}", wrapper.GetBionicleName).Methods("GET")
+ r.HandleFunc(options.BaseURL+"/bionicle/{name}", wrapper.GetBionicleName).Methods(http.MethodGet)
return r
}
@@ -193,21 +193,37 @@ type GetBionicleNameResponseObject interface {
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
- return json.NewEncoder(w).Encode(response)
+func (t GetBionicleName400JSONResponse) MarshalJSON() ([]byte, error) {
+ return externalRef0.GetBionicleName400JSONResponseBody(t).MarshalJSON()
}
-type GetBionicleName400JSONResponse struct {
- union json.RawMessage
+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)
-
- return json.NewEncoder(w).Encode(response.union)
+ _, err := buf.WriteTo(w)
+ return err
}
// StrictServerInterface represents all server handlers.
@@ -217,8 +233,8 @@ type StrictServerInterface interface {
GetBionicleName(ctx context.Context, request GetBionicleNameRequestObject) (GetBionicleNameResponseObject, 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)
@@ -272,32 +288,34 @@ func (sh *strictHandler) GetBionicleName(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/5RRQU/zMAz9K5O/7xg1HXDqcRfEBS7cpgllmbtmWpPgeEioyn9HTldtYwOJXpzEr37P",
- "7w1gQx+DR88JmgGiIdMjI5Xb2gXv7B7fpsOz6VEaG0yWXGQXPDQgr7PQzrjDme0MGctIoMBJMxruQIEv",
- "f45FAeH7wRFuoGE6oIJkO+yNTObPKLjE5PwWcs5T81LQ4ngomilEJHZYIP4o8fugc9LliFqpCRXWO7Q8",
- "0jnfhusdXzExKGDHQjpdP5DS2J9XdVVDVhAiehMdNHBf1dUcVHGgSNOTfD0If5a3LbIU2cAI1dMGGnhE",
- "Xpw7ri5yWQ7wn7CFBv7pU3r6BNG3c8sr8SDF4NNo1V1dS7HBM/oiw8S4d7YI0bskiw1n2dxiPYajr5PJ",
- "xc2HP3IEjy/tjzv+wrbK0/cVAAD//37MjEPUAgAA",
+ "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//",
}
-// 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
@@ -305,7 +323,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) {
@@ -320,15 +338,13 @@ 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, "bionicle.yaml")) {
+ 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(pathPrefix, "common.yaml")) {
+ 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
}
@@ -337,12 +353,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()
@@ -368,3 +384,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-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-1397/issue1397.gen.go b/internal/test/issues/issue-1397/issue1397.gen.go
index 2463641eb1..4ff816ae40 100644
--- a/internal/test/issues/issue-1397/issue1397.gen.go
+++ b/internal/test/issues/issue-1397/issue1397.gen.go
@@ -5,7 +5,7 @@ package issue1397
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -26,6 +26,18 @@ const (
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
@@ -189,7 +201,7 @@ func NewTestRequestWithBody(server string, contentType string, body io.Reader) (
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
}
@@ -253,6 +265,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 {
@@ -269,6 +286,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 ""
+}
+
// 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...)
@@ -338,50 +363,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+"/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/8xTO2/bMBD+K8K1W2XLj3bh1g4FPLRD4C3IQEsnmQbFo8lTYsHQfw+OUmzkBSRbJh2O",
- "9/F76HiGklpPDh1HUGeI5R5bncotRpavD+QxsMHUrQ3aailVhbEMxrMhBwp+ZzoE3WdUZ+i6NrvXtsMI",
- "ORjGNiGlDeoWKEGWkE/VCu5y4N4jKIgcjGtgyKHVp82I/HU5TQxymESs3hLhMDJWGe0OWHL2YHifaWup",
- "1NJ1ukXI3zU0seyILGr3nOeFviGHgMfOBKzE0nTHBXA1NAqBHE6zhmbSnCUVCv71EvANHjuM/D/J/ivo",
- "C+/6Y/6o4y9hUQCfMw2DYIyrCZTrrJWFQKe9AQXr+WIubF7zPnkoeFrHBtNH/GmJZVOBGnd1FIyR/1DV",
- "y0xJjtGlce29NWUCpJt+HKIk+rTwUn0PWIOCb8X1RRTTcyi2k9wUSvTk4pjsavHz9V9qiKo0PAyPAQAA",
- "///99gukXwMAAA==",
+ "zFM7b9swEP4rwrVbZcuPduHWDgU8tEPgLchASyeZBsWjyVNiwdB/D45SbOQFJFsmHY738XvoeIaSWk8O",
+ "HUdQZ4jlHludyi1Glq8P5DGwwdStDdpqKVWFsQzGsyEHCn5nOgTdZ1Rn6Lo2u9e2wwg5GMY2IaUN6hYo",
+ "QZaQT9UK7nLg3iMoiByMa2DIodWnzYj8dTlNDHKYRKzeEuEwMlYZ7Q5YcvZgeJ9pa6nU0nW6RcjfNTSx",
+ "7Igsavec54W+IYeAx84ErMTSdMcFcDU0CoEcTrOGZtKcJRUK/vUS8A0eO4z8P8n+K+gL7/pj/qjjL2FR",
+ "AJ8zDYNgjKsJlOuslYVAp70BBev5Yi5sXvM+eSh4WscG00f8aYllU4Ead3UUjJH/UNXLTEmO0aVx7b01",
+ "ZQKkm34coiT6tPBSfQ9Yg4JvxfVFFNNzKLaT3BRK9OTimOxq8fP1X2qIqjQ8DI8BAAD//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
@@ -389,7 +434,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) {
@@ -407,12 +452,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()
@@ -438,3 +483,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-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/issue.gen.go b/internal/test/issues/issue-312/issue.gen.go
index f0285c071f..25763f9374 100644
--- a/internal/test/issues/issue-312/issue.gen.go
+++ b/internal/test/issues/issue-312/issue.gen.go
@@ -5,7 +5,7 @@ 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.BindStyledParameterWithOptions("simple", "petId", ctx.Param("petId"), &petId, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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/issue.gen.go b/internal/test/issues/issue-52/issue.gen.go
index f024999d6a..5e0a502a4c 100644
--- a/internal/test/issues/issue-52/issue.gen.go
+++ b/internal/test/issues/issue-52/issue.gen.go
@@ -5,7 +5,7 @@ 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-832/issue.gen.go b/internal/test/issues/issue-832/issue.gen.go
index 0aa74f232e..8b0d1e2123 100644
--- a/internal/test/issues/issue-832/issue.gen.go
+++ b/internal/test/issues/issue-832/issue.gen.go
@@ -5,7 +5,7 @@ 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-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/issue.gen.go b/internal/test/issues/issue-grab_import_names/issue.gen.go
index 52564c0dd9..08e66b4fcb 100644
--- a/internal/test/issues/issue-grab_import_names/issue.gen.go
+++ b/internal/test/issues/issue-grab_import_names/issue.gen.go
@@ -5,7 +5,7 @@ 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.BindStyledParameterWithOptions("simple", "Foo", valueList[0], &Foo, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false})
+ 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.BindStyledParameterWithOptions("simple", "Bar", valueList[0], &Bar, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false})
+ 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-head-digit-of-httpheader/issue.gen.go b/internal/test/issues/issue-head-digit-of-httpheader/issue.gen.go
index 6eadcef68e..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
@@ -4,7 +4,7 @@
package headdigitofhttpheader
type N200ResponseHeaders struct {
- N000Foo string
+ N000Foo *string
}
type N200Response struct {
Headers N200ResponseHeaders
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 a24b19da0e..09859b13cd 100644
--- a/internal/test/issues/issue-illegal_enum_names/issue.gen.go
+++ b/internal/test/issues/issue-illegal_enum_names/issue.gen.go
@@ -5,7 +5,7 @@ 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 3a8b475103..22f3cb3d26 100644
--- a/internal/test/issues/issue-illegal_enum_names/issue_test.go
+++ b/internal/test/issues/issue-illegal_enum_names/issue_test.go
@@ -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/gen/spec_base/issue.gen.go b/internal/test/issues/issue-removed-external-ref/gen/spec_base/issue.gen.go
index 1a1c761002..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
@@ -4,6 +4,7 @@
package spec_base
import (
+ "bytes"
"context"
"encoding/json"
"fmt"
@@ -11,7 +12,6 @@ import (
"github.com/go-chi/chi/v5"
externalRef0 "github.com/oapi-codegen/oapi-codegen/v2/internal/test/issues/issue-removed-external-ref/gen/spec_ext"
- strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"
)
// DirectBar defines model for DirectBar.
@@ -215,13 +215,20 @@ type PostInvalidExtRefTroubleResponseObject interface {
VisitPostInvalidExtRefTroubleResponse(w http.ResponseWriter) error
}
-type PostInvalidExtRefTrouble300JSONResponse struct{ externalRef0.Pascal }
+type PostInvalidExtRefTrouble300JSONResponse struct {
+ externalRef0.PascalJSONResponse
+}
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 {
@@ -239,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.
@@ -255,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 881f8be12b..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
@@ -4,11 +4,11 @@
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/main.gen.go b/internal/test/issues/issue1469/main.gen.go
index 11f87b0c4f..4a1161368c 100644
--- a/internal/test/issues/issue1469/main.gen.go
+++ b/internal/test/issues/issue1469/main.gen.go
@@ -16,21 +16,36 @@ 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
// Test operation middleware
func (siw *ServerInterfaceWrapper) Test(c *fiber.Ctx) error {
- return siw.Handler.Test(c)
+ 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
+ BaseURL string
+ Middlewares []MiddlewareFunc
+ HandlerMiddlewares []HandlerMiddlewareFunc
}
// RegisterHandlers creates http.Handler with routing matching OpenAPI spec.
@@ -41,7 +56,8 @@ 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 {
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/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/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/name_normalizer.gen.go b/internal/test/outputoptions/name-normalizer/to-camel-case-with-digits/name_normalizer.gen.go
index d2a11387d0..071a7a7386 100644
--- 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
@@ -5,7 +5,7 @@ package tocamelcasewithdigits
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -212,7 +212,7 @@ func NewGetHttpPetRequest(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
}
@@ -232,7 +232,7 @@ func NewGetHttpPetRequest(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
}
@@ -293,6 +293,16 @@ type GetHttpPetResponse struct {
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 {
@@ -309,6 +319,14 @@ func (r GetHttpPetResponse) StatusCode() int {
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...)
@@ -364,11 +382,12 @@ type MiddlewareFunc func(http.Handler) http.Handler
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{Explode: false, Required: true})
+ 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
@@ -498,40 +517,41 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
- r.HandleFunc(options.BaseURL+"/api/pets/{petId}", wrapper.GetHttpPet).Methods("GET")
+ r.HandleFunc(options.BaseURL+"/api/pets/{petId}", wrapper.GetHttpPet).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/4RTzY7TMBB+FWvgaJLSveW+gr2wHLitKtXEk2RWiW3sScVS5d3R2G0pbVe9tI5n/Pn7",
- "8eyh9VPwDh0naPaQ2gEnk5ePMfooixB9wMiEebv1FuXfYmojBSbvoCnNKtc0dD5OhqEBcvywBg38FrB8",
- "Yo8RFg0TpmT6d4GO5dPRxJFcD8uiIeKvmSJaaF7gcOGxfbNoeHb43K15INena/hvnqlFxYNhxQOqbWnc",
- "KkrKeVatCcRmpIQWNHjBgubl0gOy8nup6oIbWdic+Pufr9gyLPo21MmxeSZ7V/VNZNH+Hfk6MGemGz7/",
- "GFBJRfkuGxGQq+uLdSF083RAVlKt7vI9iMpErolLN7nOZ0uJR6k9/jZTGDE/KNX5WLISgE9OrBrpD8at",
- "8jOHmZUvtDTsMKZC8HO1qlbC3wd0JhA08JC3NATDQzamNoHqgJzqfUB+sots9sVCMdAI6pOFBr4gf2UO",
- "Yq+cj2ZCxpjyyyC5TjCPChvIaHDuAccZ9WG4zp7Oya+NNKfgXSqZrVerMmuO0WVCJoSR2kypfk2icX+G",
- "9zFiBw18qP9Nc30Y5VpYZ5P/j3BnRrISYo4rzdNk4lvRmqPtaYdOkUXH1BHGSkCWvwEAAP//D5F1qDAE",
- "AAA=",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "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) {
- 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
@@ -539,7 +559,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) {
@@ -557,12 +577,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()
@@ -588,3 +608,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/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
index 3b2a1fa751..5ed20a5756 100644
--- 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
@@ -5,7 +5,7 @@ package tocamelcasewithinitialisms
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -212,7 +212,7 @@ func NewGetHTTPPetRequest(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
}
@@ -232,7 +232,7 @@ func NewGetHTTPPetRequest(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
}
@@ -293,6 +293,16 @@ type GetHTTPPetResponse struct {
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 {
@@ -309,6 +319,14 @@ func (r GetHTTPPetResponse) StatusCode() int {
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...)
@@ -364,11 +382,12 @@ type MiddlewareFunc func(http.Handler) http.Handler
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{Explode: false, Required: true})
+ 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
@@ -498,40 +517,41 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
- r.HandleFunc(options.BaseURL+"/api/pets/{petId}", wrapper.GetHTTPPet).Methods("GET")
+ r.HandleFunc(options.BaseURL+"/api/pets/{petId}", wrapper.GetHTTPPet).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/4RTTW/bPAz+KwLf96jZWXrzvdh6WXvIrQgQzaJtFrakSXSwLvB/HyglWZZk6CWRRerR",
- "8yEeoPVT8A4dJ2gOkNoBJ5OXjzH6KIsQfcDIhHm79Rbl32JqIwUm76ApzSrXNHQ+ToahAXL8sAYN/B6w",
- "fGKPERYNE6Zk+n8Cncrno4kjuR6WRUPEHzNFtNC8wvHCU/t20fDs8Llb80CuT7fw3zxTi4oHw4oHVLvS",
- "uFOUlPOsWhOIzUgJLWjwggXN67UHZOX3WtUVN7KwPfP339+wZVj0faizY/NM9kPVd5FF+wvybWDOTHd8",
- "3gyopKJ8l40IyNXtxboQuns6ICupVh/yPYrKRG6JSze5zmdLiUepPf40UxgxPyjV+ViyEoBPTqwa6RfG",
- "nfIzh5mVL7Q07DGmQvBztapWwt8HdCYQNPCQtzQEw0M2pjaB6oCc6kNAfrKLbPbFQjHQCOqThQa+IH/d",
- "bF7EXjkfzYSMMeWXQXKdYJ4UNpDR4NIDjjPq43BdPJ2zX1tpTsG7VDJbr1Zl1hyjy4RMCCO1mVL9lkTj",
- "4QLv/4gdNPBf/Wea6+Mo18I6m/x3hHszkpUQc1xpniYT34vWHG1Pe3SKLDqmjjBWArL8DgAA//+VcR3v",
- "MAQAAA==",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "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) {
- 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
@@ -539,7 +559,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) {
@@ -557,12 +577,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()
@@ -588,3 +608,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/outputoptions/name-normalizer/to-camel-case/name_normalizer.gen.go b/internal/test/outputoptions/name-normalizer/to-camel-case/name_normalizer.gen.go
index 3e4ff389e2..08c90baded 100644
--- 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
@@ -5,7 +5,7 @@ package tocamelcase
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -212,7 +212,7 @@ func NewGetHttpPetRequest(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
}
@@ -232,7 +232,7 @@ func NewGetHttpPetRequest(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
}
@@ -293,6 +293,16 @@ type GetHttpPetResponse struct {
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 {
@@ -309,6 +319,14 @@ func (r GetHttpPetResponse) StatusCode() int {
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...)
@@ -364,11 +382,12 @@ type MiddlewareFunc func(http.Handler) http.Handler
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{Explode: false, Required: true})
+ 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
@@ -498,40 +517,41 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
- r.HandleFunc(options.BaseURL+"/api/pets/{petId}", wrapper.GetHttpPet).Methods("GET")
+ r.HandleFunc(options.BaseURL+"/api/pets/{petId}", wrapper.GetHttpPet).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/4RTzY7TMBB+FWvgaJLSveW+gr2wHLitKtXEk2RWiW3sScVS5d3R2G0pbVe9tI5n/Pn7",
- "8eyh9VPwDh0naPaQ2gEnk5ePMfooixB9wMiEebv1FuXfYmojBSbvoCnNKtc0dD5OhqEBcvywBg38FrB8",
- "Yo8RFg0TpmT6d4GO5dPRxJFcD8uiIeKvmSJaaF7gcOGxfbNoeHb43K15INena/hvnqlFxYNhxQOqbWnc",
- "KkrKeVatCcRmpIQWNHjBgubl0gOy8nup6oIbWdic+Pufr9gyLPo21MmxeSZ7V/VNZNH+Hfk6MGemGz7/",
- "GFBJRfkuGxGQq+uLdSF083RAVlKt7vI9iMpErolLN7nOZ0uJR6k9/jZTGDE/KNX5WLISgE9OrBrpD8at",
- "8jOHmZUvtDTsMKZC8HO1qlbC3wd0JhA08JC3NATDQzamNoHqgJzqfUB+sots9sVCMdAI6pOFBr4gf2UO",
- "Yq+cj2ZCxpjyyyC5TjCPChvIaHDuAccZ9WG4zp7Oya+NNKfgXSqZrVerMmuO0WVCJoSR2kypfk2icX+G",
- "9zFiBw18qP9Nc30Y5VpYZ5P/j3BnRrISYo4rzdNk4lvRmqPtaYdOkUXH1BHGSkCWvwEAAP//D5F1qDAE",
- "AAA=",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "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) {
- 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
@@ -539,7 +559,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) {
@@ -557,12 +577,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()
@@ -588,3 +608,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/outputoptions/name-normalizer/unset/name_normalizer.gen.go b/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go
index a2ef05ae8b..cbdde2a4ef 100644
--- a/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go
+++ b/internal/test/outputoptions/name-normalizer/unset/name_normalizer.gen.go
@@ -5,7 +5,7 @@ package unset
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
@@ -212,7 +212,7 @@ func NewGetHttpPetRequest(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
}
@@ -232,7 +232,7 @@ func NewGetHttpPetRequest(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
}
@@ -293,6 +293,16 @@ type GetHttpPetResponse struct {
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 {
@@ -309,6 +319,14 @@ func (r GetHttpPetResponse) StatusCode() int {
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...)
@@ -364,11 +382,12 @@ type MiddlewareFunc func(http.Handler) http.Handler
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{Explode: false, Required: true})
+ 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
@@ -498,40 +517,41 @@ func HandlerWithOptions(si ServerInterface, options GorillaServerOptions) http.H
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
- r.HandleFunc(options.BaseURL+"/api/pets/{petId}", wrapper.GetHttpPet).Methods("GET")
+ r.HandleFunc(options.BaseURL+"/api/pets/{petId}", wrapper.GetHttpPet).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/4RTzY7TMBB+FWvgaJLSveW+gr2wHLitKtXEk2RWiW3sScVS5d3R2G0pbVe9tI5n/Pn7",
- "8eyh9VPwDh0naPaQ2gEnk5ePMfooixB9wMiEebv1FuXfYmojBSbvoCnNKtc0dD5OhqEBcvywBg38FrB8",
- "Yo8RFg0TpmT6d4GO5dPRxJFcD8uiIeKvmSJaaF7gcOGxfbNoeHb43K15INena/hvnqlFxYNhxQOqbWnc",
- "KkrKeVatCcRmpIQWNHjBgubl0gOy8nup6oIbWdic+Pufr9gyLPo21MmxeSZ7V/VNZNH+Hfk6MGemGz7/",
- "GFBJRfkuGxGQq+uLdSF083RAVlKt7vI9iMpErolLN7nOZ0uJR6k9/jZTGDE/KNX5WLISgE9OrBrpD8at",
- "8jOHmZUvtDTsMKZC8HO1qlbC3wd0JhA08JC3NATDQzamNoHqgJzqfUB+sots9sVCMdAI6pOFBr4gf2UO",
- "Yq+cj2ZCxpjyyyC5TjCPChvIaHDuAccZ9WG4zp7Oya+NNKfgXSqZrVerMmuO0WVCJoSR2kypfk2icX+G",
- "9zFiBw18qP9Nc30Y5VpYZ5P/j3BnRrISYo4rzdNk4lvRmqPtaYdOkUXH1BHGSkCWvwEAAP//D5F1qDAE",
- "AAA=",
-}
-
-// GetSwagger returns the content of the embedded swagger specification file
-// or error if failed to decode
+ "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) {
- 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
@@ -539,7 +559,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) {
@@ -557,12 +577,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()
@@ -588,3 +608,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/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 630770731a..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/oapi-codegen/oapi-codegen/v2 version v2.0.0-00010101000000-000000000000 DO NOT EDIT.
-package parameters
+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.BindStyledParameterWithOptions("simple", "p", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: false, Required: false})
- 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})
- 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})
- 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})
- 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})
- 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})
- 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})
- 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.BindStyledParameterWithOptions("simple", "X-Primitive", valueList[0], &XPrimitive, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false})
- 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})
- 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})
- 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})
- 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})
- 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})
- 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})
- 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})
- 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})
- 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.BindStyledParameterWithOptions("label", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- 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})
- 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.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true})
- 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})
- 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.BindStyledParameterWithOptions("matrix", "id", ctx.Param("id"), &id, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- 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})
- 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.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: true, Required: true})
- 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})
- 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.BindStyledParameterWithOptions("simple", "param", ctx.Param("param"), ¶m, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
- 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})
- 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})
- 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/doc.go b/internal/test/parameters/doc.go
index 30d5b502e5..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/oapi-codegen/oapi-codegen/v2/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 71%
rename from internal/test/parameters/parameters_test.go
rename to internal/test/parameters/echo/parameters_test.go
index 29f6680e02..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/oapi-codegen/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{
@@ -269,7 +311,7 @@ func TestParameterBinding(t *testing.T) {
// (GET /passThrough/{param})
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()
@@ -369,6 +411,36 @@ func TestParameterBinding(t *testing.T) {
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)
@@ -427,6 +499,25 @@ func TestParameterBinding(t *testing.T) {
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
@@ -517,221 +608,5 @@ func TestParameterBinding(t *testing.T) {
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/schemas.gen.go b/internal/test/schemas/schemas.gen.go
index 09efa4a018..05562de26b 100644
--- a/internal/test/schemas/schemas.gen.go
+++ b/internal/test/schemas/schemas.gen.go
@@ -5,7 +5,7 @@ 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.BindStyledParameterWithOptions("simple", "str", ctx.Param("str"), &str, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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.BindStyledParameterWithOptions("simple", "fallthrough", ctx.Param("fallthrough"), &pFallthrough, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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.BindStyledParameterWithOptions("simple", "1param", ctx.Param("1param"), &n1param, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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/server.gen.go b/internal/test/server/server.gen.go
index e360916b3a..df00ee714b 100644
--- a/internal/test/server/server.gen.go
+++ b/internal/test/server/server.gen.go
@@ -4,6 +4,7 @@
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"`
@@ -268,30 +281,34 @@ func (siw *ServerInterfaceWrapper) GetSimple(w http.ResponseWriter, r *http.Requ
func (siw *ServerInterfaceWrapper) GetWithArgs(w http.ResponseWriter, r *http.Request) {
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
}
@@ -306,7 +323,7 @@ func (siw *ServerInterfaceWrapper) GetWithArgs(w http.ResponseWriter, r *http.Re
return
}
- err = runtime.BindStyledParameterWithOptions("simple", "header_argument", valueList[0], &HeaderArgument, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false})
+ 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
@@ -331,11 +348,12 @@ func (siw *ServerInterfaceWrapper) GetWithArgs(w http.ResponseWriter, r *http.Re
func (siw *ServerInterfaceWrapper) GetWithReferences(w http.ResponseWriter, r *http.Request) {
var err error
+ _ = err
// ------------- Path parameter "global_argument" -------------
var globalArgument int64
- err = runtime.BindStyledParameterWithOptions("simple", "global_argument", chi.URLParam(r, "global_argument"), &globalArgument, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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
@@ -344,7 +362,7 @@ func (siw *ServerInterfaceWrapper) GetWithReferences(w http.ResponseWriter, r *h
// ------------- Path parameter "argument" -------------
var argument Argument
- err = runtime.BindStyledParameterWithOptions("simple", "argument", chi.URLParam(r, "argument"), &argument, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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
@@ -365,11 +383,12 @@ func (siw *ServerInterfaceWrapper) GetWithReferences(w http.ResponseWriter, r *h
func (siw *ServerInterfaceWrapper) GetWithContentType(w http.ResponseWriter, r *http.Request) {
var err error
+ _ = err
// ------------- Path parameter "content_type" -------------
var contentType GetWithContentTypeParamsContentType
- err = runtime.BindStyledParameterWithOptions("simple", "content_type", chi.URLParam(r, "content_type"), &contentType, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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
@@ -404,11 +423,12 @@ func (siw *ServerInterfaceWrapper) GetReservedKeyword(w http.ResponseWriter, r *
func (siw *ServerInterfaceWrapper) CreateResource(w http.ResponseWriter, r *http.Request) {
var err error
+ _ = err
// ------------- Path parameter "argument" -------------
var argument Argument
- err = runtime.BindStyledParameterWithOptions("simple", "argument", chi.URLParam(r, "argument"), &argument, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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,11 +449,12 @@ func (siw *ServerInterfaceWrapper) CreateResource(w http.ResponseWriter, r *http
func (siw *ServerInterfaceWrapper) CreateResource2(w http.ResponseWriter, r *http.Request) {
var err error
+ _ = err
// ------------- Path parameter "inline_argument" -------------
var inlineArgument int
- err = runtime.BindStyledParameterWithOptions("simple", "inline_argument", chi.URLParam(r, "inline_argument"), &inlineArgument, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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
@@ -444,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
}
@@ -465,11 +491,12 @@ func (siw *ServerInterfaceWrapper) CreateResource2(w http.ResponseWriter, r *htt
func (siw *ServerInterfaceWrapper) UpdateResource3(w http.ResponseWriter, r *http.Request) {
var err error
+ _ = err
// ------------- Path parameter "fallthrough" -------------
var pFallthrough int
- err = runtime.BindStyledParameterWithOptions("simple", "fallthrough", chi.URLParam(r, "fallthrough"), &pFallthrough, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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
diff --git a/internal/test/strict-server/chi/server.gen.go b/internal/test/strict-server/chi/server.gen.go
index c8c7a09245..f54a6191ed 100644
--- a/internal/test/strict-server/chi/server.gen.go
+++ b/internal/test/strict-server/chi/server.gen.go
@@ -5,10 +5,11 @@ package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
+ "errors"
"fmt"
"io"
"mime"
@@ -21,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.
@@ -39,6 +39,15 @@ type ServerInterface interface {
// (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)
@@ -88,6 +97,21 @@ func (_ Unimplemented) MultipleRequestAndResponseTypes(w http.ResponseWriter, r
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)
@@ -193,15 +217,58 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(w http.Respon
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", chi.URLParam(r, "type"), &pType, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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
@@ -292,6 +359,7 @@ func (siw *ServerInterfaceWrapper) URLEncodedExample(w http.ResponseWriter, r *h
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
@@ -307,7 +375,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http
return
}
- err = runtime.BindStyledParameterWithOptions("simple", "header1", valueList[0], &Header1, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true})
+ 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
@@ -330,7 +398,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http
return
}
- err = runtime.BindStyledParameterWithOptions("simple", "header2", valueList[0], &Header2, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false})
+ 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
@@ -490,6 +558,15 @@ func HandlerWithOptions(si ServerInterface, options ChiServerOptions) http.Handl
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)
})
@@ -542,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
@@ -576,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)
@@ -611,6 +694,7 @@ type MultipartRelatedExample200MultipartResponse func(writer *multipart.Writer)
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)
@@ -649,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 {
@@ -675,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))
@@ -692,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)
@@ -702,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)
@@ -716,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"`
}
@@ -727,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)
@@ -745,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
@@ -780,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)
@@ -817,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))
@@ -862,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))
@@ -918,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
@@ -955,8 +1156,10 @@ type HeadersExampleResponseObject interface {
}
type HeadersExample200ResponseHeaders struct {
- Header1 string
- Header2 int
+ Header1 string
+ Header2 int
+ NullableHeader *string
+ OptionalHeader *string
}
type HeadersExample200JSONResponse struct {
@@ -965,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
@@ -1008,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
@@ -1063,6 +1285,15 @@ type StrictServerInterface interface {
// (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)
@@ -1088,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)
@@ -1123,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))
@@ -1221,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 {
@@ -1255,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) {
@@ -1279,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
@@ -1311,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))
@@ -1345,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))
@@ -1465,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))
@@ -1496,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))
@@ -1521,44 +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/+xYS3PbNhD+Kxi0p5QUZccn3hpPJm3T1h3ZPnV8gIilhIQE0MVStEaj/94BQb0sWpUS",
- "PTqZ3PhY7C6+b3ex2BnPTGmNBk2OpzOO4KzRDpqXoZAI/1TgyL9JcBkqS8ponvJ3Qg7af/OII1RODAtY",
- "LPfymdEEulkqrC1UJvzS5JPz62fcZWMohX/6ESHnKf8hWbmShL8ugWdR2gL4fD6PXnhw95FHfAxCAjbe",
- "hserTd00tcBT7giVHnGvJIhdd4opTTAC9Na8aOuEF1j4kc64RWMBSQWMJqKooNtS+8UMP0FGYQdK52Yb",
- "y1ujSSjtmFR5DgiaWAse8zocc5W1BgkkG06Zt5ARc4ATQB5xUuQd4/fr31nrsOMRnwC6YOiq1+/1PV/G",
- "ghZW8ZS/bT5F3AoaNxtaEmRNF++/3d/9yZRjoiJTClKZKIopKwW6sShAMqXJeBerjFyPN5awIf5X2a5+",
- "30Lpo6YJoHdGTk8RME1croXzdb9/pricR/wmGOvSsXQqWUuwRk0uqqID80f9WZtaM0A02O4sKauClBVI",
- "61xtov3HQmQfyJf6ktxgGUtB4kSoH8vSpYGPEQpBIPcgYBAkD+NhTf1JWfgaOxfloK3HnXXqfmxqx8am",
- "ZmSYBFGwWtGYLRa+KLBKM8Gc0qMC2MKpqJPMAtpj72ctB+1eHryOk9ezaEPLc1zXddwkUIUF6MzIL6Mw",
- "4qoUI0isHm0u97oF8ZQPp+RDdvuAO1IiR5zgmRJbCKV3n95nKunfkT5aYod0RWi6EhmPTPwZprVBGVuB",
- "ogQCdMnMW597xSPoSOW/lpIsE5oNgWlRgmQiJ0D2wbBWpdtK2UFr94P5GERWqpqWZ/mS/j3jHpKmDeIR",
- "9wZ4GlAJea3Qk05YQbQDtqf/jM+vImCBZmi24w1T3WVwUaKW0CHkzpfELuY68AuWBmsSl2nadkfc1vXj",
- "HGeQZ/L1o/8Bnvdqu45Y+s6d24cCVoWPr2PWrtoHti+spHugOFESTFLamwM1XwxUZyFTuQIZt7uIg2+v",
- "lYRbozME2myB/JVOG2JLZf6mSWNgAYGIOcNqYGXliFnhHFPUVJFChduqhK3i8bjy7DZYeliV012svjkR",
- "p28uxehN/+rwJW9PHDcbrcwr+Tj4/X2QOfTOfrSe6cCO73h2L5TO/pISrw21ulP4lyCwOtMzUBPfEWnJ",
- "EKhCDZJNlFgMYrZys1WworWrFwpurLqhxYDtkIYo2qnrmke7hnBP3/CI6JSjy3PFaaXVrlHho//N2h76",
- "5dmgjP6fDgJFQYBakJrAT8e5QW5rMRru8ibTXrAc7Wnh6duLqnnEw+w6lKAKC18niGyaJGHm3XO1GI0A",
- "e8okwiqPwr8BAAD//4h9qqfAGAAA",
-}
-
-// 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
@@ -1566,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) {
@@ -1584,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()
@@ -1615,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 c135a2a445..1f4c633fae 100644
--- a/internal/test/strict-server/chi/server.go
+++ b/internal/test/strict-server/chi/server.go
@@ -122,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.gen.go b/internal/test/strict-server/chi/types.gen.go
index 6682c1acab..08ae8548e1 100644
--- a/internal/test/strict-server/chi/types.gen.go
+++ b/internal/test/strict-server/chi/types.gen.go
@@ -3,6 +3,12 @@
// 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,6 +32,14 @@ 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
@@ -44,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
@@ -58,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.gen.go b/internal/test/strict-server/client/client.gen.go
index e7959520e4..a076eddef0 100644
--- a/internal/test/strict-server/client/client.gen.go
+++ b/internal/test/strict-server/client/client.gen.go
@@ -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,6 +39,14 @@ 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
@@ -57,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
@@ -72,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
@@ -165,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)
@@ -296,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 {
@@ -482,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
}
@@ -511,7 +663,7 @@ 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
}
@@ -540,7 +692,7 @@ func NewMultipartRelatedExampleRequestWithBody(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
}
@@ -575,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)
}
@@ -598,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
}
@@ -614,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
}
@@ -634,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
}
@@ -672,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
}
@@ -685,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)
}
@@ -708,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
}
@@ -737,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
}
@@ -766,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
}
@@ -806,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
}
@@ -846,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
}
@@ -857,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
}
@@ -867,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
}
@@ -910,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
}
@@ -983,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)
@@ -1024,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 {
@@ -1040,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 {
@@ -1061,11 +1364,24 @@ 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 {
@@ -1082,12 +1398,30 @@ func (r MultipartRelatedExampleResponse) StatusCode() int {
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 {
@@ -1104,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 {
@@ -1125,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 {
@@ -1147,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 {
@@ -1168,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 {
@@ -1189,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 {
@@ -1210,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 {
@@ -1231,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 {
@@ -1253,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
@@ -1278,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...)
@@ -1346,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...)
@@ -1545,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)
@@ -1699,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/echo/server.gen.go b/internal/test/strict-server/echo/server.gen.go
index f07dfa5e46..f3d5f6eaf9 100644
--- a/internal/test/strict-server/echo/server.gen.go
+++ b/internal/test/strict-server/echo/server.gen.go
@@ -5,10 +5,11 @@ package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
+ "errors"
"fmt"
"io"
"mime"
@@ -21,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.
@@ -39,6 +39,15 @@ type ServerInterface interface {
// (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
@@ -105,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.BindStyledParameterWithOptions("simple", "type", ctx.Param("type"), &pType, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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))
}
@@ -182,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.BindStyledParameterWithOptions("simple", "header1", valueList[0], &Header1, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true})
+ 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))
}
@@ -199,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.BindStyledParameterWithOptions("simple", "header2", valueList[0], &Header2, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false})
+ 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))
}
@@ -236,31 +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+"/multipart-related", wrapper.MultipartRelatedExample)
- 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"]...)
}
@@ -288,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
@@ -322,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)
@@ -357,6 +421,7 @@ type MultipartRelatedExample200MultipartResponse func(writer *multipart.Writer)
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)
@@ -395,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 {
@@ -421,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))
@@ -438,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)
@@ -448,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)
@@ -462,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"`
}
@@ -473,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)
@@ -491,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
@@ -526,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)
@@ -563,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))
@@ -608,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))
@@ -664,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
@@ -701,8 +883,10 @@ type HeadersExampleResponseObject interface {
}
type HeadersExample200ResponseHeaders struct {
- Header1 string
- Header2 int
+ Header1 string
+ Header2 int
+ NullableHeader *string
+ OptionalHeader *string
}
type HeadersExample200JSONResponse struct {
@@ -711,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
@@ -754,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
@@ -809,6 +1012,15 @@ type StrictServerInterface interface {
// (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)
@@ -834,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}
@@ -852,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))
@@ -942,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 {
@@ -972,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) {
@@ -995,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
@@ -1026,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))
@@ -1057,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))
@@ -1172,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))
@@ -1201,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))
@@ -1224,44 +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/+xYS3PbNhD+Kxi0p5QUZccn3hpPJm3T1h3ZPnV8gIilhIQE0MVStEaj/94BQb0sWpUS",
- "PTqZ3PhY7C6+b3ex2BnPTGmNBk2OpzOO4KzRDpqXoZAI/1TgyL9JcBkqS8ponvJ3Qg7af/OII1RODAtY",
- "LPfymdEEulkqrC1UJvzS5JPz62fcZWMohX/6ESHnKf8hWbmShL8ugWdR2gL4fD6PXnhw95FHfAxCAjbe",
- "hserTd00tcBT7giVHnGvJIhdd4opTTAC9Na8aOuEF1j4kc64RWMBSQWMJqKooNtS+8UMP0FGYQdK52Yb",
- "y1ujSSjtmFR5DgiaWAse8zocc5W1BgkkG06Zt5ARc4ATQB5xUuQd4/fr31nrsOMRnwC6YOiq1+/1PV/G",
- "ghZW8ZS/bT5F3AoaNxtaEmRNF++/3d/9yZRjoiJTClKZKIopKwW6sShAMqXJeBerjFyPN5awIf5X2a5+",
- "30Lpo6YJoHdGTk8RME1croXzdb9/pricR/wmGOvSsXQqWUuwRk0uqqID80f9WZtaM0A02O4sKauClBVI",
- "61xtov3HQmQfyJf6ktxgGUtB4kSoH8vSpYGPEQpBIPcgYBAkD+NhTf1JWfgaOxfloK3HnXXqfmxqx8am",
- "ZmSYBFGwWtGYLRa+KLBKM8Gc0qMC2MKpqJPMAtpj72ctB+1eHryOk9ezaEPLc1zXddwkUIUF6MzIL6Mw",
- "4qoUI0isHm0u97oF8ZQPp+RDdvuAO1IiR5zgmRJbCKV3n95nKunfkT5aYod0RWi6EhmPTPwZprVBGVuB",
- "ogQCdMnMW597xSPoSOW/lpIsE5oNgWlRgmQiJ0D2wbBWpdtK2UFr94P5GERWqpqWZ/mS/j3jHpKmDeIR",
- "9wZ4GlAJea3Qk05YQbQDtqf/jM+vImCBZmi24w1T3WVwUaKW0CHkzpfELuY68AuWBmsSl2nadkfc1vXj",
- "HGeQZ/L1o/8Bnvdqu45Y+s6d24cCVoWPr2PWrtoHti+spHugOFESTFLamwM1XwxUZyFTuQIZt7uIg2+v",
- "lYRbozME2myB/JVOG2JLZf6mSWNgAYGIOcNqYGXliFnhHFPUVJFChduqhK3i8bjy7DZYeliV012svjkR",
- "p28uxehN/+rwJW9PHDcbrcwr+Tj4/X2QOfTOfrSe6cCO73h2L5TO/pISrw21ulP4lyCwOtMzUBPfEWnJ",
- "EKhCDZJNlFgMYrZys1WworWrFwpurLqhxYDtkIYo2qnrmke7hnBP3/CI6JSjy3PFaaXVrlHho//N2h76",
- "5dmgjP6fDgJFQYBakJrAT8e5QW5rMRru8ibTXrAc7Wnh6duLqnnEw+w6lKAKC18niGyaJGHm3XO1GI0A",
- "e8okwiqPwr8BAAD//4h9qqfAGAAA",
-}
-
-// 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
@@ -1269,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) {
@@ -1287,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()
@@ -1318,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 c135a2a445..1f4c633fae 100644
--- a/internal/test/strict-server/echo/server.go
+++ b/internal/test/strict-server/echo/server.go
@@ -122,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.gen.go b/internal/test/strict-server/echo/types.gen.go
index 6682c1acab..08ae8548e1 100644
--- a/internal/test/strict-server/echo/types.gen.go
+++ b/internal/test/strict-server/echo/types.gen.go
@@ -3,6 +3,12 @@
// 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,6 +32,14 @@ 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
@@ -44,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
@@ -58,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.gen.go b/internal/test/strict-server/fiber/server.gen.go
index b15d923fd0..aa69ce929a 100644
--- a/internal/test/strict-server/fiber/server.gen.go
+++ b/internal/test/strict-server/fiber/server.gen.go
@@ -5,10 +5,10 @@ package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
- "encoding/json"
+ "errors"
"fmt"
"io"
"mime"
@@ -38,6 +38,15 @@ type ServerInterface interface {
// (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
@@ -65,85 +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 {
- return siw.Handler.MultipartRelatedExample(c)
+ 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.BindStyledParameterWithOptions("simple", "type", c.Params("type"), &pType, runtime.BindStyledParameterOptions{Explode: false, Required: true})
+ 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
@@ -151,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.BindStyledParameterWithOptions("simple", "header1", value, &Header1, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true})
+ 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())
}
@@ -167,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.BindStyledParameterWithOptions("simple", "header2", value, &Header2, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false})
+ 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())
}
@@ -179,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.
@@ -202,7 +422,8 @@ 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 {
@@ -217,6 +438,12 @@ func RegisterHandlersWithOptions(router fiber.Router, si ServerInterface, option
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)
@@ -433,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"`
}
@@ -672,8 +993,10 @@ type HeadersExampleResponseObject interface {
}
type HeadersExample200ResponseHeaders struct {
- Header1 string
- Header2 int
+ Header1 string
+ Header2 int
+ NullableHeader *string
+ OptionalHeader *string
}
type HeadersExample200JSONResponse struct {
@@ -684,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)
@@ -734,9 +1063,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion
}
type UnionExample200JSONResponse struct {
- Body struct {
- union json.RawMessage
- }
+ Body UnionExample200JSONResponseBody
Headers UnionExample200ResponseHeaders
}
@@ -780,6 +1107,15 @@ type StrictServerInterface interface {
// (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)
@@ -805,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 {
@@ -824,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))
@@ -917,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
@@ -936,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) {
@@ -961,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
@@ -994,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))
@@ -1024,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))
@@ -1143,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))
@@ -1174,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))
@@ -1199,44 +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/+xYS3PbNhD+Kxi0p5QUZccn3hpPJm3T1h3ZPnV8gIilhIQE0MVStEaj/94BQb0sWpUS",
- "PTqZ3PhY7C6+b3ex2BnPTGmNBk2OpzOO4KzRDpqXoZAI/1TgyL9JcBkqS8ponvJ3Qg7af/OII1RODAtY",
- "LPfymdEEulkqrC1UJvzS5JPz62fcZWMohX/6ESHnKf8hWbmShL8ugWdR2gL4fD6PXnhw95FHfAxCAjbe",
- "hserTd00tcBT7giVHnGvJIhdd4opTTAC9Na8aOuEF1j4kc64RWMBSQWMJqKooNtS+8UMP0FGYQdK52Yb",
- "y1ujSSjtmFR5DgiaWAse8zocc5W1BgkkG06Zt5ARc4ATQB5xUuQd4/fr31nrsOMRnwC6YOiq1+/1PV/G",
- "ghZW8ZS/bT5F3AoaNxtaEmRNF++/3d/9yZRjoiJTClKZKIopKwW6sShAMqXJeBerjFyPN5awIf5X2a5+",
- "30Lpo6YJoHdGTk8RME1croXzdb9/pricR/wmGOvSsXQqWUuwRk0uqqID80f9WZtaM0A02O4sKauClBVI",
- "61xtov3HQmQfyJf6ktxgGUtB4kSoH8vSpYGPEQpBIPcgYBAkD+NhTf1JWfgaOxfloK3HnXXqfmxqx8am",
- "ZmSYBFGwWtGYLRa+KLBKM8Gc0qMC2MKpqJPMAtpj72ctB+1eHryOk9ezaEPLc1zXddwkUIUF6MzIL6Mw",
- "4qoUI0isHm0u97oF8ZQPp+RDdvuAO1IiR5zgmRJbCKV3n95nKunfkT5aYod0RWi6EhmPTPwZprVBGVuB",
- "ogQCdMnMW597xSPoSOW/lpIsE5oNgWlRgmQiJ0D2wbBWpdtK2UFr94P5GERWqpqWZ/mS/j3jHpKmDeIR",
- "9wZ4GlAJea3Qk05YQbQDtqf/jM+vImCBZmi24w1T3WVwUaKW0CHkzpfELuY68AuWBmsSl2nadkfc1vXj",
- "HGeQZ/L1o/8Bnvdqu45Y+s6d24cCVoWPr2PWrtoHti+spHugOFESTFLamwM1XwxUZyFTuQIZt7uIg2+v",
- "lYRbozME2myB/JVOG2JLZf6mSWNgAYGIOcNqYGXliFnhHFPUVJFChduqhK3i8bjy7DZYeliV012svjkR",
- "p28uxehN/+rwJW9PHDcbrcwr+Tj4/X2QOfTOfrSe6cCO73h2L5TO/pISrw21ulP4lyCwOtMzUBPfEWnJ",
- "EKhCDZJNlFgMYrZys1WworWrFwpurLqhxYDtkIYo2qnrmke7hnBP3/CI6JSjy3PFaaXVrlHho//N2h76",
- "5dmgjP6fDgJFQYBakJrAT8e5QW5rMRru8ibTXrAc7Wnh6duLqnnEw+w6lKAKC18niGyaJGHm3XO1GI0A",
- "e8okwiqPwr8BAAD//4h9qqfAGAAA",
-}
-
-// 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
@@ -1244,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) {
@@ -1262,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()
@@ -1293,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 c135a2a445..1f4c633fae 100644
--- a/internal/test/strict-server/fiber/server.go
+++ b/internal/test/strict-server/fiber/server.go
@@ -122,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.gen.go b/internal/test/strict-server/fiber/types.gen.go
index 6682c1acab..08ae8548e1 100644
--- a/internal/test/strict-server/fiber/types.gen.go
+++ b/internal/test/strict-server/fiber/types.gen.go
@@ -3,6 +3,12 @@
// 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,6 +32,14 @@ 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
@@ -44,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
@@ -58,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.gen.go b/internal/test/strict-server/gin/server.gen.go
index 21f9f32763..b5294a5b54 100644
--- a/internal/test/strict-server/gin/server.gen.go
+++ b/internal/test/strict-server/gin/server.gen.go
@@ -5,10 +5,11 @@ package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
+ "errors"
"fmt"
"io"
"mime"
@@ -21,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.
@@ -39,6 +39,15 @@ type ServerInterface interface {
// (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)
@@ -125,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.BindStyledParameterWithOptions("simple", "type", c.Param("type"), &pType, runtime.BindStyledParameterOptions{Explode: false, Required: true})
+ 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
@@ -218,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
@@ -233,7 +283,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) {
return
}
- err = runtime.BindStyledParameterWithOptions("simple", "header1", valueList[0], &Header1, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true})
+ 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
@@ -255,7 +305,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(c *gin.Context) {
return
}
- err = runtime.BindStyledParameterWithOptions("simple", "header2", valueList[0], &Header2, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false})
+ 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
@@ -319,6 +369,9 @@ func RegisterHandlersWithOptions(router gin.IRouter, si ServerInterface, options
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)
@@ -353,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
@@ -387,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)
@@ -422,6 +481,7 @@ type MultipartRelatedExample200MultipartResponse func(writer *multipart.Writer)
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)
@@ -460,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 {
@@ -486,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))
@@ -503,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)
@@ -513,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)
@@ -527,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"`
}
@@ -538,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)
@@ -556,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
@@ -591,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)
@@ -628,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))
@@ -673,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))
@@ -729,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
@@ -766,8 +943,10 @@ type HeadersExampleResponseObject interface {
}
type HeadersExample200ResponseHeaders struct {
- Header1 string
- Header2 int
+ Header1 string
+ Header2 int
+ NullableHeader *string
+ OptionalHeader *string
}
type HeadersExample200JSONResponse struct {
@@ -776,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
@@ -819,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
@@ -874,6 +1072,15 @@ type StrictServerInterface interface {
// (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)
@@ -899,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
@@ -917,11 +1169,13 @@ func (sh *strictHandler) JSONExample(ctx *gin.Context) {
var body JSONExampleJSONRequestBody
if err := ctx.ShouldBindJSON(&body); err != nil {
- ctx.Status(http.StatusBadRequest)
- ctx.Error(err)
- return
+ 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))
@@ -933,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))
}
}
@@ -948,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) {
@@ -965,14 +1218,13 @@ 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 {
- ctx.Error(fmt.Errorf("unexpected response type: %T", response))
+ sh.options.ResponseErrorHandlerFunc(ctx, fmt.Errorf("unexpected response type: %T", response))
}
}
@@ -981,10 +1233,10 @@ func (sh *strictHandler) MultipartRelatedExample(ctx *gin.Context) {
var request MultipartRelatedExampleRequestObject
if _, params, err := mime.ParseMediaType(ctx.Request.Header.Get("Content-Type")); err != nil {
- ctx.Error(err)
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
} else if boundary := params["boundary"]; boundary == "" {
- ctx.Error(http.ErrMissingBoundary)
+ sh.options.RequestErrorHandlerFunc(ctx, http.ErrMissingBoundary)
return
} else {
request.Body = multipart.NewReader(ctx.Request.Body, boundary)
@@ -1000,14 +1252,13 @@ func (sh *strictHandler) MultipartRelatedExample(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.(MultipartRelatedExampleResponseObject); ok {
if err := validResponse.VisitMultipartRelatedExampleResponse(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))
}
}
@@ -1019,20 +1270,22 @@ func (sh *strictHandler) MultipleRequestAndResponseTypes(ctx *gin.Context) {
var body MultipleRequestAndResponseTypesJSONRequestBody
if err := ctx.ShouldBindJSON(&body); err != nil {
- ctx.Status(http.StatusBadRequest)
- ctx.Error(err)
- return
+ 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
@@ -1041,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) {
@@ -1068,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))
}
}
@@ -1095,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))
}
}
@@ -1112,11 +1452,13 @@ func (sh *strictHandler) ReusableResponses(ctx *gin.Context) {
var body ReusableResponsesJSONRequestBody
if err := ctx.ShouldBindJSON(&body); err != nil {
- ctx.Status(http.StatusBadRequest)
- ctx.Error(err)
- return
+ 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))
@@ -1128,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))
}
}
@@ -1145,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))
@@ -1161,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))
}
}
@@ -1188,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))
}
}
@@ -1217,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))
}
}
@@ -1233,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
@@ -1253,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))
}
}
@@ -1272,11 +1611,13 @@ func (sh *strictHandler) HeadersExample(ctx *gin.Context, params HeadersExampleP
var body HeadersExampleJSONRequestBody
if err := ctx.ShouldBindJSON(&body); err != nil {
- ctx.Status(http.StatusBadRequest)
- ctx.Error(err)
- return
+ 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))
@@ -1288,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))
}
}
@@ -1305,11 +1645,13 @@ func (sh *strictHandler) UnionExample(ctx *gin.Context) {
var body UnionExampleJSONRequestBody
if err := ctx.ShouldBindJSON(&body); err != nil {
- ctx.Status(http.StatusBadRequest)
- ctx.Error(err)
- return
+ 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))
@@ -1321,55 +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/+xYS3PbNhD+Kxi0p5QUZccn3hpPJm3T1h3ZPnV8gIilhIQE0MVStEaj/94BQb0sWpUS",
- "PTqZ3PhY7C6+b3ex2BnPTGmNBk2OpzOO4KzRDpqXoZAI/1TgyL9JcBkqS8ponvJ3Qg7af/OII1RODAtY",
- "LPfymdEEulkqrC1UJvzS5JPz62fcZWMohX/6ESHnKf8hWbmShL8ugWdR2gL4fD6PXnhw95FHfAxCAjbe",
- "hserTd00tcBT7giVHnGvJIhdd4opTTAC9Na8aOuEF1j4kc64RWMBSQWMJqKooNtS+8UMP0FGYQdK52Yb",
- "y1ujSSjtmFR5DgiaWAse8zocc5W1BgkkG06Zt5ARc4ATQB5xUuQd4/fr31nrsOMRnwC6YOiq1+/1PV/G",
- "ghZW8ZS/bT5F3AoaNxtaEmRNF++/3d/9yZRjoiJTClKZKIopKwW6sShAMqXJeBerjFyPN5awIf5X2a5+",
- "30Lpo6YJoHdGTk8RME1croXzdb9/pricR/wmGOvSsXQqWUuwRk0uqqID80f9WZtaM0A02O4sKauClBVI",
- "61xtov3HQmQfyJf6ktxgGUtB4kSoH8vSpYGPEQpBIPcgYBAkD+NhTf1JWfgaOxfloK3HnXXqfmxqx8am",
- "ZmSYBFGwWtGYLRa+KLBKM8Gc0qMC2MKpqJPMAtpj72ctB+1eHryOk9ezaEPLc1zXddwkUIUF6MzIL6Mw",
- "4qoUI0isHm0u97oF8ZQPp+RDdvuAO1IiR5zgmRJbCKV3n95nKunfkT5aYod0RWi6EhmPTPwZprVBGVuB",
- "ogQCdMnMW597xSPoSOW/lpIsE5oNgWlRgmQiJ0D2wbBWpdtK2UFr94P5GERWqpqWZ/mS/j3jHpKmDeIR",
- "9wZ4GlAJea3Qk05YQbQDtqf/jM+vImCBZmi24w1T3WVwUaKW0CHkzpfELuY68AuWBmsSl2nadkfc1vXj",
- "HGeQZ/L1o/8Bnvdqu45Y+s6d24cCVoWPr2PWrtoHti+spHugOFESTFLamwM1XwxUZyFTuQIZt7uIg2+v",
- "lYRbozME2myB/JVOG2JLZf6mSWNgAYGIOcNqYGXliFnhHFPUVJFChduqhK3i8bjy7DZYeliV012svjkR",
- "p28uxehN/+rwJW9PHDcbrcwr+Tj4/X2QOfTOfrSe6cCO73h2L5TO/pISrw21ulP4lyCwOtMzUBPfEWnJ",
- "EKhCDZJNlFgMYrZys1WworWrFwpurLqhxYDtkIYo2qnrmke7hnBP3/CI6JSjy3PFaaXVrlHho//N2h76",
- "5dmgjP6fDgJFQYBakJrAT8e5QW5rMRru8ibTXrAc7Wnh6duLqnnEw+w6lKAKC18niGyaJGHm3XO1GI0A",
- "e8okwiqPwr8BAAD//4h9qqfAGAAA",
-}
-
-// 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
@@ -1377,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) {
@@ -1395,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()
@@ -1426,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 c135a2a445..1f4c633fae 100644
--- a/internal/test/strict-server/gin/server.go
+++ b/internal/test/strict-server/gin/server.go
@@ -122,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.gen.go b/internal/test/strict-server/gin/types.gen.go
index 6682c1acab..08ae8548e1 100644
--- a/internal/test/strict-server/gin/types.gen.go
+++ b/internal/test/strict-server/gin/types.gen.go
@@ -3,6 +3,12 @@
// 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,6 +32,14 @@ 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
@@ -44,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
@@ -58,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.gen.go b/internal/test/strict-server/gorilla/server.gen.go
index c6b29393df..e8d9dc439d 100644
--- a/internal/test/strict-server/gorilla/server.gen.go
+++ b/internal/test/strict-server/gorilla/server.gen.go
@@ -5,10 +5,11 @@ package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
+ "errors"
"fmt"
"io"
"mime"
@@ -21,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.
@@ -39,6 +39,15 @@ type ServerInterface interface {
// (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)
@@ -129,15 +138,58 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(w http.Respon
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", mux.Vars(r)["type"], &pType, runtime.BindStyledParameterOptions{Explode: false, Required: true})
+ 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
@@ -228,6 +280,7 @@ func (siw *ServerInterfaceWrapper) URLEncodedExample(w http.ResponseWriter, r *h
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
@@ -243,7 +296,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http
return
}
- err = runtime.BindStyledParameterWithOptions("simple", "header1", valueList[0], &Header1, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true})
+ 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
@@ -266,7 +319,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http
return
}
- err = runtime.BindStyledParameterWithOptions("simple", "header2", valueList[0], &Header2, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false})
+ 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
@@ -414,29 +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+"/multipart-related", wrapper.MultipartRelatedExample).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/no-content-headers", wrapper.NoContentHeaders).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/required-json-body", wrapper.RequiredJSONBody).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/reserved-go-keyword-parameters/{type}", wrapper.ReservedGoKeywordParameters).Methods("GET")
+ r.HandleFunc(options.BaseURL+"/required-text-body", wrapper.RequiredTextBody).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/reserved-go-keyword-parameters/{type}", wrapper.ReservedGoKeywordParameters).Methods(http.MethodGet)
- r.HandleFunc(options.BaseURL+"/text", wrapper.TextExample).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/reusable-responses", wrapper.ReusableResponses).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/unknown", wrapper.UnknownExample).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/text", wrapper.TextExample).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/unknown", wrapper.UnknownExample).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/with-headers", wrapper.HeadersExample).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/urlencoded", wrapper.URLEncodedExample).Methods(http.MethodPost)
- r.HandleFunc(options.BaseURL+"/with-union", wrapper.UnionExample).Methods("POST")
+ r.HandleFunc(options.BaseURL+"/with-headers", wrapper.HeadersExample).Methods(http.MethodPost)
+
+ r.HandleFunc(options.BaseURL+"/with-union", wrapper.UnionExample).Methods(http.MethodPost)
return r
}
@@ -465,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
@@ -499,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)
@@ -534,6 +599,7 @@ type MultipartRelatedExample200MultipartResponse func(writer *multipart.Writer)
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)
@@ -572,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 {
@@ -598,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))
@@ -615,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)
@@ -625,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)
@@ -639,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"`
}
@@ -650,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)
@@ -668,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
@@ -703,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)
@@ -740,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))
@@ -785,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))
@@ -841,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
@@ -878,8 +1061,10 @@ type HeadersExampleResponseObject interface {
}
type HeadersExample200ResponseHeaders struct {
- Header1 string
- Header2 int
+ Header1 string
+ Header2 int
+ NullableHeader *string
+ OptionalHeader *string
}
type HeadersExample200JSONResponse struct {
@@ -888,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
@@ -931,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
@@ -986,6 +1190,15 @@ type StrictServerInterface interface {
// (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)
@@ -1011,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)
@@ -1046,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))
@@ -1144,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 {
@@ -1178,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) {
@@ -1202,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
@@ -1234,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))
@@ -1268,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))
@@ -1388,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))
@@ -1419,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))
@@ -1444,44 +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/+xYS3PbNhD+Kxi0p5QUZccn3hpPJm3T1h3ZPnV8gIilhIQE0MVStEaj/94BQb0sWpUS",
- "PTqZ3PhY7C6+b3ex2BnPTGmNBk2OpzOO4KzRDpqXoZAI/1TgyL9JcBkqS8ponvJ3Qg7af/OII1RODAtY",
- "LPfymdEEulkqrC1UJvzS5JPz62fcZWMohX/6ESHnKf8hWbmShL8ugWdR2gL4fD6PXnhw95FHfAxCAjbe",
- "hserTd00tcBT7giVHnGvJIhdd4opTTAC9Na8aOuEF1j4kc64RWMBSQWMJqKooNtS+8UMP0FGYQdK52Yb",
- "y1ujSSjtmFR5DgiaWAse8zocc5W1BgkkG06Zt5ARc4ATQB5xUuQd4/fr31nrsOMRnwC6YOiq1+/1PV/G",
- "ghZW8ZS/bT5F3AoaNxtaEmRNF++/3d/9yZRjoiJTClKZKIopKwW6sShAMqXJeBerjFyPN5awIf5X2a5+",
- "30Lpo6YJoHdGTk8RME1croXzdb9/pricR/wmGOvSsXQqWUuwRk0uqqID80f9WZtaM0A02O4sKauClBVI",
- "61xtov3HQmQfyJf6ktxgGUtB4kSoH8vSpYGPEQpBIPcgYBAkD+NhTf1JWfgaOxfloK3HnXXqfmxqx8am",
- "ZmSYBFGwWtGYLRa+KLBKM8Gc0qMC2MKpqJPMAtpj72ctB+1eHryOk9ezaEPLc1zXddwkUIUF6MzIL6Mw",
- "4qoUI0isHm0u97oF8ZQPp+RDdvuAO1IiR5zgmRJbCKV3n95nKunfkT5aYod0RWi6EhmPTPwZprVBGVuB",
- "ogQCdMnMW597xSPoSOW/lpIsE5oNgWlRgmQiJ0D2wbBWpdtK2UFr94P5GERWqpqWZ/mS/j3jHpKmDeIR",
- "9wZ4GlAJea3Qk05YQbQDtqf/jM+vImCBZmi24w1T3WVwUaKW0CHkzpfELuY68AuWBmsSl2nadkfc1vXj",
- "HGeQZ/L1o/8Bnvdqu45Y+s6d24cCVoWPr2PWrtoHti+spHugOFESTFLamwM1XwxUZyFTuQIZt7uIg2+v",
- "lYRbozME2myB/JVOG2JLZf6mSWNgAYGIOcNqYGXliFnhHFPUVJFChduqhK3i8bjy7DZYeliV012svjkR",
- "p28uxehN/+rwJW9PHDcbrcwr+Tj4/X2QOfTOfrSe6cCO73h2L5TO/pISrw21ulP4lyCwOtMzUBPfEWnJ",
- "EKhCDZJNlFgMYrZys1WworWrFwpurLqhxYDtkIYo2qnrmke7hnBP3/CI6JSjy3PFaaXVrlHho//N2h76",
- "5dmgjP6fDgJFQYBakJrAT8e5QW5rMRru8ibTXrAc7Wnh6duLqnnEw+w6lKAKC18niGyaJGHm3XO1GI0A",
- "e8okwiqPwr8BAAD//4h9qqfAGAAA",
-}
-
-// 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
@@ -1489,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) {
@@ -1507,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()
@@ -1538,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 5c5d7c9e77..3d3890d982 100644
--- a/internal/test/strict-server/gorilla/server.go
+++ b/internal/test/strict-server/gorilla/server.go
@@ -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.gen.go b/internal/test/strict-server/gorilla/types.gen.go
index 6682c1acab..08ae8548e1 100644
--- a/internal/test/strict-server/gorilla/types.gen.go
+++ b/internal/test/strict-server/gorilla/types.gen.go
@@ -3,6 +3,12 @@
// 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,6 +32,14 @@ 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
@@ -44,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
@@ -58,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.gen.go b/internal/test/strict-server/iris/server.gen.go
index 7f224b3b37..54c401bab9 100644
--- a/internal/test/strict-server/iris/server.gen.go
+++ b/internal/test/strict-server/iris/server.gen.go
@@ -5,10 +5,10 @@ package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
- "encoding/json"
+ "errors"
"fmt"
"io"
"mime"
@@ -21,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.
@@ -39,6 +38,15 @@ type ServerInterface interface {
// (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)
@@ -99,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.BindStyledParameterWithOptions("simple", "type", ctx.Params().Get("type"), &pType, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: false, Required: true})
+ 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)
@@ -157,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
@@ -172,7 +203,7 @@ func (w *ServerInterfaceWrapper) HeadersExample(ctx iris.Context) {
return
}
- err = runtime.BindStyledParameterWithOptions("simple", "header1", valueList[0], &Header1, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true})
+ 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)
@@ -195,7 +226,7 @@ func (w *ServerInterfaceWrapper) HeadersExample(ctx iris.Context) {
return
}
- err = runtime.BindStyledParameterWithOptions("simple", "header2", valueList[0], &Header2, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false})
+ 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)
@@ -238,6 +269,9 @@ func RegisterHandlersWithOptions(router *iris.Application, si ServerInterface, o
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)
@@ -448,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"`
}
@@ -687,8 +815,10 @@ type HeadersExampleResponseObject interface {
}
type HeadersExample200ResponseHeaders struct {
- Header1 string
- Header2 int
+ Header1 string
+ Header2 int
+ NullableHeader *string
+ OptionalHeader *string
}
type HeadersExample200JSONResponse struct {
@@ -699,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)
@@ -749,9 +885,7 @@ func (response UnionExample200ApplicationAlternativePlusJSONResponse) VisitUnion
}
type UnionExample200JSONResponse struct {
- Body struct {
- union json.RawMessage
- }
+ Body UnionExample200JSONResponseBody
Headers UnionExample200ResponseHeaders
}
@@ -795,6 +929,15 @@ type StrictServerInterface interface {
// (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)
@@ -820,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}
@@ -838,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))
@@ -945,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 {
@@ -979,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) {
@@ -1006,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
@@ -1041,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))
@@ -1078,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))
@@ -1210,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))
@@ -1244,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))
@@ -1272,44 +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/+xYS3PbNhD+Kxi0p5QUZccn3hpPJm3T1h3ZPnV8gIilhIQE0MVStEaj/94BQb0sWpUS",
- "PTqZ3PhY7C6+b3ex2BnPTGmNBk2OpzOO4KzRDpqXoZAI/1TgyL9JcBkqS8ponvJ3Qg7af/OII1RODAtY",
- "LPfymdEEulkqrC1UJvzS5JPz62fcZWMohX/6ESHnKf8hWbmShL8ugWdR2gL4fD6PXnhw95FHfAxCAjbe",
- "hserTd00tcBT7giVHnGvJIhdd4opTTAC9Na8aOuEF1j4kc64RWMBSQWMJqKooNtS+8UMP0FGYQdK52Yb",
- "y1ujSSjtmFR5DgiaWAse8zocc5W1BgkkG06Zt5ARc4ATQB5xUuQd4/fr31nrsOMRnwC6YOiq1+/1PV/G",
- "ghZW8ZS/bT5F3AoaNxtaEmRNF++/3d/9yZRjoiJTClKZKIopKwW6sShAMqXJeBerjFyPN5awIf5X2a5+",
- "30Lpo6YJoHdGTk8RME1croXzdb9/pricR/wmGOvSsXQqWUuwRk0uqqID80f9WZtaM0A02O4sKauClBVI",
- "61xtov3HQmQfyJf6ktxgGUtB4kSoH8vSpYGPEQpBIPcgYBAkD+NhTf1JWfgaOxfloK3HnXXqfmxqx8am",
- "ZmSYBFGwWtGYLRa+KLBKM8Gc0qMC2MKpqJPMAtpj72ctB+1eHryOk9ezaEPLc1zXddwkUIUF6MzIL6Mw",
- "4qoUI0isHm0u97oF8ZQPp+RDdvuAO1IiR5zgmRJbCKV3n95nKunfkT5aYod0RWi6EhmPTPwZprVBGVuB",
- "ogQCdMnMW597xSPoSOW/lpIsE5oNgWlRgmQiJ0D2wbBWpdtK2UFr94P5GERWqpqWZ/mS/j3jHpKmDeIR",
- "9wZ4GlAJea3Qk05YQbQDtqf/jM+vImCBZmi24w1T3WVwUaKW0CHkzpfELuY68AuWBmsSl2nadkfc1vXj",
- "HGeQZ/L1o/8Bnvdqu45Y+s6d24cCVoWPr2PWrtoHti+spHugOFESTFLamwM1XwxUZyFTuQIZt7uIg2+v",
- "lYRbozME2myB/JVOG2JLZf6mSWNgAYGIOcNqYGXliFnhHFPUVJFChduqhK3i8bjy7DZYeliV012svjkR",
- "p28uxehN/+rwJW9PHDcbrcwr+Tj4/X2QOfTOfrSe6cCO73h2L5TO/pISrw21ulP4lyCwOtMzUBPfEWnJ",
- "EKhCDZJNlFgMYrZys1WworWrFwpurLqhxYDtkIYo2qnrmke7hnBP3/CI6JSjy3PFaaXVrlHho//N2h76",
- "5dmgjP6fDgJFQYBakJrAT8e5QW5rMRru8ibTXrAc7Wnh6duLqnnEw+w6lKAKC18niGyaJGHm3XO1GI0A",
- "e8okwiqPwr8BAAD//4h9qqfAGAAA",
-}
-
-// 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
@@ -1317,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) {
@@ -1335,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()
@@ -1366,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 c0ab4c7700..12b000d733 100644
--- a/internal/test/strict-server/iris/server.go
+++ b/internal/test/strict-server/iris/server.go
@@ -121,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.gen.go b/internal/test/strict-server/iris/types.gen.go
index 6682c1acab..08ae8548e1 100644
--- a/internal/test/strict-server/iris/types.gen.go
+++ b/internal/test/strict-server/iris/types.gen.go
@@ -3,6 +3,12 @@
// 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,6 +32,14 @@ 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
@@ -44,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
@@ -58,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/Makefile b/internal/test/strict-server/stdhttp/Makefile
deleted file mode 100644
index dac22331f7..0000000000
--- a/internal/test/strict-server/stdhttp/Makefile
+++ /dev/null
@@ -1,36 +0,0 @@
-SHELL:=/bin/bash
-
-YELLOW := \e[0;33m
-RESET := \e[0;0m
-
-GOVER := $(shell go env GOVERSION)
-GOMINOR := $(shell bash -c "cut -f2 -d. <<< $(GOVER)")
-
-define execute-if-go-122
-@{ \
-if [[ 22 -le $(GOMINOR) ]]; then \
- $1; \
-else \
- echo -e "$(YELLOW)Skipping task as you're running Go v1.$(GOMINOR).x which is < Go 1.22, which this module requires$(RESET)"; \
-fi \
-}
-endef
-
-lint:
- $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./...)
-
-lint-ci:
-
- $(call execute-if-go-122,$(GOBIN)/golangci-lint run ./... --out-format=github-actions --timeout=5m)
-
-generate:
- $(call execute-if-go-122,go generate ./...)
-
-test:
- $(call execute-if-go-122,go test -cover ./...)
-
-tidy:
- $(call execute-if-go-122,go mod tidy)
-
-tidy-ci:
- $(call execute-if-go-122,tidied -verbose)
diff --git a/internal/test/strict-server/stdhttp/go.mod b/internal/test/strict-server/stdhttp/go.mod
deleted file mode 100644
index 2e90c73f62..0000000000
--- a/internal/test/strict-server/stdhttp/go.mod
+++ /dev/null
@@ -1,35 +0,0 @@
-module github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/stdhttp
-
-go 1.22
-
-replace github.com/oapi-codegen/oapi-codegen/v2 => ../../../../
-
-replace github.com/oapi-codegen/oapi-codegen/v2/internal/test => ../..
-
-require (
- github.com/getkin/kin-openapi v0.126.0
- github.com/oapi-codegen/oapi-codegen/v2 v2.0.0-00010101000000-000000000000
- github.com/oapi-codegen/oapi-codegen/v2/internal/test v0.0.0-00010101000000-000000000000
- github.com/oapi-codegen/runtime v1.1.0
- github.com/oapi-codegen/testutil v1.1.0
- github.com/stretchr/testify v1.9.0
-)
-
-require (
- github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/go-openapi/jsonpointer v0.21.0 // indirect
- github.com/go-openapi/swag v0.23.0 // indirect
- github.com/google/uuid v1.4.0 // indirect
- github.com/invopop/yaml v0.3.1 // indirect
- github.com/josharian/intern v1.0.0 // indirect
- github.com/mailru/easyjson v0.7.7 // indirect
- github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
- github.com/perimeterx/marshmallow v1.1.5 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- golang.org/x/mod v0.17.0 // indirect
- golang.org/x/text v0.15.0 // indirect
- golang.org/x/tools v0.21.0 // indirect
- gopkg.in/yaml.v2 v2.4.0 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
-)
diff --git a/internal/test/strict-server/stdhttp/go.sum b/internal/test/strict-server/stdhttp/go.sum
deleted file mode 100644
index b1563e235e..0000000000
--- a/internal/test/strict-server/stdhttp/go.sum
+++ /dev/null
@@ -1,62 +0,0 @@
-github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
-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/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
-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/getkin/kin-openapi v0.126.0 h1:c2cSgLnAsS0xYfKsgt5oBV6MYRM/giU8/RtwUY4wyfY=
-github.com/getkin/kin-openapi v0.126.0/go.mod h1:7mONz8IwmSRg6RttPu6v8U/OJ+gr+J99qSFNjPGSQqw=
-github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
-github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
-github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
-github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
-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/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
-github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/invopop/yaml v0.3.1 h1:f0+ZpmhfBSS4MhG+4HYseMdJhoeeopbSKbq5Rpeelso=
-github.com/invopop/yaml v0.3.1/go.mod h1:PMOp3nn4/12yEZUFfmOuNHJsZToEEOwoWsT+D81KkeA=
-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/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
-github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
-github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
-github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
-github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
-github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
-github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-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/oapi-codegen/runtime v1.1.0 h1:rJpoNUawn5XTvekgfkvSZr0RqEnoYpFkyvrzfWeFKWM=
-github.com/oapi-codegen/runtime v1.1.0/go.mod h1:BeSfBkWWWnAnGdyS+S/GnlbmHKzf8/hwkvelJZDeKA8=
-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/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/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
-github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
-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/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-github.com/ugorji/go/codec v1.2.11 h1:BMaWp1Bb6fHwEtbplGBGJ498wD+LKlNSl25MjdZY4dU=
-github.com/ugorji/go/codec v1.2.11/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
-golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
-golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
-golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
-golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
-golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
-golang.org/x/tools v0.21.0 h1:qc0xYgIbsSDt9EyWz05J5wfa7LOVW0YTLOXrqdLAWIw=
-golang.org/x/tools v0.21.0/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/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/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.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/internal/test/strict-server/stdhttp/server.gen.go b/internal/test/strict-server/stdhttp/server.gen.go
index 6a3b2537a9..f3073a462b 100644
--- a/internal/test/strict-server/stdhttp/server.gen.go
+++ b/internal/test/strict-server/stdhttp/server.gen.go
@@ -7,10 +7,11 @@ package api
import (
"bytes"
- "compress/gzip"
+ "compress/flate"
"context"
"encoding/base64"
"encoding/json"
+ "errors"
"fmt"
"io"
"mime"
@@ -22,7 +23,6 @@ import (
"github.com/getkin/kin-openapi/openapi3"
"github.com/oapi-codegen/runtime"
- strictnethttp "github.com/oapi-codegen/runtime/strictmiddleware/nethttp"
)
// ServerInterface represents all server handlers.
@@ -40,6 +40,15 @@ type ServerInterface interface {
// (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)
@@ -130,15 +139,58 @@ func (siw *ServerInterfaceWrapper) MultipleRequestAndResponseTypes(w http.Respon
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})
+ 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
@@ -229,6 +281,7 @@ func (siw *ServerInterfaceWrapper) URLEncodedExample(w http.ResponseWriter, r *h
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
@@ -244,7 +297,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http
return
}
- err = runtime.BindStyledParameterWithOptions("simple", "header1", valueList[0], &Header1, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: true})
+ 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
@@ -267,7 +320,7 @@ func (siw *ServerInterfaceWrapper) HeadersExample(w http.ResponseWriter, r *http
return
}
- err = runtime.BindStyledParameterWithOptions("simple", "header2", valueList[0], &Header2, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: false, Required: false})
+ 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
@@ -376,21 +429,27 @@ 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 *http.ServeMux
+ 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 *http.ServeMux) http.Handler {
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
return HandlerWithOptions(si, StdHTTPServerOptions{
BaseRouter: m,
})
}
-func HandlerFromMuxWithBaseURL(si ServerInterface, m *http.ServeMux, baseURL string) http.Handler {
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
return HandlerWithOptions(si, StdHTTPServerOptions{
BaseURL: baseURL,
BaseRouter: m,
@@ -416,18 +475,21 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
- m.HandleFunc("POST "+options.BaseURL+"/json", wrapper.JSONExample)
- m.HandleFunc("POST "+options.BaseURL+"/multipart", wrapper.MultipartExample)
- m.HandleFunc("POST "+options.BaseURL+"/multipart-related", wrapper.MultipartRelatedExample)
- m.HandleFunc("POST "+options.BaseURL+"/multiple", wrapper.MultipleRequestAndResponseTypes)
- m.HandleFunc("GET "+options.BaseURL+"/reserved-go-keyword-parameters/{type}", wrapper.ReservedGoKeywordParameters)
- m.HandleFunc("POST "+options.BaseURL+"/reusable-responses", wrapper.ReusableResponses)
- m.HandleFunc("POST "+options.BaseURL+"/text", wrapper.TextExample)
- m.HandleFunc("POST "+options.BaseURL+"/unknown", wrapper.UnknownExample)
- m.HandleFunc("POST "+options.BaseURL+"/unspecified-content-type", wrapper.UnspecifiedContentType)
- m.HandleFunc("POST "+options.BaseURL+"/urlencoded", wrapper.URLEncodedExample)
- m.HandleFunc("POST "+options.BaseURL+"/with-headers", wrapper.HeadersExample)
- m.HandleFunc("POST "+options.BaseURL+"/with-union", wrapper.UnionExample)
+ 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
}
@@ -456,10 +518,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 +557,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)
@@ -525,6 +593,7 @@ type MultipartRelatedExample200MultipartResponse func(writer *multipart.Writer)
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)
@@ -563,24 +632,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 {
@@ -589,6 +663,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))
@@ -606,6 +681,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)
@@ -616,6 +692,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)
@@ -630,6 +707,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"`
}
@@ -641,6 +818,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)
@@ -659,12 +837,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
@@ -694,6 +877,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)
@@ -731,6 +915,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))
@@ -776,6 +961,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))
@@ -832,15 +1018,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
@@ -869,8 +1055,10 @@ type HeadersExampleResponseObject interface {
}
type HeadersExample200ResponseHeaders struct {
- Header1 string
- Header2 int
+ Header1 string
+ Header2 int
+ NullableHeader *string
+ OptionalHeader *string
}
type HeadersExample200JSONResponse struct {
@@ -879,12 +1067,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
@@ -922,28 +1121,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
@@ -977,6 +1184,15 @@ type StrictServerInterface interface {
// (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)
@@ -1002,8 +1218,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)
@@ -1037,10 +1253,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))
@@ -1135,10 +1354,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 {
@@ -1169,8 +1391,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) {
@@ -1193,6 +1417,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
@@ -1225,10 +1536,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))
@@ -1259,8 +1573,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))
@@ -1379,10 +1695,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))
@@ -1410,10 +1729,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))
@@ -1435,44 +1757,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/+xYS3PbNhD+Kxi0p5QUZccn3hpPJm3T1h3ZPnV8gIilhIQE0MVStEaj/94BQb0sWpUS",
- "PTqZ3PhY7C6+b3ex2BnPTGmNBk2OpzOO4KzRDpqXoZAI/1TgyL9JcBkqS8ponvJ3Qg7af/OII1RODAtY",
- "LPfymdEEulkqrC1UJvzS5JPz62fcZWMohX/6ESHnKf8hWbmShL8ugWdR2gL4fD6PXnhw95FHfAxCAjbe",
- "hserTd00tcBT7giVHnGvJIhdd4opTTAC9Na8aOuEF1j4kc64RWMBSQWMJqKooNtS+8UMP0FGYQdK52Yb",
- "y1ujSSjtmFR5DgiaWAse8zocc5W1BgkkG06Zt5ARc4ATQB5xUuQd4/fr31nrsOMRnwC6YOiq1+/1PV/G",
- "ghZW8ZS/bT5F3AoaNxtaEmRNF++/3d/9yZRjoiJTClKZKIopKwW6sShAMqXJeBerjFyPN5awIf5X2a5+",
- "30Lpo6YJoHdGTk8RME1croXzdb9/pricR/wmGOvSsXQqWUuwRk0uqqID80f9WZtaM0A02O4sKauClBVI",
- "61xtov3HQmQfyJf6ktxgGUtB4kSoH8vSpYGPEQpBIPcgYBAkD+NhTf1JWfgaOxfloK3HnXXqfmxqx8am",
- "ZmSYBFGwWtGYLRa+KLBKM8Gc0qMC2MKpqJPMAtpj72ctB+1eHryOk9ezaEPLc1zXddwkUIUF6MzIL6Mw",
- "4qoUI0isHm0u97oF8ZQPp+RDdvuAO1IiR5zgmRJbCKV3n95nKunfkT5aYod0RWi6EhmPTPwZprVBGVuB",
- "ogQCdMnMW597xSPoSOW/lpIsE5oNgWlRgmQiJ0D2wbBWpdtK2UFr94P5GERWqpqWZ/mS/j3jHpKmDeIR",
- "9wZ4GlAJea3Qk05YQbQDtqf/jM+vImCBZmi24w1T3WVwUaKW0CHkzpfELuY68AuWBmsSl2nadkfc1vXj",
- "HGeQZ/L1o/8Bnvdqu45Y+s6d24cCVoWPr2PWrtoHti+spHugOFESTFLamwM1XwxUZyFTuQIZt7uIg2+v",
- "lYRbozME2myB/JVOG2JLZf6mSWNgAYGIOcNqYGXliFnhHFPUVJFChduqhK3i8bjy7DZYeliV012svjkR",
- "p28uxehN/+rwJW9PHDcbrcwr+Tj4/X2QOfTOfrSe6cCO73h2L5TO/pISrw21ulP4lyCwOtMzUBPfEWnJ",
- "EKhCDZJNlFgMYrZys1WworWrFwpurLqhxYDtkIYo2qnrmke7hnBP3/CI6JSjy3PFaaXVrlHho//N2h76",
- "5dmgjP6fDgJFQYBakJrAT8e5QW5rMRru8ibTXrAc7Wnh6duLqnnEw+w6lKAKC18niGyaJGHm3XO1GI0A",
- "e8okwiqPwr8BAAD//4h9qqfAGAAA",
-}
-
-// 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
@@ -1480,7 +1807,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) {
@@ -1498,12 +1825,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()
@@ -1529,3 +1856,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/stdhttp/server.go b/internal/test/strict-server/stdhttp/server.go
index a142a6b813..3d24a5d272 100644
--- a/internal/test/strict-server/stdhttp/server.go
+++ b/internal/test/strict-server/stdhttp/server.go
@@ -124,10 +124,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/stdhttp/std_strict_test.go b/internal/test/strict-server/stdhttp/std_strict_test.go
index 40d362a54a..4c1e76e9ac 100644
--- a/internal/test/strict-server/stdhttp/std_strict_test.go
+++ b/internal/test/strict-server/stdhttp/std_strict_test.go
@@ -196,6 +196,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/internal/test/strict-server/stdhttp/types.gen.go b/internal/test/strict-server/stdhttp/types.gen.go
index 6682c1acab..08ae8548e1 100644
--- a/internal/test/strict-server/stdhttp/types.gen.go
+++ b/internal/test/strict-server/stdhttp/types.gen.go
@@ -3,6 +3,12 @@
// 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,6 +32,14 @@ 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
@@ -44,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
@@ -58,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/strict-schema.yaml b/internal/test/strict-server/strict-schema.yaml
index a0b6a6e054..fd5f07feda 100644
--- a/internal/test/strict-server/strict-schema.yaml
+++ b/internal/test/strict-server/strict-schema.yaml
@@ -192,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:
@@ -205,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
@@ -247,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
@@ -278,9 +346,11 @@ paths:
description: OK
headers:
header1:
+ required: true
schema:
type: string
header2:
+ required: true
schema:
type: integer
content:
@@ -304,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 0ae094df02..49a6abe25a 100644
--- a/internal/test/strict-server/strict_test.go
+++ b/internal/test/strict-server/strict_test.go
@@ -13,8 +13,6 @@ 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"
@@ -22,7 +20,6 @@ import (
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"
- fiberAPI "github.com/oapi-codegen/oapi-codegen/v2/internal/test/strict-server/fiber"
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"
@@ -63,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"
@@ -239,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/codegen/codegen.go b/pkg/codegen/codegen.go
index 7163998d19..22317bda16 100644
--- a/pkg/codegen/codegen.go
+++ b/pkg/codegen/codegen.go
@@ -19,12 +19,17 @@ import (
"bytes"
"context"
"embed"
+ "errors"
"fmt"
+ "go/scanner"
"io"
"io/fs"
+ "maps"
"net/http"
"os"
+ "regexp"
"runtime/debug"
+ "slices"
"sort"
"strings"
"text/template"
@@ -47,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
@@ -66,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
@@ -77,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
}
@@ -108,6 +151,11 @@ 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)
@@ -131,12 +179,48 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
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)
}
@@ -156,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)
}
@@ -182,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
@@ -201,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)
@@ -245,7 +366,7 @@ func Generate(spec *openapi3.T, opts Configuration) (string, error) {
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)
}
@@ -309,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)
@@ -340,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 {
@@ -405,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
}
@@ -435,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)
@@ -451,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)
}
@@ -461,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)
}
@@ -494,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...)
@@ -531,6 +689,10 @@ 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,
@@ -559,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,
@@ -606,7 +772,22 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response
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)
}
@@ -616,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,
@@ -636,6 +821,7 @@ func GenerateTypesForResponses(t *template.Template, responses openapi3.Response
}
types = append(types, typeDef)
+ types = append(types, goType.AdditionalTypes...)
}
}
return types, nil
@@ -652,7 +838,8 @@ func GenerateTypesForRequestBodies(t *template.Template, bodies map[string]*open
// 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
}
@@ -667,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,
@@ -682,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
}
@@ -696,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)
}
@@ -720,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{}
@@ -743,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,
})
}
}
@@ -793,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.
@@ -822,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)
@@ -863,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)
}
@@ -884,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)
}
@@ -947,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)
@@ -994,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
}
@@ -1014,7 +1302,7 @@ func OperationImports(ops []OperationDefinition) (map[string]goImport, error) {
if err != nil {
return nil, err
}
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
}
}
@@ -1023,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 {
@@ -1032,7 +1320,7 @@ func OperationImports(ops []OperationDefinition) (map[string]goImport, error) {
if err != nil {
return nil, err
}
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
}
}
@@ -1067,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
}
@@ -1075,15 +1363,18 @@ 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
@@ -1094,14 +1385,14 @@ func GoSchemaImports(schemas ...*openapi3.SchemaRef) (map[string]goImport, error
if err != nil {
return nil, err
}
- MergeImports(res, imprts)
+ maps.Copy(res, imprts)
}
} 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
@@ -1122,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
}
@@ -1140,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
@@ -1159,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
@@ -1175,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 1d752601b3..037c9e1886 100644
--- a/pkg/codegen/codegen_test.go
+++ b/pkg/codegen/codegen_test.go
@@ -13,7 +13,7 @@ import (
)
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/oapi-codegen/oapi-codegen/v2/examples/petstore-expanded`
)
@@ -77,7 +77,14 @@ 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")
@@ -110,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\"`")
@@ -166,6 +173,41 @@ func TestGoTypeImport(t *testing.T) {
}
}
+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) {
if testing.Short() {
t.Skip("Skipping test that interacts with the network")
@@ -227,5 +269,65 @@ 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)
+
+ // 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
var testOpenAPIDefinition string
diff --git a/pkg/codegen/configuration.go b/pkg/codegen/configuration.go
index b9d8bad1d9..dbcb0a6874 100644
--- a/pkg/codegen/configuration.go
+++ b/pkg/codegen/configuration.go
@@ -4,8 +4,18 @@ 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"`
@@ -50,6 +60,9 @@ func (o Configuration) Validate() error {
if o.Generate.EchoServer {
nServers++
}
+ if o.Generate.Echo5Server {
+ nServers++
+ }
if o.Generate.GorillaServer {
nServers++
}
@@ -112,6 +125,8 @@ type GenerateOptions struct {
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
@@ -126,12 +141,70 @@ type GenerateOptions struct {
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
// code generator.
type CompatibilityOptions struct {
@@ -140,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
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.
@@ -167,12 +253,12 @@ 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
@@ -195,6 +281,24 @@ type CompatibilityOptions struct {
//
// 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 {
@@ -207,6 +311,12 @@ type OutputOptions struct {
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.
@@ -224,8 +334,15 @@ type OutputOptions struct {
ResponseTypeSuffix string `yaml:"response-type-suffix,omitempty"`
// Override the default generated client type with the value
ClientTypeName string `yaml:"client-type-name,omitempty"`
- // Whether to use the initialism overrides
- InitialismOverrides bool `yaml:"initialism-overrides,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"`
@@ -234,10 +351,90 @@ type OutputOptions struct {
// "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"`
}
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",
+ }
+ }
+
+ if _, err := compileStreamingContentTypes(oo.StreamingContentTypes); err != nil {
+ return map[string]string{
+ "streaming-content-types": err.Error(),
+ }
+ }
+
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 f5ef5ef4d2..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,10 +17,14 @@ 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"
@@ -28,7 +35,7 @@ const (
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)
@@ -36,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)
@@ -48,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)
@@ -60,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)
}
@@ -76,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)
@@ -84,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)
}
@@ -100,11 +115,11 @@ 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 interface{}) (bool, error) {
+func extParseOapiCodegenOnlyHonourGoName(extPropValue any) (bool, error) {
onlyHonourGoName, ok := extPropValue.(bool)
if !ok {
return false, fmt.Errorf("failed to convert type: %T", extPropValue)
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
index a48b3d4e1e..829885a5b3 100644
--- a/pkg/codegen/externalref.go
+++ b/pkg/codegen/externalref.go
@@ -58,6 +58,20 @@ func ensureExternalRefsInParameterDefinitions(defs *[]ParameterDefinition, ref s
}
}
+// 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
@@ -68,13 +82,26 @@ func ensureExternalRefsInSchema(schema *Schema, ref string) {
return
}
- // if this is already defined as the start of a struct, we shouldn't inject **??**
- if strings.HasPrefix(schema.GoType, "struct {") {
+ parts := strings.SplitN(ref, "#", 2)
+ pack, ok := globalState.importMapping[parts[0]]
+ if !ok {
return
}
- parts := strings.SplitN(ref, "#", 2)
- if pack, ok := globalState.importMapping[parts[0]]; ok {
+ // 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/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 d2ab35bb7d..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,17 +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
- result.Extensions = make(map[string]interface{})
- for k, v := range s1.Extensions {
- result.Extensions[k] = v
- }
- 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...)
@@ -103,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")
}
@@ -111,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")
}
@@ -195,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()
@@ -227,6 +385,17 @@ 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
}
@@ -238,7 +407,7 @@ func equalTypes(t1 *openapi3.Types, t2 *openapi3.Types) bool {
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/deepmap/oapi-codegen/issues/1634)
+ // 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
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 da903810db..736a8ea1b5 100644
--- a/pkg/codegen/operations.go
+++ b/pkg/codegen/operations.go
@@ -16,8 +16,10 @@ package codegen
import (
"bufio"
"bytes"
+ "cmp"
"fmt"
- "sort"
+ "maps"
+ "slices"
"strconv"
"strings"
"text/template"
@@ -44,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 {
@@ -114,6 +171,34 @@ 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 := LowercaseFirstCharacters(pd.GoName())
if IsGoKeyword(name) {
@@ -135,10 +220,17 @@ func (pd ParameterDefinition) GoName() string {
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 {
@@ -154,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
@@ -172,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".
@@ -206,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
@@ -223,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
@@ -285,10 +430,10 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini
// 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++
}
}
@@ -297,50 +442,84 @@ func (o *OperationDefinition) GetResponseTypeDefinitions() ([]ResponseTypeDefini
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):
+ case slices.Contains(contentTypesHalJSON, contentTypeName):
typeName = fmt.Sprintf("HALJSON%s", nameNormalizer(responseName))
- case "application/json" == contentTypeName:
+ tag = "HALJSON"
+ case contentTypeName == "application/json":
// if it's the standard application/json
typeName = fmt.Sprintf("JSON%s", nameNormalizer(responseName))
+ tag = "JSON"
// Vendored JSON
- case StringInArray(contentTypeName, contentTypesJSON) || util.IsMediaTypeJson(contentTypeName):
+ 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):
+ case slices.Contains(contentTypesYAML, contentTypeName):
typeName = fmt.Sprintf("YAML%s", nameNormalizer(responseName))
+ tag = "YAML"
// XML:
- case StringInArray(contentTypeName, contentTypesXML):
+ 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
}
@@ -352,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
@@ -511,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
@@ -530,20 +753,27 @@ 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{}{}
+ }
+ }
+
+ // 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
@@ -557,25 +787,56 @@ 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 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 = nameNormalizer(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)
@@ -598,14 +859,14 @@ 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)
}
ensureExternalRefsInRequestBodyDefinitions(&bodyDefinitions, pathItem.Ref)
- responseDefinitions, err := GenerateResponseDefinitions(op.OperationID, op.Responses.Map())
+ responseDefinitions, err := GenerateResponseDefinitions(operationId, op.Responses.Map(), pathItem.Ref)
if err != nil {
return nil, fmt.Errorf("error generating response definitions: %w", err)
}
@@ -613,11 +874,12 @@ func OperationDefinitions(swagger *openapi3.T, initialismOverrides bool) ([]Oper
ensureExternalRefsInResponseDefinitions(&responseDefinitions, pathItem.Ref)
opDef := OperationDefinition{
- PathParams: pathParams,
- HeaderParams: FilterParameterDefinitionByType(allParams, "header"),
- QueryParams: FilterParameterDefinitionByType(allParams, "query"),
- CookieParams: FilterParameterDefinitionByType(allParams, "cookie"),
- OperationId: nameNormalizer(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,
@@ -626,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.
@@ -641,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
@@ -655,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 nameNormalizer(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
}
@@ -732,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{
@@ -761,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
@@ -770,13 +1048,15 @@ 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 map[string]*openapi3.ResponseRef) ([]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{})
@@ -813,11 +1093,44 @@ func GenerateResponseDefinitions(operationID string, responses map[string]*opena
}
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,
@@ -834,7 +1147,14 @@ func GenerateResponseDefinitions(operationID string, responses map[string]*opena
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)
}
@@ -859,6 +1179,12 @@ func GenerateResponseDefinitions(operationID string, responses map[string]*opena
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)
}
@@ -881,6 +1207,12 @@ func GenerateTypeDefsForOperation(op OperationDefinition) []TypeDefinition {
for _, body := range op.Bodies {
typeDefs = append(typeDefs, body.Schema.AdditionalTypes...)
}
+
+ for _, resp := range op.Responses {
+ for _, content := range resp.Contents {
+ typeDefs = append(typeDefs, content.Schema.AdditionalTypes...)
+ }
+ }
return typeDefs
}
@@ -907,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{
@@ -941,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)
}
@@ -991,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) {
@@ -1028,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)
}
@@ -1049,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 0d3a889747..efdac65f0b 100644
--- a/pkg/codegen/prune.go
+++ b/pkg/codegen/prune.go
@@ -2,23 +2,15 @@ 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 {
@@ -402,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)
}
@@ -410,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)
}
@@ -421,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)
// }
@@ -429,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)
}
@@ -437,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)
}
@@ -445,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)
}
@@ -453,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)
}
@@ -461,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)
}
@@ -469,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/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 3d4bdbbddb..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"
@@ -41,6 +43,17 @@ type Schema struct {
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 != ""
}
@@ -52,6 +65,32 @@ func (s Schema) IsExternalRef() bool {
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
@@ -88,7 +127,7 @@ type Property struct {
ReadOnly bool
WriteOnly bool
NeedsFormTag bool
- Extensions map[string]interface{}
+ Extensions map[string]any
Deprecated bool
}
@@ -128,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
@@ -165,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.
@@ -188,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
@@ -199,6 +278,8 @@ type ResponseTypeDefinition struct {
// The type name of a response model.
ResponseName string
+
+ AdditionalTypeDefinitions []TypeDefinition
}
func (t *TypeDefinition) IsAlias() bool {
@@ -231,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 {
@@ -251,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)
@@ -300,14 +398,63 @@ 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
@@ -323,10 +470,13 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
// 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
@@ -383,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
}
@@ -395,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,
@@ -417,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,
@@ -425,7 +577,7 @@ 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)
@@ -451,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)
@@ -487,7 +639,7 @@ func GenerateGoSchema(sref *openapi3.SchemaRef, path []string) (Schema, error) {
enumNames := enumValues
for _, key := range []string{extEnumVarNames, extEnumNames} {
- if extension, ok := schema.Extensions[key]; ok {
+ if extension, ok := extensions[key]; ok {
if extEnumNames, err := extParseEnumVarNames(extension); err == nil {
enumNames = extEnumNames
break
@@ -513,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)
@@ -554,6 +706,7 @@ func oapiSchemaToGoType(schema *openapi3.Schema, path []string, outSchema *Schem
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
@@ -570,78 +723,47 @@ 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
- if sliceContains(globalState.options.OutputOptions.DisableTypeAliasesForType, "array") {
+ if slices.Contains(globalState.options.OutputOptions.DisableTypeAliasesForType, "array") {
outSchema.DefineViaAlias = false
}
+ setSkipOptionalPointerForContainerType(outSchema)
} else if t.Is("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"
- }
+ spec := globalState.typeMapping.Integer.Resolve(f)
+ outSchema.GoType = spec.Type
outSchema.DefineViaAlias = true
} else if t.Is("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)
- }
+ spec := globalState.typeMapping.Number.Resolve(f)
+ outSchema.GoType = spec.Type
outSchema.DefineViaAlias = true
} else if t.Is("boolean") {
- if f != "" {
- return fmt.Errorf("invalid format (%s) for boolean", f)
- }
- outSchema.GoType = "bool"
+ spec := globalState.typeMapping.Boolean.Resolve(f)
+ outSchema.GoType = spec.Type
outSchema.DefineViaAlias = true
} else if t.Is("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"
+ 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
} else {
@@ -665,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 {
@@ -688,8 +817,8 @@ func GenFieldsFromProperties(props []Property) []string {
// This comment has to be on its own line for godoc & IDEs to pick up
var deprecationReason string
if extension, ok := p.Extensions[extDeprecationReason]; ok {
- if extOmitEmpty, err := extParseDeprecationReason(extension); err == nil {
- deprecationReason = extOmitEmpty
+ if extDeprecationReason, err := extParseDeprecationReason(extension); err == nil {
+ deprecationReason = extDeprecationReason
}
}
@@ -709,31 +838,39 @@ func GenFieldsFromProperties(props []Property) []string {
shouldOmitEmpty := (!p.Required || p.ReadOnly || p.WriteOnly) &&
(!p.Required || !p.ReadOnly || !globalState.options.Compatibility.DisableRequiredReadOnlyAsPointer)
- omitEmpty := !p.Nullable && shouldOmitEmpty
+ omitEmpty := shouldOmitEmpty
- if p.Nullable && globalState.options.OutputOptions.NullableType {
- omitEmpty = shouldOmitEmpty
+ omitZero := false
+
+ // default, but allow turning of
+ if shouldOmitEmpty && p.Schema.SkipOptionalPointer && globalState.options.OutputOptions.PreferSkipOptionalPointerWithOmitzero {
+ omitZero = true
}
- // Support x-omitempty
+ // 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
@@ -867,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.
@@ -881,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
index c4b3f8bd7b..77c1a8751a 100644
--- a/pkg/codegen/schema_test.go
+++ b/pkg/codegen/schema_test.go
@@ -3,7 +3,9 @@ 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) {
@@ -454,3 +456,74 @@ func TestProperty_GoTypeDef_nullable(t *testing.T) {
})
}
}
+
+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 62ea244c8b..a72d2911ce 100644
--- a/pkg/codegen/template_helpers.go
+++ b/pkg/codegen/template_helpers.go
@@ -17,12 +17,15 @@ import (
"bytes"
"fmt"
"os"
+ "slices"
"strings"
"text/template"
"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"
)
@@ -44,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
@@ -146,7 +171,7 @@ func genResponseUnmarshal(op *OperationDefinition) string {
SortedMapKeys := SortedMapKeys(responseRef.Value.Content)
jsonCount := 0
for _, contentTypeName := range SortedMapKeys {
- if StringInArray(contentTypeName, contentTypesJSON) || util.IsMediaTypeJson(contentTypeName) {
+ if slices.Contains(contentTypesJSON, contentTypeName) || util.IsMediaTypeJson(contentTypeName) {
jsonCount++
}
}
@@ -163,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"+
@@ -183,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"+
@@ -197,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"+
@@ -225,7 +250,7 @@ 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 SortedMapKeys(handledCaseClauses) {
@@ -245,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)
}
@@ -290,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{
@@ -322,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 ced82b4c42..08402e2aca 100644
--- a/pkg/codegen/templates/chi/chi-middleware.tmpl
+++ b/pkg/codegen/templates/chi/chi-middleware.tmpl
@@ -8,11 +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) {
{{if or .RequiresParamObject (gt (len .PathParams) 0) }}
var err error
+ _ = err
{{end}}
{{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" -------------
@@ -29,7 +30,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
}
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", chi.URLParam(r, "{{.ParamName}}"), &{{$varName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: {{.Explode}}, Required: {{.Required}}})
+ 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
@@ -54,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}}
@@ -69,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}}"})
@@ -77,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}}
@@ -98,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}}
@@ -110,14 +116,14 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", valueList[0], &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}})
+ 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")
@@ -129,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}}
@@ -153,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.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie.Value, &value, runtime.BindStyledParameterOptions{Explode: {{.Explode}}, Required: {{.Required}}})
+ 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}}
}
@@ -173,6 +180,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
return
}
{{- end}}
+ }
{{end}}
{{end}}
@@ -192,7 +200,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
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 1603c3d5c8..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.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", ctx.Param("{{.ParamName}}"), &{{$varName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: {{.Explode}}, Required: {{.Required}}})
+ 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.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", valueList[0], &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}})
+ 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.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: {{.Explode}}, Required: {{.Required}}})
+ 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 7745e0d88e..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,6 +14,7 @@ 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 {
@@ -20,6 +22,6 @@ for _, m := range options.Middlewares {
}
{{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 0904c7894d..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.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", c.Params("{{.ParamName}}"), &{{$varName}}, runtime.BindStyledParameterOptions{Explode: {{.Explode}}, Required: {{.Required}}})
+ 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.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", value, &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}})
+ 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.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie, &value, runtime.BindStyledParameterOptions{Explode: {{.Explode}}, Required: {{.Required}}})
+ 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 8f1a6b229f..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.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", c.Param("{{.ParamName}}"), &{{$varName}}, runtime.BindStyledParameterOptions{Explode: {{.Explode}}, Required: {{.Required}}})
+ 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.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", valueList[0], &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}})
+ 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.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie, &value, runtime.BindStyledParameterOptions{Explode: {{.Explode}}, Required: {{.Required}}})
+ 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 4353c9f42f..c971395fb8 100644
--- a/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
+++ b/pkg/codegen/templates/gorilla/gorilla-middleware.tmpl
@@ -8,11 +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) {
{{if or .RequiresParamObject (gt (len .PathParams) 0) }}
var err error
+ _ = err
{{end}}
{{range .PathParams}}// ------------- Path parameter "{{.ParamName}}" -------------
@@ -29,7 +30,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
}
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", mux.Vars(r)["{{.ParamName}}"], &{{$varName}}, runtime.BindStyledParameterOptions{Explode: {{.Explode}}, Required: {{.Required}}})
+ 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
@@ -54,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}}
@@ -69,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}}"})
@@ -77,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}}
@@ -98,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}}
@@ -110,14 +116,14 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", valueList[0], &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}})
+ 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")
@@ -129,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}}
@@ -153,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.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie.Value, &value, runtime.BindStyledParameterOptions{Explode: {{.Explode}}, Required: {{.Required}}})
+ 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}}
}
@@ -173,6 +180,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
return
}
{{- end}}
+ }
{{end}}
{{end}}
@@ -192,7 +200,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
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 4d19422423..d57c2d1cd4 100644
--- a/pkg/codegen/templates/imports.tmpl
+++ b/pkg/codegen/templates/imports.tmpl
@@ -8,14 +8,14 @@ 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"
@@ -28,19 +28,11 @@ import (
"github.com/oapi-codegen/runtime"
"github.com/oapi-codegen/nullable"
- 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"
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 ae40439ef4..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.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", ctx.Params().Get("{{.ParamName}}"), &{{$varName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: {{.Explode}}, Required: {{.Required}}})
+ 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.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", valueList[0], &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}})
+ 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.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie.Value, &value, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationCookie, Explode: {{.Explode}}, Required: {{.Required}}})
+ 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
index 9542fabae1..63fccd2445 100644
--- a/pkg/codegen/templates/stdhttp/std-http-handler.tmpl
+++ b/pkg/codegen/templates/stdhttp/std-http-handler.tmpl
@@ -3,21 +3,27 @@ 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 *http.ServeMux
+ 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 *http.ServeMux) http.Handler {
+func HandlerFromMux(si ServerInterface, m ServeMux) http.Handler {
return HandlerWithOptions(si, StdHTTPServerOptions {
BaseRouter: m,
})
}
-func HandlerFromMuxWithBaseURL(si ServerInterface, m *http.ServeMux, baseURL string) http.Handler {
+func HandlerFromMuxWithBaseURL(si ServerInterface, m ServeMux, baseURL string) http.Handler {
return HandlerWithOptions(si, StdHTTPServerOptions {
BaseURL: baseURL,
BaseRouter: m,
@@ -43,7 +49,7 @@ func HandlerWithOptions(si ServerInterface, options StdHTTPServerOptions) http.H
ErrorHandlerFunc: options.ErrorHandlerFunc,
}
{{end}}
-{{range .}}m.HandleFunc("{{.Method }} "+options.BaseURL+"{{.Path | swaggerUriToStdHttpUri}}", wrapper.{{.OperationId}})
+{{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
index 79a51fd75b..04baa51e39 100644
--- a/pkg/codegen/templates/stdhttp/std-http-interface.tmpl
+++ b/pkg/codegen/templates/stdhttp/std-http-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/stdhttp/std-http-middleware.tmpl b/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl
index 02805ef175..8058ed1714 100644
--- a/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl
+++ b/pkg/codegen/templates/stdhttp/std-http-middleware.tmpl
@@ -8,28 +8,29 @@ 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) {
{{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("{{.ParamName}}")
+ {{$varName}} = r.PathValue("{{.SanitizedParamName}}")
{{end}}
{{if .IsJson}}
- err = json.Unmarshal([]byte(r.PathValue("{{.ParamName}}")), &{{$varName}})
+ 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("{{.ParamName}}"), &{{$varName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationPath, Explode: {{.Explode}}, Required: {{.Required}}})
+ 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
@@ -54,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}}
@@ -69,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}}"})
@@ -77,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}}
@@ -98,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}}
@@ -110,14 +116,14 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
{{end}}
{{if .IsStyled}}
- err = runtime.BindStyledParameterWithOptions("{{.Style}}", "{{.ParamName}}", valueList[0], &{{.GoName}}, runtime.BindStyledParameterOptions{ParamLocation: runtime.ParamLocationHeader, Explode: {{.Explode}}, Required: {{.Required}}})
+ 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")
@@ -129,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}}
@@ -153,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.BindStyledParameterWithOptions("simple", "{{.ParamName}}", cookie.Value, &value, runtime.BindStyledParameterOptions{Explode: {{.Explode}}, Required: {{.Required}}})
+ 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}}
}
@@ -173,6 +180,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
return
}
{{- end}}
+ }
{{end}}
{{end}}
@@ -192,7 +200,7 @@ func (siw *ServerInterfaceWrapper) {{$opid}}(w http.ResponseWriter, r *http.Requ
handler.ServeHTTP(w, r)
}
-{{end}}
+{{end}}{{end}}
type UnescapedCookieParamError struct {
ParamName string
diff --git a/pkg/codegen/templates/strict/strict-echo.tmpl b/pkg/codegen/templates/strict/strict-echo.tmpl
index 676690fab3..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
@@ -68,8 +76,14 @@ type strictHandler struct {
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" */ -}}
@@ -94,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 8bcfc89b10..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,15 +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 if $isExternalRef -}}
- type {{$receiverTypeName}} struct { {{$ref}} }
{{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 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 *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"}}{{if eq .ContentType "multipart/form-data"}}writer.FormDataContentType(){{else}}mime.FormatMediaType("{{.ContentType}}", map[string]string{"boundary": writer.Boundary()}){{end}}{{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))
@@ -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
@@ -102,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}}
@@ -126,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 510899c9e0..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 {
@@ -59,8 +66,14 @@ type strictHandler struct {
{{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" */ -}}
@@ -87,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 d4c43164a6..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,40 +76,47 @@ 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.ShouldBindJSON(&body); err != nil {
- ctx.Status(http.StatusBadRequest)
- ctx.Error(err)
+ {{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 eq .ContentType "multipart/form-data" -}}
- if reader, err := ctx.Request.MultipartReader(); err == nil {
- request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = reader
- } else {
- ctx.Error(err)
+ if reader, err := ctx.Request.MultipartReader(); err != nil {
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
+ } else {
+ request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = reader
}
{{else -}}
if _, params, err := mime.ParseMediaType(ctx.Request.Header.Get("Content-Type")); err != nil {
- ctx.Error(err)
+ sh.options.RequestErrorHandlerFunc(ctx, err)
return
} else if boundary := params["boundary"]; boundary == "" {
- ctx.Error(http.ErrMissingBoundary)
+ sh.options.RequestErrorHandlerFunc(ctx, http.ErrMissingBoundary)
return
} else {
request.{{if $multipleBodies}}{{.NameTag}}{{end}}Body = multipart.NewReader(ctx.Request.Body, boundary)
@@ -72,11 +125,17 @@ type strictHandler struct {
{{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" */ -}}
@@ -93,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 8d32415ad6..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))
@@ -91,8 +100,14 @@ type strictHandler struct {
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" */ -}}
@@ -118,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 b26edd4678..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,25 +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 if $isExternalRef -}}
- type {{$receiverTypeName}} struct { {{$ref}} }
{{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 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}}
@@ -76,40 +82,116 @@
{{if eq .NameTag "Multipart" -}}
writer := multipart.NewWriter(w)
{{end -}}
- w.Header().Set("Content-Type", {{if eq .NameTag "Multipart"}}{{if eq .ContentType "multipart/form-data"}}writer.FormDataContentType(){{else}}mime.FormatMediaType("{{.ContentType}}", map[string]string{"boundary": writer.Boundary()}){{end}}{{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}}
@@ -128,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 e93fdf6166..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,25 +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 if $isExternalRef -}}
- type {{$receiverTypeName}} struct { {{$ref}} }
{{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 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,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"}}{{if eq .ContentType "multipart/form-data"}}writer.FormDataContentType(){{else}}mime.FormatMediaType("{{.ContentType}}", map[string]string{"boundary": writer.Boundary()}){{end}}{{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))
@@ -89,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
@@ -107,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}}
@@ -128,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 dfdeb1546f..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)
@@ -74,8 +83,14 @@ type strictHandler struct {
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" */ -}}
@@ -104,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 464fb11c43..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 -}}
@@ -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 1e1e76f762..496faf5648 100644
--- a/pkg/codegen/utils.go
+++ b/pkg/codegen/utils.go
@@ -15,12 +15,14 @@ package codegen
import (
"bytes"
+ "cmp"
"fmt"
"go/token"
+ "maps"
"net/url"
"reflect"
"regexp"
- "sort"
+ "slices"
"strconv"
"strings"
"unicode"
@@ -81,7 +83,7 @@ func (m NameNormalizerMap) Options() []string {
options = append(options, string(key))
}
- sort.Strings(options)
+ slices.Sort(options)
return options
}
@@ -205,7 +207,7 @@ func LowercaseFirstCharacters(str string) string {
runes := []rune(str)
- for i := 0; i < len(runes); i++ {
+ for i := range runes {
next := i + 1
if i != 0 && next < len(runes) && unicode.IsLower(runes[next]) {
break
@@ -224,25 +226,25 @@ func LowercaseFirstCharacters(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
@@ -283,7 +285,7 @@ func ToCamelCaseWithDigits(s string) string {
func ToCamelCaseWithInitialisms(s string) string {
parts := camelCaseMatchParts.FindAllString(ToCamelCaseWithDigits(s), -1)
for i := range parts {
- if v, ok := initialismsMap[strings.ToLower(parts[i])]; ok {
+ if v, ok := globalState.initialismsMap[strings.ToLower(parts[i])]; ok {
parts[i] = v
}
}
@@ -292,19 +294,26 @@ func ToCamelCaseWithInitialisms(s string) string {
var camelCaseMatchParts = regexp.MustCompile(`[\p{Lu}\d]+([\p{Ll}\d]+|$)`)
-// initialismsMap stores initialisms as "lower(initialism) -> initialism" map.
-// List of initialisms was taken from https://staticcheck.io/docs/configuration/options/#initialisms.
-var initialismsMap = makeInitialismsMap([]string{
+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...)
-func makeInitialismsMap(l []string) map[string]string {
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
}
@@ -315,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])) {
@@ -344,7 +351,7 @@ func SortedMapKeys[T any](m map[string]T) []string {
for k := range m {
keys = append(keys, k)
}
- sort.Strings(keys)
+ slices.Sort(keys)
return keys
}
@@ -366,11 +373,11 @@ func SortedSchemaKeys(dict map[string]*openapi3.SchemaRef) []string {
}
}
- sort.Slice(keys, func(i, j int) bool {
- if i, j := orders[keys[i]], orders[keys[j]]; i != j {
- return i < j
- }
- return keys[i] < keys[j]
+ slices.SortFunc(keys, func(a, b string) int {
+ return cmp.Or(
+ cmp.Compare(orders[a], orders[b]),
+ cmp.Compare(a, b),
+ )
})
return keys
}
@@ -399,15 +406,11 @@ func schemaXOrder(v *openapi3.SchemaRef) (int64, bool) {
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.
@@ -441,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)
+ }
+ } 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
}
- return fmt.Sprintf("%s.%s", goImport.Name, goType), 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.
@@ -596,8 +628,9 @@ func SwaggerUriToGorillaUri(uri string) string {
}
// SwaggerUriToStdHttpUri converts a swagger style path URI with parameters to a
-// Chi compatible path URI. We need to replace all Swagger parameters with
-// "{param}". Valid input parameters are:
+// 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*}
@@ -608,7 +641,16 @@ func SwaggerUriToGorillaUri(uri string) string {
// {?param}
// {?param*}
func SwaggerUriToStdHttpUri(uri string) string {
- return pathParamRE.ReplaceAllString(uri, "{$1}")
+ // 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
@@ -628,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",
@@ -693,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 {
@@ -706,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
@@ -776,6 +842,10 @@ func typeNamePrefix(name string) (prefix string) {
prefix += "Tilde"
case '=':
prefix += "Equal"
+ case '>':
+ prefix += "GreaterThan"
+ case '<':
+ prefix += "LessThan"
case '#':
prefix += "Hash"
case '.':
@@ -786,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) {
@@ -832,6 +904,15 @@ func PathToTypeName(path []string) string {
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 {
@@ -849,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, "")
@@ -1013,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
+
+ // 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]interface{})
+ importI, ok := goTypeImportExt.(map[string]any)
if !ok {
return nil, fmt.Errorf("failed to convert type: %T", goTypeImportExt)
}
@@ -1045,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.
@@ -1067,14 +1161,5 @@ func isAdditionalPropertiesExplicitFalse(s *openapi3.Schema) bool {
return false
}
- return *s.AdditionalProperties.Has == false //nolint:gosimple
-}
-
-func sliceContains[E comparable](s []E, v E) bool {
- for _, ss := range s {
- if ss == v {
- return true
- }
- }
- return false
+ return !*s.AdditionalProperties.Has
}
diff --git a/pkg/codegen/utils_test.go b/pkg/codegen/utils_test.go
index a55e648e8a..df37c6d77a 100644
--- a/pkg/codegen/utils_test.go
+++ b/pkg/codegen/utils_test.go
@@ -160,7 +160,7 @@ func TestSortedSchemaKeysWithXOrder(t *testing.T) {
withOrder := func(i float64) *openapi3.SchemaRef {
return &openapi3.SchemaRef{
Value: &openapi3.Schema{
- Extensions: map[string]interface{}{"x-order": i},
+ Extensions: map[string]any{"x-order": i},
},
}
}
@@ -233,10 +233,14 @@ components:
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 {
@@ -259,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",
@@ -430,6 +439,7 @@ func TestSwaggerUriToChiUri(t *testing.T) {
}
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}"))
@@ -444,6 +454,13 @@ func TestSwaggerUriToStdHttpUriUri(t *testing.T) {
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) {
@@ -452,6 +469,53 @@ func TestOrderedParamsFromUri(t *testing.T) {
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) {
@@ -459,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
@@ -590,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))
}
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/util/loader.go b/pkg/util/loader.go
index f29a160d7f..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) {
@@ -25,3 +31,74 @@ func LoadSwagger(filePath string) (swagger *openapi3.T, err error) {
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
+ }
+
+ // 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
+
+ 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, 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"
+ }
]
}